summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java162
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java190
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java5
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java37
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java23
-rw-r--r--core/api/current.txt237
-rw-r--r--core/api/system-current.txt52
-rw-r--r--core/api/test-current.txt6
-rw-r--r--core/java/Android.bp8
-rw-r--r--core/java/android/app/ActivityManager.java129
-rw-r--r--core/java/android/app/ContextImpl.java12
-rw-r--r--core/java/android/app/Dialog.java3
-rw-r--r--core/java/android/app/GameManager.java2
-rw-r--r--core/java/android/app/ILocaleManager.aidl5
-rw-r--r--core/java/android/app/KeyguardManager.java14
-rw-r--r--core/java/android/app/LocaleManager.java28
-rw-r--r--core/java/android/app/StatusBarManager.java40
-rw-r--r--core/java/android/app/TEST_MAPPING19
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java167
-rw-r--r--core/java/android/app/admin/FactoryResetProtectionPolicy.java15
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl9
-rw-r--r--core/java/android/app/usage/BroadcastResponseStats.java2
-rw-r--r--core/java/android/app/usage/IUsageStatsManager.aidl2
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java12
-rw-r--r--core/java/android/content/Context.java26
-rw-r--r--core/java/android/content/ContextWrapper.java4
-rw-r--r--core/java/android/content/Intent.java82
-rw-r--r--core/java/android/content/pm/AppSearchShortcutInfo.java2
-rw-r--r--core/java/android/content/pm/Capability.aidl18
-rw-r--r--core/java/android/content/pm/Capability.java143
-rw-r--r--core/java/android/content/pm/CapabilityParams.aidl18
-rw-r--r--core/java/android/content/pm/CapabilityParams.java215
-rw-r--r--core/java/android/content/pm/PackageInfo.java3
-rw-r--r--core/java/android/content/pm/PackageManager.java22
-rw-r--r--core/java/android/content/pm/SHORTCUT_OWNERS5
-rw-r--r--core/java/android/content/pm/ShortcutInfo.java131
-rw-r--r--core/java/android/content/res/AssetManager.java7
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java13
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl6
-rw-r--r--core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl2
-rw-r--r--core/java/android/inputmethodservice/NavigationBarController.java4
-rw-r--r--core/java/android/inputmethodservice/navigationbar/DeadZone.java2
-rw-r--r--core/java/android/inputmethodservice/navigationbar/KeyButtonView.java6
-rw-r--r--core/java/android/net/SntpClient.java9
-rw-r--r--core/java/android/os/storage/IStorageManager.aidl1
-rw-r--r--core/java/android/permission/IPermissionController.aidl2
-rw-r--r--core/java/android/permission/IPermissionManager.aidl2
-rw-r--r--core/java/android/permission/PermissionControllerManager.java6
-rw-r--r--core/java/android/permission/PermissionControllerService.java19
-rw-r--r--core/java/android/permission/PermissionManager.java14
-rw-r--r--core/java/android/permission/PermissionUsageHelper.java15
-rw-r--r--core/java/android/provider/Settings.java12
-rw-r--r--core/java/android/service/displayhash/DisplayHashingService.java3
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java6
-rw-r--r--core/java/android/util/NtpTrustedTime.java31
-rw-r--r--core/java/android/util/TimingsTraceLog.java2
-rw-r--r--core/java/android/view/ContentRecordingSession.java38
-rw-r--r--core/java/android/view/HandwritingInitiator.java10
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java2
-rw-r--r--core/java/android/view/SurfaceView.java145
-rw-r--r--core/java/android/view/ViewRootImpl.java412
-rw-r--r--core/java/android/window/OnBackInvokedCallback.java2
-rw-r--r--core/java/android/window/OnBackInvokedDispatcher.java6
-rw-r--r--core/java/android/window/ProxyOnBackInvokedDispatcher.java8
-rw-r--r--core/java/android/window/WindowInfosListener.java11
-rw-r--r--core/java/android/window/WindowOnBackInvokedDispatcher.java2
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java13
-rw-r--r--core/java/com/android/internal/logging/InstanceId.java98
-rw-r--r--core/java/com/android/internal/logging/InstanceIdSequence.java62
-rw-r--r--core/java/com/android/internal/logging/UiEventLogger.java111
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java50
-rw-r--r--core/java/com/android/internal/os/KernelAllocationStats.java26
-rw-r--r--core/java/com/android/server/SystemConfig.java41
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/android_window_WindowInfosListener.cpp70
-rw-r--r--core/jni/com_android_internal_os_KernelAllocationStats.cpp149
-rw-r--r--core/proto/android/os/appbatterystats.proto47
-rw-r--r--core/res/AndroidManifest.xml9
-rw-r--r--core/tests/coretests/src/android/net/SntpClientTest.java3
-rw-r--r--core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java6
-rw-r--r--core/tests/coretests/src/android/window/BackNavigationTest.java4
-rw-r--r--core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java23
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java2
-rw-r--r--core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java14
-rw-r--r--data/etc/com.android.systemui.xml3
-rw-r--r--data/etc/services.core.protolog.json18
-rw-r--r--graphics/java/android/graphics/Typeface.java2
-rw-r--r--graphics/java/android/graphics/fonts/Font.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java30
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java25
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp12
-rw-r--r--libs/hwui/HardwareBitmapUploader.h2
-rw-r--r--libs/hwui/hwui/Bitmap.cpp4
-rw-r--r--location/java/android/location/GnssExcessPathInfo.java375
-rw-r--r--location/java/android/location/GnssReflectingPlane.java44
-rw-r--r--location/java/android/location/GnssSingleSatCorrection.java395
-rw-r--r--location/java/android/location/Location.java148
-rwxr-xr-xmedia/java/android/media/IAudioService.aidl6
-rw-r--r--media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl (renamed from core/java/com/android/internal/logging/UiEvent.java)21
-rw-r--r--media/java/android/media/MediaActionSound.java5
-rw-r--r--media/java/android/media/MediaCodec.java20
-rw-r--r--media/java/android/media/MediaFormat.java41
-rw-r--r--media/java/android/media/MediaRoute2Info.java2
-rw-r--r--media/java/android/media/RouteDiscoveryPreference.java5
-rw-r--r--media/java/android/media/Spatializer.java93
-rw-r--r--media/java/android/media/projection/IMediaProjection.aidl13
-rw-r--r--media/java/android/media/projection/MediaProjection.java57
-rw-r--r--media/java/android/media/tv/AdRequest.java6
-rw-r--r--media/java/android/media/tv/AitInfo.java6
-rw-r--r--media/java/android/media/tv/CommandRequest.java31
-rw-r--r--media/java/android/media/tv/CommandResponse.java19
-rw-r--r--media/java/android/media/tv/SectionRequest.java5
-rw-r--r--media/java/android/media/tv/SectionResponse.java10
-rw-r--r--media/java/android/media/tv/StreamEventResponse.java15
-rw-r--r--media/java/android/media/tv/TableRequest.java7
-rw-r--r--media/java/android/media/tv/TableResponse.java7
-rw-r--r--media/java/android/media/tv/TimelineResponse.java5
-rw-r--r--media/java/android/media/tv/TvInputManager.java4
-rw-r--r--media/java/android/media/tv/TvView.java10
-rw-r--r--media/java/android/media/tv/interactive/AppLinkInfo.aidl2
-rw-r--r--media/java/android/media/tv/interactive/AppLinkInfo.java152
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl4
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl9
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl6
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl3
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl3
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl3
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppManager.java109
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppService.java112
-rw-r--r--media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl (renamed from media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl)4
-rw-r--r--media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java (renamed from media/java/android/media/tv/interactive/TvInteractiveAppInfo.java)30
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppView.java133
-rw-r--r--packages/CompanionDeviceManager/res/color/selector.xml1
-rw-r--r--packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml1
-rw-r--r--packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml5
-rw-r--r--packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml5
-rw-r--r--packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml1
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_apps.xml1
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_device_other.xml1
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_notifications.xml1
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_storage.xml1
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_watch.xml1
-rw-r--r--packages/CompanionDeviceManager/res/layout/activity_confirmation.xml75
-rw-r--r--packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml50
-rw-r--r--packages/CompanionDeviceManager/res/layout/helper_confirmation.xml17
-rw-r--r--packages/CompanionDeviceManager/res/layout/list_item_device.xml1
-rw-r--r--packages/CompanionDeviceManager/res/layout/list_item_permission.xml8
-rw-r--r--packages/CompanionDeviceManager/res/layout/vendor_header.xml7
-rw-r--r--packages/CompanionDeviceManager/res/values/styles.xml66
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java27
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java3
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java9
-rw-r--r--packages/ConnectivityT/framework-t/Android.bp2
-rw-r--r--packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java10
-rw-r--r--packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java113
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java283
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java28
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl13
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl1
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl (renamed from packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl)6
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java36
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java16
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-or/strings.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml22
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml2
-rw-r--r--packages/SettingsLib/res/values/strings.xml24
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java15
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java18
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java23
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java93
-rw-r--r--packages/SettingsProvider/res/values-or/strings.xml2
-rw-r--r--packages/SystemUI/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/res-keyguard/values/dimens.xml3
-rw-r--r--packages/SystemUI/res/drawable/media_ttt_undo_background.xml15
-rw-r--r--packages/SystemUI/res/drawable/user_switcher_icon_large.xml4
-rw-r--r--packages/SystemUI/res/layout/ongoing_privacy_chip.xml2
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/dimens.xml8
-rw-r--r--packages/SystemUI/res/values/config.xml14
-rw-r--r--packages/SystemUI/res/values/dimens.xml12
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt49
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java115
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt276
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt261
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt261
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java152
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt84
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt29
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java62
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java61
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt92
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt97
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt266
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java11
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java62
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java35
-rw-r--r--services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java83
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java16
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateService.java6
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java13
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java52
-rw-r--r--services/core/java/com/android/server/am/AppBatteryExemptionTracker.java82
-rw-r--r--services/core/java/com/android/server/am/AppBatteryTracker.java68
-rw-r--r--services/core/java/com/android/server/am/AppPermissionTracker.java362
-rw-r--r--services/core/java/com/android/server/am/AppRestrictionController.java7
-rw-r--r--services/core/java/com/android/server/am/BaseAppStateTracker.java13
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java14
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java8
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java16
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java13
-rw-r--r--services/core/java/com/android/server/audio/SpatializerHelper.java63
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java18
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java14
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java22
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java22
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java5
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java8
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java8
-rw-r--r--services/core/java/com/android/server/locales/LocaleManagerService.java34
-rw-r--r--services/core/java/com/android/server/locales/TEST_MAPPING9
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java17
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java56
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java57
-rw-r--r--services/core/java/com/android/server/pm/DexOptHelper.java4
-rw-r--r--services/core/java/com/android/server/pm/InitAppsHelper.java (renamed from services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java)203
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java30
-rw-r--r--services/core/java/com/android/server/pm/Installer.java44
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java131
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java24
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java2
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java4
-rw-r--r--services/core/java/com/android/server/pm/StorageEventHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java67
-rw-r--r--services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java6
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java19
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java22
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java17
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java71
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java38
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java48
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java71
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java2
-rw-r--r--services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java125
-rw-r--r--services/core/java/com/android/server/utils/TimingsTraceAndSlog.java2
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java61
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java11
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java3
-rw-r--r--services/core/java/com/android/server/wm/ContentRecorder.java154
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java9
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java1
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java2
-rw-r--r--services/core/jni/gnss/MeasurementCorrections.cpp133
-rw-r--r--services/core/jni/gnss/MeasurementCorrections.h20
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java7
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java10
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java12
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java87
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java11
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java39
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java165
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java66
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java82
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java75
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java59
-rw-r--r--services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java145
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java20
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java82
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java14
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java26
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java4
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl11
-rw-r--r--tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java6
-rw-r--r--tests/TrustTests/AndroidManifest.xml10
-rw-r--r--tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt3
-rw-r--r--tests/TrustTests/src/android/trust/test/LockUserTest.kt4
-rw-r--r--tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt124
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt25
375 files changed, 9547 insertions, 4185 deletions
diff --git a/Android.bp b/Android.bp
index 753cefc38ed6..149b22355c58 100644
--- a/Android.bp
+++ b/Android.bp
@@ -97,6 +97,7 @@ filegroup {
":platform-compat-native-aidl",
// AIDL sources from external directories
+ ":android.hardware.gnss-V2-java-source",
":android.hardware.graphics.common-V3-java-source",
":android.hardware.security.keymint-V2-java-source",
":android.hardware.security.secureclock-V1-java-source",
@@ -328,6 +329,7 @@ java_defaults {
"modules-utils-preconditions",
"modules-utils-synchronous-result-receiver",
"modules-utils-os",
+ "modules-utils-uieventlogger-interface",
"framework-permission-aidl-java",
"spatializer-aidl-java",
"audiopolicy-types-aidl-java",
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index e2426c2f1758..f822a188c99c 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -2,6 +2,7 @@ package com.android.server.usage;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager.ProcessState;
import android.app.usage.AppStandbyInfo;
@@ -237,4 +238,11 @@ public interface AppStandbyInternal {
*/
@ProcessState
int getBroadcastResponseFgThresholdState();
+
+ /**
+ * Return the last known value corresponding to the {@code key} from
+ * {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController.
+ */
+ @Nullable
+ String getAppStandbyConstant(@NonNull String key);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 18f63b7ad902..23056b5670b9 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -17,6 +17,7 @@
package com.android.server.job;
import static com.android.server.job.JobSchedulerService.MAX_JOB_CONTEXTS_COUNT;
+import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.annotation.IntDef;
@@ -32,9 +33,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.os.BatteryStats;
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
@@ -51,19 +54,24 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.util.StatLogger;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.StateController;
+import com.android.server.job.restrictions.JobRestriction;
import com.android.server.pm.UserManagerInternal;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* This class decides, given the various configuration and the system status, which jobs can start
@@ -278,6 +286,11 @@ class JobConcurrencyManager {
String[] mRecycledShouldStopJobReason = new String[MAX_JOB_CONTEXTS_COUNT];
+ /**
+ * Set of JobServiceContexts that we use to run jobs.
+ */
+ final List<JobServiceContext> mActiveServices = new ArrayList<>();
+
private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
private final WorkCountTracker mWorkCountTracker = new WorkCountTracker();
@@ -358,6 +371,20 @@ class JobConcurrencyManager {
onInteractiveStateChanged(mPowerManager.isInteractive());
}
+ /**
+ * Called when the boot phase reaches
+ * {@link com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START}.
+ */
+ void onThirdPartyAppsCanStart() {
+ final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME));
+ for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
+ mActiveServices.add(
+ new JobServiceContext(mService, this, batteryStats,
+ mService.mJobPackageTracker, mContext.getMainLooper()));
+ }
+ }
+
@GuardedBy("mLock")
void onAppRemovedLocked(String pkgName, int uid) {
final PackageStats packageStats = mActivePkgStats.get(UserHandle.getUserId(uid), pkgName);
@@ -390,6 +417,7 @@ class JobConcurrencyManager {
case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
if (mPowerManager != null && mPowerManager.isDeviceIdleMode()) {
synchronized (mLock) {
+ stopUnexemptedJobsForDoze();
stopLongRunningJobsLocked("deep doze");
}
}
@@ -471,6 +499,11 @@ class JobConcurrencyManager {
}
@GuardedBy("mLock")
+ ArraySet<JobStatus> getRunningJobsLocked() {
+ return mRunningJobs;
+ }
+
+ @GuardedBy("mLock")
boolean isJobRunningLocked(JobStatus job) {
return mRunningJobs.contains(job);
}
@@ -546,7 +579,7 @@ class JobConcurrencyManager {
}
final List<JobStatus> pendingJobs = mService.mPendingJobs;
- final List<JobServiceContext> activeServices = mService.mActiveServices;
+ final List<JobServiceContext> activeServices = mActiveServices;
// To avoid GC churn, we recycle the arrays.
JobStatus[] contextIdToJobMap = mRecycledAssignContextIdToJobMap;
@@ -719,9 +752,44 @@ class JobConcurrencyManager {
}
@GuardedBy("mLock")
+ boolean stopJobOnServiceContextLocked(JobStatus job,
+ @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
+ if (!mRunningJobs.contains(job)) {
+ return false;
+ }
+
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus executing = jsc.getRunningJobLocked();
+ if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
+ jsc.cancelExecutingJobLocked(reason, internalReasonCode, debugReason);
+ return true;
+ }
+ }
+ Slog.wtf(TAG, "Couldn't find running job on a context");
+ mRunningJobs.remove(job);
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ private void stopUnexemptedJobsForDoze() {
+ // When becoming idle, make sure no jobs are actively running,
+ // except those using the idle exemption flag.
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus executing = jsc.getRunningJobLocked();
+ if (executing != null && !executing.canRunInDoze()) {
+ jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
+ JobParameters.INTERNAL_STOP_REASON_DEVICE_IDLE,
+ "cancelled due to doze");
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
private void stopLongRunningJobsLocked(@NonNull String debugReason) {
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; ++i) {
- final JobServiceContext jsc = mService.mActiveServices.get(i);
+ final JobServiceContext jsc = mActiveServices.get(i);
final JobStatus jobStatus = jsc.getRunningJobLocked();
if (jobStatus != null && !jsc.isWithinExecutionGuaranteeTime()) {
@@ -731,6 +799,41 @@ class JobConcurrencyManager {
}
}
+ @GuardedBy("mLock")
+ void stopNonReadyActiveJobsLocked() {
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext serviceContext = mActiveServices.get(i);
+ final JobStatus running = serviceContext.getRunningJobLocked();
+ if (running == null) {
+ continue;
+ }
+ if (!running.isReady()) {
+ if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX
+ && running.getStopReason() == JobParameters.STOP_REASON_APP_STANDBY) {
+ serviceContext.cancelExecutingJobLocked(
+ running.getStopReason(),
+ JobParameters.INTERNAL_STOP_REASON_RESTRICTED_BUCKET,
+ "cancelled due to restricted bucket");
+ } else {
+ serviceContext.cancelExecutingJobLocked(
+ running.getStopReason(),
+ JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
+ "cancelled due to unsatisfied constraints");
+ }
+ } else {
+ final JobRestriction restriction = mService.checkIfRestricted(running);
+ if (restriction != null) {
+ final int internalReasonCode = restriction.getInternalReason();
+ serviceContext.cancelExecutingJobLocked(restriction.getReason(),
+ internalReasonCode,
+ "restricted due to "
+ + JobParameters.getInternalReasonCodeDescription(
+ internalReasonCode));
+ }
+ }
+ }
+ }
+
private void noteConcurrency() {
mService.mJobPackageTracker.noteConcurrency(mRunningJobs.size(),
// TODO: log per type instead of only TOP
@@ -1078,6 +1181,24 @@ class JobConcurrencyManager {
}
@GuardedBy("mLock")
+ boolean executeTimeoutCommandLocked(PrintWriter pw, String pkgName, int userId,
+ boolean hasJobId, int jobId) {
+ boolean foundSome = false;
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ final JobServiceContext jc = mActiveServices.get(i);
+ final JobStatus js = jc.getRunningJobLocked();
+ if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId, "shell")) {
+ foundSome = true;
+ pw.print("Timing out: ");
+ js.printUniqueId(pw);
+ pw.print(" ");
+ pw.println(js.getServiceComponent().flattenToShortString());
+ }
+ }
+ return foundSome;
+ }
+
+ @GuardedBy("mLock")
private String printPendingQueueLocked() {
StringBuilder s = new StringBuilder("Pending queue: ");
Iterator<JobStatus> it = mService.mPendingJobs.iterator();
@@ -1200,6 +1321,43 @@ class JobConcurrencyManager {
}
}
+ @GuardedBy("mLock")
+ void dumpActiveJobsLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate,
+ long nowElapsed, long nowUptime) {
+ pw.println("Active jobs:");
+ pw.increaseIndent();
+ for (int i = 0; i < mActiveServices.size(); i++) {
+ JobServiceContext jsc = mActiveServices.get(i);
+ final JobStatus job = jsc.getRunningJobLocked();
+
+ if (job != null && !predicate.test(job)) {
+ continue;
+ }
+
+ pw.print("Slot #"); pw.print(i); pw.print(": ");
+ jsc.dumpLocked(pw, nowElapsed);
+
+ if (job != null) {
+ pw.increaseIndent();
+
+ pw.increaseIndent();
+ job.dump(pw, false, nowElapsed);
+ pw.decreaseIndent();
+
+ pw.print("Evaluated bias: ");
+ pw.println(JobInfo.getBiasString(job.lastEvaluatedBias));
+
+ pw.print("Active at ");
+ TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
+ pw.print(", pending for ");
+ TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
+ pw.decreaseIndent();
+ pw.println();
+ }
+ }
+ pw.decreaseIndent();
+ }
+
public void dumpProtoLocked(ProtoOutputStream proto, long tag, long now, long nowRealtime) {
final long token = proto.start(tag);
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 b9362789c6c6..3d74bc98ad32 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -57,7 +57,6 @@ import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
-import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Handler;
@@ -67,7 +66,6 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
@@ -90,7 +88,6 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IBatteryStats;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -100,7 +97,6 @@ import com.android.server.AppStateTrackerImpl;
import com.android.server.DeviceIdleInternal;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
-import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
import com.android.server.job.controllers.BackgroundJobsController;
import com.android.server.job.controllers.BatteryController;
@@ -243,12 +239,6 @@ public class JobSchedulerService extends com.android.server.SystemService
static final int MSG_CHECK_CHANGED_JOB_LIST = 8;
static final int MSG_CHECK_MEDIA_EXEMPTION = 9;
- /**
- * Track Services that have currently active or pending jobs. The index is provided by
- * {@link JobStatus#getServiceToken()}
- */
- final List<JobServiceContext> mActiveServices = new ArrayList<>();
-
/** List of controllers that will notify this service of updates to jobs. */
final List<StateController> mControllers;
/**
@@ -307,7 +297,6 @@ public class JobSchedulerService extends com.android.server.SystemService
PackageManagerInternal mLocalPM;
ActivityManagerInternal mActivityManagerInternal;
- IBatteryStats mBatteryStats;
DeviceIdleInternal mLocalDeviceIdleController;
@VisibleForTesting
AppStateTrackerImpl mAppStateTracker;
@@ -1578,7 +1567,8 @@ public class JobSchedulerService extends com.android.server.SystemService
mJobPackageTracker.noteNonpending(cancelled);
}
// Cancel if running.
- stopJobOnServiceContextLocked(cancelled, reason, internalReasonCode, debugReason);
+ mConcurrencyManager.stopJobOnServiceContextLocked(
+ cancelled, reason, internalReasonCode, debugReason);
// If this is a replacement, bring in the new version of the job
if (incomingJob != null) {
if (DEBUG) Slog.i(TAG, "Tracking replacement job " + incomingJob.toShortString());
@@ -1627,19 +1617,7 @@ public class JobSchedulerService extends com.android.server.SystemService
if (DEBUG) {
Slog.d(TAG, "Doze state changed: " + deviceIdle);
}
- if (deviceIdle) {
- // When becoming idle, make sure no jobs are actively running,
- // except those using the idle exemption flag.
- for (int i=0; i<mActiveServices.size(); i++) {
- JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus executing = jsc.getRunningJobLocked();
- if (executing != null && !executing.canRunInDoze()) {
- jsc.cancelExecutingJobLocked(JobParameters.STOP_REASON_DEVICE_STATE,
- JobParameters.INTERNAL_STOP_REASON_DEVICE_IDLE,
- "cancelled due to doze");
- }
- }
- } else {
+ if (!deviceIdle) {
// When coming out of idle, allow thing to start back up.
if (mReadyToRock) {
if (mLocalDeviceIdleController != null) {
@@ -1682,10 +1660,10 @@ public class JobSchedulerService extends com.android.server.SystemService
// active is true if pending queue contains jobs OR some job is running.
boolean active = mPendingJobs.size() > 0;
if (mPendingJobs.size() <= 0) {
- for (int i=0; i<mActiveServices.size(); i++) {
- final JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus job = jsc.getRunningJobLocked();
- if (job != null && !job.canRunInDoze()) {
+ final ArraySet<JobStatus> runningJobs = mConcurrencyManager.getRunningJobsLocked();
+ for (int i = runningJobs.size() - 1; i >= 0; --i) {
+ final JobStatus job = runningJobs.valueAt(i);
+ if (!job.canRunInDoze()) {
// We will report active if we have a job running and it does not have an
// exception that allows it to run in Doze.
active = true;
@@ -1895,16 +1873,9 @@ public class JobSchedulerService extends com.android.server.SystemService
synchronized (mLock) {
// Let's go!
mReadyToRock = true;
- mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
- BatteryStats.SERVICE_NAME));
mLocalDeviceIdleController =
LocalServices.getService(DeviceIdleInternal.class);
- // Create the "runners".
- for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
- mActiveServices.add(
- new JobServiceContext(this, mConcurrencyManager, mBatteryStats,
- mJobPackageTracker, getContext().getMainLooper()));
- }
+ mConcurrencyManager.onThirdPartyAppsCanStart();
// Attach jobs to their controllers.
mJobs.forEachJob((job) -> {
for (int controller = 0; controller < mControllers.size(); controller++) {
@@ -1961,19 +1932,6 @@ public class JobSchedulerService extends com.android.server.SystemService
return removed;
}
- private boolean stopJobOnServiceContextLocked(JobStatus job,
- @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
- for (int i = 0; i < mActiveServices.size(); i++) {
- JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus executing = jsc.getRunningJobLocked();
- if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
- jsc.cancelExecutingJobLocked(reason, internalReasonCode, debugReason);
- return true;
- }
- }
- return false;
- }
-
/** Return {@code true} if the specified job is currently executing. */
@GuardedBy("mLock")
public boolean isCurrentlyRunningLocked(JobStatus job) {
@@ -2383,7 +2341,8 @@ public class JobSchedulerService extends com.android.server.SystemService
* - if passes all the restrictions or has {@link JobInfo#BIAS_FOREGROUND_SERVICE} bias
* or higher.
*/
- private JobRestriction checkIfRestricted(JobStatus job) {
+ @GuardedBy("mLock")
+ JobRestriction checkIfRestricted(JobStatus job) {
if (evaluateJobBiasLocked(job) >= JobInfo.BIAS_FOREGROUND_SERVICE) {
// Jobs with BIAS_FOREGROUND_SERVICE or higher should not be restricted
return null;
@@ -2397,38 +2356,9 @@ public class JobSchedulerService extends com.android.server.SystemService
return null;
}
+ @GuardedBy("mLock")
private void stopNonReadyActiveJobsLocked() {
- for (int i=0; i<mActiveServices.size(); i++) {
- JobServiceContext serviceContext = mActiveServices.get(i);
- final JobStatus running = serviceContext.getRunningJobLocked();
- if (running == null) {
- continue;
- }
- if (!running.isReady()) {
- if (running.getEffectiveStandbyBucket() == RESTRICTED_INDEX
- && running.getStopReason() == JobParameters.STOP_REASON_APP_STANDBY) {
- serviceContext.cancelExecutingJobLocked(
- running.getStopReason(),
- JobParameters.INTERNAL_STOP_REASON_RESTRICTED_BUCKET,
- "cancelled due to restricted bucket");
- } else {
- serviceContext.cancelExecutingJobLocked(
- running.getStopReason(),
- JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
- "cancelled due to unsatisfied constraints");
- }
- } else {
- final JobRestriction restriction = checkIfRestricted(running);
- if (restriction != null) {
- final int internalReasonCode = restriction.getInternalReason();
- serviceContext.cancelExecutingJobLocked(restriction.getReason(),
- internalReasonCode,
- "restricted due to "
- + JobParameters.getInternalReasonCodeDescription(
- internalReasonCode));
- }
- }
- }
+ mConcurrencyManager.stopNonReadyActiveJobsLocked();
}
/**
@@ -2598,7 +2528,7 @@ public class JobSchedulerService extends com.android.server.SystemService
debugReason = "couldn't figure out why the job should stop running";
}
}
- stopJobOnServiceContextLocked(job, job.getStopReason(),
+ mConcurrencyManager.stopJobOnServiceContextLocked(job, job.getStopReason(),
internalStopReason, debugReason);
} else if (mPendingJobs.remove(job)) {
noteJobNonPending(job);
@@ -3516,9 +3446,11 @@ public class JobSchedulerService extends com.android.server.SystemService
final ArrayList<JobInfo> runningJobs;
synchronized (mLock) {
- runningJobs = new ArrayList<>(mActiveServices.size());
- for (JobServiceContext jsc : mActiveServices) {
- final JobStatus job = jsc.getRunningJobLocked();
+ final ArraySet<JobStatus> runningJobStatuses =
+ mConcurrencyManager.getRunningJobsLocked();
+ runningJobs = new ArrayList<>(runningJobStatuses.size());
+ for (int i = runningJobStatuses.size() - 1; i >= 0; --i) {
+ final JobStatus job = runningJobStatuses.valueAt(i);
if (job != null) {
runningJobs.add(job.getJob());
}
@@ -3599,18 +3531,8 @@ public class JobSchedulerService extends com.android.server.SystemService
}
synchronized (mLock) {
- boolean foundSome = false;
- for (int i = 0; i < mActiveServices.size(); i++) {
- final JobServiceContext jc = mActiveServices.get(i);
- final JobStatus js = jc.getRunningJobLocked();
- if (jc.timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId, "shell")) {
- foundSome = true;
- pw.print("Timing out: ");
- js.printUniqueId(pw);
- pw.print(" ");
- pw.println(js.getServiceComponent().flattenToShortString());
- }
- }
+ final boolean foundSome = mConcurrencyManager.executeTimeoutCommandLocked(pw,
+ pkgName, userId, hasJobId, jobId);
if (!foundSome) {
pw.println("No matching executing jobs found.");
}
@@ -4037,38 +3959,7 @@ public class JobSchedulerService extends com.android.server.SystemService
pw.decreaseIndent();
pw.println();
- pw.println("Active jobs:");
- pw.increaseIndent();
- for (int i=0; i<mActiveServices.size(); i++) {
- JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus job = jsc.getRunningJobLocked();
-
- if (job != null && !predicate.test(job)) {
- continue;
- }
-
- pw.print("Slot #"); pw.print(i); pw.print(": ");
- jsc.dumpLocked(pw, nowElapsed);
-
- if (job != null) {
- pw.increaseIndent();
-
- pw.increaseIndent();
- job.dump(pw, false, nowElapsed);
- pw.decreaseIndent();
-
- pw.print("Evaluated bias: ");
- pw.println(JobInfo.getBiasString(job.lastEvaluatedBias));
-
- pw.print("Active at ");
- TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
- pw.print(", pending for ");
- TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
- pw.decreaseIndent();
- pw.println();
- }
- }
- pw.decreaseIndent();
+ mConcurrencyManager.dumpActiveJobsLocked(pw, predicate, nowElapsed, nowUptime);
pw.println();
boolean recentPrinted = false;
@@ -4228,45 +4119,6 @@ public class JobSchedulerService extends com.android.server.SystemService
proto.end(pjToken);
}
- for (JobServiceContext jsc : mActiveServices) {
- final long ajToken = proto.start(JobSchedulerServiceDumpProto.ACTIVE_JOBS);
- final JobStatus job = jsc.getRunningJobLocked();
-
- if (job == null) {
- final long ijToken = proto.start(ActiveJob.INACTIVE);
-
- proto.write(ActiveJob.InactiveJob.TIME_SINCE_STOPPED_MS,
- nowElapsed - jsc.mStoppedTime);
- if (jsc.mStoppedReason != null) {
- proto.write(ActiveJob.InactiveJob.STOPPED_REASON,
- jsc.mStoppedReason);
- }
-
- proto.end(ijToken);
- } else {
- final long rjToken = proto.start(ActiveJob.RUNNING);
-
- job.writeToShortProto(proto, ActiveJob.RunningJob.INFO);
-
- proto.write(ActiveJob.RunningJob.RUNNING_DURATION_MS,
- nowElapsed - jsc.getExecutionStartTimeElapsed());
- proto.write(ActiveJob.RunningJob.TIME_UNTIL_TIMEOUT_MS,
- jsc.getTimeoutElapsed() - nowElapsed);
-
- job.dump(proto, ActiveJob.RunningJob.DUMP, false, nowElapsed);
-
- proto.write(ActiveJob.RunningJob.EVALUATED_PRIORITY,
- evaluateJobBiasLocked(job));
-
- proto.write(ActiveJob.RunningJob.TIME_SINCE_MADE_ACTIVE_MS,
- nowUptime - job.madeActive);
- proto.write(ActiveJob.RunningJob.PENDING_DURATION_MS,
- job.madeActive - job.madePending);
-
- proto.end(rjToken);
- }
- proto.end(ajToken);
- }
if (filterUid == -1) {
proto.write(JobSchedulerServiceDumpProto.IS_READY_TO_ROCK, mReadyToRock);
proto.write(JobSchedulerServiceDumpProto.REPORTED_ACTIVE, mReportedActive);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index efcf14f07ee9..30fdb1e9ad4e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -441,11 +441,6 @@ public final class JobStatus {
/** The reason a job most recently went from ready to not ready. */
private int mReasonReadyToUnready = JobParameters.STOP_REASON_UNDEFINED;
- /** Provide a handle to the service that this job will be run on. */
- public int getServiceToken() {
- return callingUid;
- }
-
/**
* Core constructor for JobStatus instances. All other ctors funnel down to this one.
*
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index e986b1a9bf24..2e3b377d08a5 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -384,14 +384,16 @@ public class AppIdleHistory {
return userHistory;
}
+ // TODO (206518483): Remove unused parameter 'elapsedRealtime'.
private AppUsageHistory getPackageHistory(ArrayMap<String, AppUsageHistory> userHistory,
String packageName, long elapsedRealtime, boolean create) {
AppUsageHistory appUsageHistory = userHistory.get(packageName);
if (appUsageHistory == null && create) {
appUsageHistory = new AppUsageHistory();
- appUsageHistory.lastUsedElapsedTime = getElapsedTime(elapsedRealtime);
- appUsageHistory.lastUsedScreenTime = getScreenOnTime(elapsedRealtime);
- appUsageHistory.lastPredictedTime = getElapsedTime(0);
+ appUsageHistory.lastUsedByUserElapsedTime = Integer.MIN_VALUE;
+ appUsageHistory.lastUsedElapsedTime = Integer.MIN_VALUE;
+ appUsageHistory.lastUsedScreenTime = Integer.MIN_VALUE;
+ appUsageHistory.lastPredictedTime = Integer.MIN_VALUE;
appUsageHistory.currentBucket = STANDBY_BUCKET_NEVER;
appUsageHistory.bucketingReason = REASON_MAIN_DEFAULT;
appUsageHistory.lastInformedBucket = -1;
@@ -544,7 +546,7 @@ public class AppIdleHistory {
AppUsageHistory appUsageHistory =
getPackageHistory(userHistory, packageName, elapsedRealtime, false);
if (appUsageHistory == null || appUsageHistory.lastUsedByUserElapsedTime == Long.MIN_VALUE
- || appUsageHistory.lastUsedByUserElapsedTime == 0) {
+ || appUsageHistory.lastUsedByUserElapsedTime <= 0) {
return Long.MAX_VALUE;
}
return getElapsedTime(elapsedRealtime) - appUsageHistory.lastUsedByUserElapsedTime;
@@ -631,8 +633,12 @@ public class AppIdleHistory {
// If we don't have any state for the app, assume never used
if (appUsageHistory == null) return screenTimeThresholds.length - 1;
- long screenOnDelta = getScreenOnTime(elapsedRealtime) - appUsageHistory.lastUsedScreenTime;
- long elapsedDelta = getElapsedTime(elapsedRealtime) - appUsageHistory.lastUsedElapsedTime;
+ long screenOnDelta = appUsageHistory.lastUsedScreenTime >= 0
+ ? getScreenOnTime(elapsedRealtime) - appUsageHistory.lastUsedScreenTime
+ : Long.MAX_VALUE;
+ long elapsedDelta = appUsageHistory.lastUsedElapsedTime >= 0
+ ? getElapsedTime(elapsedRealtime) - appUsageHistory.lastUsedElapsedTime
+ : Long.MAX_VALUE;
if (DEBUG) Slog.d(TAG, packageName
+ " lastUsedScreen=" + appUsageHistory.lastUsedScreenTime
@@ -951,14 +957,14 @@ public class AppIdleHistory {
+ " reason="
+ UsageStatsManager.reasonToString(appUsageHistory.bucketingReason));
idpw.print(" used=");
- TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedElapsedTime, idpw);
+ printLastActionElapsedTime(idpw, totalElapsedTime, appUsageHistory.lastUsedElapsedTime);
idpw.print(" usedByUser=");
- TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedByUserElapsedTime,
- idpw);
+ printLastActionElapsedTime(idpw, totalElapsedTime,
+ appUsageHistory.lastUsedByUserElapsedTime);
idpw.print(" usedScr=");
- TimeUtils.formatDuration(screenOnTime - appUsageHistory.lastUsedScreenTime, idpw);
+ printLastActionElapsedTime(idpw, totalElapsedTime, appUsageHistory.lastUsedScreenTime);
idpw.print(" lastPred=");
- TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastPredictedTime, idpw);
+ printLastActionElapsedTime(idpw, totalElapsedTime, appUsageHistory.lastPredictedTime);
dumpBucketExpiryTimes(idpw, appUsageHistory, totalElapsedTime);
idpw.print(" lastJob=");
TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastJobRunTime, idpw);
@@ -986,6 +992,15 @@ public class AppIdleHistory {
idpw.decreaseIndent();
}
+ private void printLastActionElapsedTime(IndentingPrintWriter idpw, long totalElapsedTimeMS,
+ long lastActionTimeMs) {
+ if (lastActionTimeMs < 0) {
+ idpw.print("<uninitialized>");
+ } else {
+ TimeUtils.formatDuration(totalElapsedTimeMS - lastActionTimeMs, idpw);
+ }
+ }
+
private void dumpBucketExpiryTimes(IndentingPrintWriter idpw, AppUsageHistory appUsageHistory,
long totalElapsedTimeMs) {
idpw.print(" expiryTimes=");
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 4952894c068b..502913063a00 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -100,6 +100,7 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings.Global;
import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
@@ -130,6 +131,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -375,6 +377,15 @@ public class AppStandbyController
ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE;
/**
+ * Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}.
+ *
+ * Note: We are intentionally not guarding this by any lock since this is only updated on
+ * a handler thread and when querying, if we do end up seeing slightly older values, it is fine
+ * since the values are only used in tests and doesn't need to be queried in any other cases.
+ */
+ private final Map<String, String> mAppStandbyProperties = new ArrayMap<>();
+
+ /**
* Whether we should allow apps into the
* {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not.
* If false, any attempts to put an app into the bucket will put the app into the
@@ -887,8 +898,11 @@ public class AppStandbyController
}
}
+ final long elapsedLastUsedByUserTimeDelta = app.lastUsedByUserElapsedTime >= 0
+ ? elapsedTimeAdjusted - app.lastUsedByUserElapsedTime
+ : Long.MAX_VALUE;
if (app.lastRestrictAttemptElapsedTime > app.lastUsedByUserElapsedTime
- && elapsedTimeAdjusted - app.lastUsedByUserElapsedTime
+ && elapsedLastUsedByUserTimeDelta
>= mInjector.getAutoRestrictedBucketDelayMs()) {
newBucket = STANDBY_BUCKET_RESTRICTED;
reason = app.lastRestrictReason;
@@ -1837,6 +1851,12 @@ public class AppStandbyController
}
@Override
+ @Nullable
+ public String getAppStandbyConstant(@NonNull String key) {
+ return mAppStandbyProperties.get(key);
+ }
+
+ @Override
public void flushToDisk() {
synchronized (mAppIdleLock) {
mAppIdleHistory.writeAppIdleTimes(mInjector.elapsedRealtime());
@@ -2774,6 +2794,7 @@ public class AppStandbyController
}
break;
}
+ mAppStandbyProperties.put(name, properties.getString(name, null));
}
}
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 24d48ab5996a..598881db0c50 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4532,22 +4532,36 @@ package android.app {
}
public static class ActivityManager.TaskDescription implements android.os.Parcelable {
- ctor public ActivityManager.TaskDescription(String, @DrawableRes int, int);
- ctor public ActivityManager.TaskDescription(String, @DrawableRes int);
- ctor public ActivityManager.TaskDescription(String);
- ctor public ActivityManager.TaskDescription();
+ ctor @Deprecated public ActivityManager.TaskDescription(String, @DrawableRes int, int);
+ ctor @Deprecated public ActivityManager.TaskDescription(String, @DrawableRes int);
+ ctor @Deprecated public ActivityManager.TaskDescription(String);
+ ctor @Deprecated public ActivityManager.TaskDescription();
ctor @Deprecated public ActivityManager.TaskDescription(String, android.graphics.Bitmap, int);
ctor @Deprecated public ActivityManager.TaskDescription(String, android.graphics.Bitmap);
ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
method public int describeContents();
+ method @ColorInt public int getBackgroundColor();
method @Deprecated public android.graphics.Bitmap getIcon();
method public String getLabel();
- method public int getPrimaryColor();
+ method @ColorInt public int getNavigationBarColor();
+ method @ColorInt public int getPrimaryColor();
+ method @ColorInt public int getStatusBarColor();
method public void readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.ActivityManager.TaskDescription> CREATOR;
}
+ public static final class ActivityManager.TaskDescription.Builder {
+ ctor public ActivityManager.TaskDescription.Builder();
+ method @NonNull public android.app.ActivityManager.TaskDescription build();
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setBackgroundColor(@ColorInt int);
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setIcon(@DrawableRes int);
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setLabel(@Nullable String);
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setNavigationBarColor(@ColorInt int);
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setPrimaryColor(@ColorInt int);
+ method @NonNull public android.app.ActivityManager.TaskDescription.Builder setStatusBarColor(@ColorInt int);
+ }
+
public class ActivityOptions {
method @Nullable public android.graphics.Rect getLaunchBounds();
method public int getLaunchDisplayId();
@@ -5815,6 +5829,7 @@ package android.app {
public class LocaleManager {
method @NonNull public android.os.LocaleList getApplicationLocales();
method @NonNull @RequiresPermission(value="android.permission.READ_APP_SPECIFIC_LOCALES", conditional=true) public android.os.LocaleList getApplicationLocales(@NonNull String);
+ method @NonNull public android.os.LocaleList getSystemLocales();
method public void setApplicationLocales(@NonNull android.os.LocaleList);
}
@@ -7465,6 +7480,8 @@ package android.app.admin {
method public CharSequence getStartUserSessionMessage(@NonNull android.content.ComponentName);
method @Deprecated public boolean getStorageEncryption(@Nullable android.content.ComponentName);
method public int getStorageEncryptionStatus();
+ method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>);
+ method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>, @NonNull java.lang.Object...);
method @Nullable public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
method @Nullable public android.os.PersistableBundle getTransferOwnershipBundle();
method @Nullable public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(@Nullable android.content.ComponentName, @NonNull android.content.ComponentName);
@@ -7706,6 +7723,7 @@ package android.app.admin {
field public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
field @Deprecated public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
field public static final String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
+ field public static final String EXTRA_PROVISIONING_USE_MOBILE_DATA = "android.app.extra.PROVISIONING_USE_MOBILE_DATA";
field public static final String EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY = "android.app.extra.PROVISIONING_WIFI_ANONYMOUS_IDENTITY";
field public static final String EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_CA_CERTIFICATE";
field public static final String EXTRA_PROVISIONING_WIFI_DOMAIN = "android.app.extra.PROVISIONING_WIFI_DOMAIN";
@@ -9736,8 +9754,8 @@ package android.content {
method @Nullable public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler, int);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void removeStickyBroadcast(@RequiresPermission android.content.Intent);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void removeStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
- method public void revokeOwnPermissionOnKill(@NonNull String);
- method public void revokeOwnPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
+ method public void revokeSelfPermissionOnKill(@NonNull String);
+ method public void revokeSelfPermissionsOnKill(@NonNull java.util.Collection<java.lang.String>);
method public abstract void revokeUriPermission(android.net.Uri, int);
method public abstract void revokeUriPermission(String, android.net.Uri, int);
method public abstract void sendBroadcast(@RequiresPermission android.content.Intent);
@@ -10125,12 +10143,16 @@ package android.content {
method @Nullable public long[] getLongArrayExtra(String);
method public long getLongExtra(String, long);
method @Nullable public String getPackage();
- method @Nullable public android.os.Parcelable[] getParcelableArrayExtra(String);
- method @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(String);
- method @Nullable public <T extends android.os.Parcelable> T getParcelableExtra(String);
+ method @Deprecated @Nullable public android.os.Parcelable[] getParcelableArrayExtra(String);
+ method @Nullable public <T> T[] getParcelableArrayExtra(@Nullable String, @NonNull Class<T>);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> java.util.ArrayList<T> getParcelableArrayListExtra(String);
+ method @Nullable public <T> java.util.ArrayList<T> getParcelableArrayListExtra(@Nullable String, @NonNull Class<? extends T>);
+ method @Deprecated @Nullable public <T extends android.os.Parcelable> T getParcelableExtra(String);
+ method @Nullable public <T> T getParcelableExtra(@Nullable String, @NonNull Class<T>);
method @Nullable public String getScheme();
method @Nullable public android.content.Intent getSelector();
- method @Nullable public java.io.Serializable getSerializableExtra(String);
+ method @Deprecated @Nullable public java.io.Serializable getSerializableExtra(String);
+ method @Nullable public <T extends java.io.Serializable> T getSerializableExtra(@Nullable String, @NonNull Class<T>);
method @Nullable public short[] getShortArrayExtra(String);
method public short getShortExtra(String, short);
method @Nullable public android.graphics.Rect getSourceBounds();
@@ -11240,6 +11262,33 @@ package android.content.pm {
field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Attribution> CREATOR;
}
+ public final class Capability implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public String getName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Capability> CREATOR;
+ }
+
+ public static final class Capability.Builder {
+ ctor public Capability.Builder(@NonNull String);
+ method @NonNull public android.content.pm.Capability build();
+ }
+
+ public final class CapabilityParams implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getAliases();
+ method @NonNull public String getName();
+ method @NonNull public String getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.CapabilityParams> CREATOR;
+ }
+
+ public static final class CapabilityParams.Builder {
+ ctor public CapabilityParams.Builder(@NonNull String, @NonNull String);
+ method @NonNull public android.content.pm.CapabilityParams.Builder addAlias(@NonNull String);
+ method @NonNull public android.content.pm.CapabilityParams build();
+ }
+
public final class ChangedPackages implements android.os.Parcelable {
ctor public ChangedPackages(int, @NonNull java.util.List<java.lang.String>);
method public int describeContents();
@@ -12301,7 +12350,8 @@ package android.content.pm {
method @NonNull public static android.content.pm.ShortcutInfo createFromGenericDocument(@NonNull android.content.Context, @NonNull android.app.appsearch.GenericDocument);
method public int describeContents();
method @Nullable public android.content.ComponentName getActivity();
- method @NonNull public java.util.List<java.lang.String> getCapabilityParameterValues(@NonNull String, @NonNull String);
+ method @NonNull public java.util.List<android.content.pm.Capability> getCapabilities();
+ method @NonNull public java.util.List<android.content.pm.CapabilityParams> getCapabilityParams(@NonNull android.content.pm.Capability);
method @Nullable public java.util.Set<java.lang.String> getCategories();
method @Nullable public CharSequence getDisabledMessage();
method public int getDisabledReason();
@@ -12316,7 +12366,6 @@ package android.content.pm {
method public int getRank();
method @Nullable public CharSequence getShortLabel();
method public android.os.UserHandle getUserHandle();
- method public boolean hasCapability(@NonNull String);
method public boolean hasKeyFieldsOnly();
method public boolean isCached();
method public boolean isDeclaredInManifest();
@@ -12341,7 +12390,7 @@ package android.content.pm {
public static class ShortcutInfo.Builder {
ctor public ShortcutInfo.Builder(android.content.Context, String);
- method @NonNull public android.content.pm.ShortcutInfo.Builder addCapabilityBinding(@NonNull String, @Nullable String, @Nullable java.util.List<java.lang.String>);
+ method @NonNull public android.content.pm.ShortcutInfo.Builder addCapabilityBinding(@NonNull android.content.pm.Capability, @Nullable android.content.pm.CapabilityParams);
method @NonNull public android.content.pm.ShortcutInfo build();
method @NonNull public android.content.pm.ShortcutInfo.Builder setActivity(@NonNull android.content.ComponentName);
method @NonNull public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
@@ -19487,26 +19536,26 @@ package android.location {
method @NonNull public static String convert(@FloatRange double, int);
method @FloatRange public static double convert(@NonNull String);
method public int describeContents();
- method public static void distanceBetween(@FloatRange double, @FloatRange double, @FloatRange double, @FloatRange double, float[]);
- method @FloatRange public float distanceTo(@NonNull android.location.Location);
- method public void dump(@NonNull android.util.Printer, @Nullable String);
- method @FloatRange public float getAccuracy();
+ method public static void distanceBetween(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, float[]);
+ method @FloatRange(from=0.0) public float distanceTo(@NonNull android.location.Location);
+ method @Deprecated public void dump(@NonNull android.util.Printer, @Nullable String);
+ method @FloatRange(from=0.0) public float getAccuracy();
method @FloatRange public double getAltitude();
- method @FloatRange(from=0.0f, to=360.0f, toInclusive=false) public float getBearing();
- method @FloatRange public float getBearingAccuracyDegrees();
- method @IntRange public long getElapsedRealtimeAgeMillis();
- method @IntRange public long getElapsedRealtimeAgeMillis(@IntRange long);
- method @IntRange public long getElapsedRealtimeMillis();
- method @IntRange public long getElapsedRealtimeNanos();
- method @FloatRange public double getElapsedRealtimeUncertaintyNanos();
+ method @FloatRange(from=0.0, to=360.0, toInclusive=false) public float getBearing();
+ method @FloatRange(from=0.0) public float getBearingAccuracyDegrees();
+ method @IntRange(from=0) public long getElapsedRealtimeAgeMillis();
+ method public long getElapsedRealtimeAgeMillis(@IntRange(from=0) long);
+ method @IntRange(from=0) public long getElapsedRealtimeMillis();
+ method @IntRange(from=0) public long getElapsedRealtimeNanos();
+ method @FloatRange(from=0.0) public double getElapsedRealtimeUncertaintyNanos();
method @Nullable public android.os.Bundle getExtras();
- method @FloatRange public double getLatitude();
- method @FloatRange public double getLongitude();
+ method @FloatRange(from=-90.0, to=90.0) public double getLatitude();
+ method @FloatRange(from=-180.0, to=180.0) public double getLongitude();
method @Nullable public String getProvider();
- method @FloatRange public float getSpeed();
- method @FloatRange public float getSpeedAccuracyMetersPerSecond();
- method @IntRange public long getTime();
- method @FloatRange public float getVerticalAccuracyMeters();
+ method @FloatRange(from=0.0) public float getSpeed();
+ method @FloatRange(from=0.0) public float getSpeedAccuracyMetersPerSecond();
+ method @IntRange(from=0) public long getTime();
+ method @FloatRange(from=0.0) public float getVerticalAccuracyMeters();
method public boolean hasAccuracy();
method public boolean hasAltitude();
method public boolean hasBearing();
@@ -19528,21 +19577,21 @@ package android.location {
method public void removeVerticalAccuracy();
method public void reset();
method public void set(@NonNull android.location.Location);
- method public void setAccuracy(@FloatRange float);
+ method public void setAccuracy(@FloatRange(from=0.0) float);
method public void setAltitude(@FloatRange double);
method public void setBearing(@FloatRange(fromInclusive=false, toInclusive=false) float);
- method public void setBearingAccuracyDegrees(@FloatRange float);
- method public void setElapsedRealtimeNanos(@IntRange long);
- method public void setElapsedRealtimeUncertaintyNanos(@FloatRange double);
+ method public void setBearingAccuracyDegrees(@FloatRange(from=0.0) float);
+ method public void setElapsedRealtimeNanos(@IntRange(from=0) long);
+ method public void setElapsedRealtimeUncertaintyNanos(@FloatRange(from=0.0) double);
method public void setExtras(@Nullable android.os.Bundle);
- method public void setLatitude(@FloatRange double);
- method public void setLongitude(@FloatRange double);
+ method public void setLatitude(@FloatRange(from=-90.0, to=90.0) double);
+ method public void setLongitude(@FloatRange(from=-180.0, to=180.0) double);
method public void setMock(boolean);
method public void setProvider(@Nullable String);
- method public void setSpeed(@FloatRange float);
- method public void setSpeedAccuracyMetersPerSecond(@FloatRange float);
- method public void setTime(@IntRange long);
- method public void setVerticalAccuracyMeters(@FloatRange float);
+ method public void setSpeed(@FloatRange(from=0.0) float);
+ method public void setSpeedAccuracyMetersPerSecond(@FloatRange(from=0.0) float);
+ method public void setTime(@IntRange(from=0) long);
+ method public void setVerticalAccuracyMeters(@FloatRange(from=0.0) float);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.Location> CREATOR;
field public static final int FORMAT_DEGREES = 0; // 0x0
@@ -22186,7 +22235,7 @@ package android.media {
field public static final String KEY_AAC_DRC_OUTPUT_LOUDNESS = "aac-drc-output-loudness";
field public static final String KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level";
field public static final String KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level";
- field public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
+ field @Deprecated public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
field public static final String KEY_AAC_PROFILE = "aac-profile";
field public static final String KEY_AAC_SBR_MODE = "aac-sbr-mode";
field public static final String KEY_ALLOW_FRAME_DROP = "allow-frame-drop";
@@ -22205,6 +22254,10 @@ package android.media {
field public static final String KEY_COLOR_TRANSFER_REQUEST = "color-transfer-request";
field public static final String KEY_COMPLEXITY = "complexity";
field public static final String KEY_CREATE_INPUT_SURFACE_SUSPENDED = "create-input-buffers-suspended";
+ field public static final String KEY_CROP_BOTTOM = "crop-bottom";
+ field public static final String KEY_CROP_LEFT = "crop-left";
+ field public static final String KEY_CROP_RIGHT = "crop-right";
+ field public static final String KEY_CROP_TOP = "crop-top";
field public static final String KEY_DURATION = "durationUs";
field public static final String KEY_ENCODER_DELAY = "encoder-delay";
field public static final String KEY_ENCODER_PADDING = "encoder-padding";
@@ -22894,7 +22947,6 @@ package android.media {
method public int describeContents();
method @Nullable public String getClientPackageName();
method public int getConnectionState();
- method @NonNull public java.util.Set<java.lang.String> getDeduplicationIds();
method @Nullable public CharSequence getDescription();
method @Nullable public android.os.Bundle getExtras();
method @NonNull public java.util.List<java.lang.String> getFeatures();
@@ -22928,7 +22980,6 @@ package android.media {
method @NonNull public android.media.MediaRoute2Info.Builder clearFeatures();
method @NonNull public android.media.MediaRoute2Info.Builder setClientPackageName(@Nullable String);
method @NonNull public android.media.MediaRoute2Info.Builder setConnectionState(int);
- method @NonNull public android.media.MediaRoute2Info.Builder setDeduplicationIds(@NonNull java.util.Set<java.lang.String>);
method @NonNull public android.media.MediaRoute2Info.Builder setDescription(@Nullable CharSequence);
method @NonNull public android.media.MediaRoute2Info.Builder setExtras(@Nullable android.os.Bundle);
method @NonNull public android.media.MediaRoute2Info.Builder setIconUri(@Nullable android.net.Uri);
@@ -23455,11 +23506,8 @@ package android.media {
public final class RouteDiscoveryPreference implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public java.util.List<java.lang.String> getAllowedPackages();
- method @NonNull public java.util.List<java.lang.String> getDeduplicationPackageOrder();
method @NonNull public java.util.List<java.lang.String> getPreferredFeatures();
method public boolean shouldPerformActiveScan();
- method public boolean shouldRemoveDuplicates();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.RouteDiscoveryPreference> CREATOR;
}
@@ -23468,8 +23516,6 @@ package android.media {
ctor public RouteDiscoveryPreference.Builder(@NonNull java.util.List<java.lang.String>, boolean);
ctor public RouteDiscoveryPreference.Builder(@NonNull android.media.RouteDiscoveryPreference);
method @NonNull public android.media.RouteDiscoveryPreference build();
- method @NonNull public android.media.RouteDiscoveryPreference.Builder setAllowedPackages(@NonNull java.util.List<java.lang.String>);
- method @NonNull public android.media.RouteDiscoveryPreference.Builder setDeduplicationPackageOrder(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.media.RouteDiscoveryPreference.Builder setPreferredFeatures(@NonNull java.util.List<java.lang.String>);
method @NonNull public android.media.RouteDiscoveryPreference.Builder setShouldPerformActiveScan(boolean);
}
@@ -23548,17 +23594,24 @@ package android.media {
}
public class Spatializer {
+ method public void addOnHeadTrackerAvailableListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnHeadTrackerAvailableListener);
method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
method public int getImmersiveAudioLevel();
method public boolean isAvailable();
method public boolean isEnabled();
+ method public boolean isHeadTrackerAvailable();
+ method public void removeOnHeadTrackerAvailableListener(@NonNull android.media.Spatializer.OnHeadTrackerAvailableListener);
method public void removeOnSpatializerStateChangedListener(@NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1; // 0x1
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0; // 0x0
field public static final int SPATIALIZER_IMMERSIVE_LEVEL_OTHER = -1; // 0xffffffff
}
+ public static interface Spatializer.OnHeadTrackerAvailableListener {
+ method public void onHeadTrackerAvailableChanged(@NonNull android.media.Spatializer, boolean);
+ }
+
public static interface Spatializer.OnSpatializerStateChangedListener {
method public void onSpatializerAvailableChanged(@NonNull android.media.Spatializer, boolean);
method public void onSpatializerEnabledChanged(@NonNull android.media.Spatializer, boolean);
@@ -25191,17 +25244,23 @@ package android.media.tv {
}
public final class CommandRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
- ctor public CommandRequest(int, int, @NonNull String, @NonNull String, @NonNull String);
+ ctor public CommandRequest(int, int, @NonNull String, @NonNull String, @NonNull String, @NonNull String);
+ method @NonNull public String getArgumentType();
method @NonNull public String getArguments();
method @NonNull public String getName();
- method @NonNull public String getNameSpace();
+ method @NonNull public String getNamespace();
+ field public static final String ARGUMENT_TYPE_JSON = "json";
+ field public static final String ARGUMENT_TYPE_XML = "xml";
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.CommandRequest> CREATOR;
}
public final class CommandResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
- ctor public CommandResponse(int, int, int, @Nullable String);
+ ctor public CommandResponse(int, int, int, @Nullable String, @NonNull String);
method @Nullable public String getResponse();
+ method @NonNull public String getResponseType();
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.CommandResponse> CREATOR;
+ field public static final String RESPONSE_TYPE_JSON = "json";
+ field public static final String RESPONSE_TYPE_XML = "xml";
}
public final class DsmccRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
@@ -25266,7 +25325,7 @@ package android.media.tv {
ctor public StreamEventResponse(int, int, int, int, long, @Nullable byte[]);
method @Nullable public byte[] getData();
method public int getEventId();
- method public long getNpt();
+ method public long getNptMillis();
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.StreamEventResponse> CREATOR;
}
@@ -25296,7 +25355,7 @@ package android.media.tv {
public final class TimelineResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
ctor public TimelineResponse(int, int, int, @Nullable String, int, int, long, long);
- method @Nullable public String getSelector();
+ method @Nullable public android.net.Uri getSelector();
method public long getTicks();
method public int getUnitsPerSecond();
method public int getUnitsPerTick();
@@ -26059,7 +26118,7 @@ package android.media.tv {
method public void onContentAllowed(String);
method public void onContentBlocked(String, android.media.tv.TvContentRating);
method public void onDisconnected(String);
- method public void onSignalStrength(@NonNull String, int);
+ method public void onSignalStrengthUpdated(@NonNull String, int);
method public void onTimeShiftStatusChanged(String, int);
method public void onTrackSelected(String, int, String);
method public void onTracksChanged(String, java.util.List<android.media.tv.TvTrackInfo>);
@@ -26074,40 +26133,16 @@ package android.media.tv {
package android.media.tv.interactive {
public final class AppLinkInfo implements android.os.Parcelable {
+ ctor public AppLinkInfo(@NonNull String, @NonNull String, @NonNull String);
method public int describeContents();
- method @NonNull public String getClassName();
- method @NonNull public String getPackageName();
- method @Nullable public String getUriHost();
- method @Nullable public String getUriPrefix();
- method @Nullable public String getUriScheme();
+ method @NonNull public android.content.ComponentName getComponentName();
+ method @NonNull public android.net.Uri getUri();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.AppLinkInfo> CREATOR;
}
- public static final class AppLinkInfo.Builder {
- ctor public AppLinkInfo.Builder(@NonNull String, @NonNull String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo build();
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriHost(@NonNull String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriPrefix(@NonNull String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriScheme(@NonNull String);
- }
-
- public final class TvInteractiveAppInfo implements android.os.Parcelable {
- ctor public TvInteractiveAppInfo(@NonNull android.content.Context, @NonNull android.content.ComponentName);
- method public int describeContents();
- method @NonNull public String getId();
- method @Nullable public android.content.pm.ServiceInfo getServiceInfo();
- method @NonNull public int getSupportedTypes();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.TvInteractiveAppInfo> CREATOR;
- field public static final int INTERACTIVE_APP_TYPE_ATSC = 2; // 0x2
- field public static final int INTERACTIVE_APP_TYPE_GINGA = 4; // 0x4
- field public static final int INTERACTIVE_APP_TYPE_HBBTV = 1; // 0x1
- }
-
public final class TvInteractiveAppManager {
- method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppInfo> getTvInteractiveAppServiceList();
- method public void prepare(@NonNull String, int);
+ method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList();
method public void registerAppLinkInfo(@NonNull String, @NonNull android.media.tv.interactive.AppLinkInfo);
method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback);
method public void sendAppLinkCommand(@NonNull String, @NonNull android.os.Bundle);
@@ -26130,6 +26165,7 @@ package android.media.tv.interactive {
field public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type";
field public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri";
field public static final String INTENT_KEY_CHANNEL_URI = "channel_uri";
+ field public static final String INTENT_KEY_COMMAND_TYPE = "command_type";
field public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
field public static final String INTENT_KEY_TV_INPUT_ID = "tv_input_id";
field public static final int INTERACTIVE_APP_STATE_ERROR = 3; // 0x3
@@ -26158,7 +26194,6 @@ package android.media.tv.interactive {
method public void onAppLinkCommand(@NonNull android.os.Bundle);
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method @Nullable public abstract android.media.tv.interactive.TvInteractiveAppService.Session onCreateSession(@NonNull String, int);
- method public abstract void onPrepare(int);
method public void onRegisterAppLinkInfo(@NonNull android.media.tv.interactive.AppLinkInfo);
method public void onUnregisterAppLinkInfo(@NonNull android.media.tv.interactive.AppLinkInfo);
field public static final String COMMAND_PARAMETER_KEY_CHANGE_CHANNEL_QUIETLY = "command_change_channel_quietly";
@@ -26179,6 +26214,7 @@ package android.media.tv.interactive {
public abstract static class TvInteractiveAppService.Session implements android.view.KeyEvent.Callback {
ctor public TvInteractiveAppService.Session(@NonNull android.content.Context);
+ method public boolean isMediaViewEnabled();
method @CallSuper public void layoutSurface(int, int, int, int);
method @CallSuper public final void notifyBiInteractiveAppCreated(@NonNull android.net.Uri, @Nullable String);
method @CallSuper public void notifySessionStateChanged(int, int);
@@ -26187,23 +26223,24 @@ package android.media.tv.interactive {
method public void onBroadcastInfoResponse(@NonNull android.media.tv.BroadcastInfoResponse);
method public void onContentAllowed();
method public void onContentBlocked(@NonNull android.media.tv.TvContentRating);
- method public void onCreateBiInteractiveApp(@NonNull android.net.Uri, @Nullable android.os.Bundle);
+ method public void onCreateBiInteractiveAppRequest(@NonNull android.net.Uri, @Nullable android.os.Bundle);
method @Nullable public android.view.View onCreateMediaView();
method public void onCurrentChannelLcn(int);
method public void onCurrentChannelUri(@Nullable android.net.Uri);
method public void onCurrentTvInputId(@Nullable String);
- method public void onDestroyBiInteractiveApp(@NonNull String);
+ method public void onDestroyBiInteractiveAppRequest(@NonNull String);
method public boolean onGenericMotionEvent(@NonNull android.view.MotionEvent);
method public boolean onKeyDown(int, @NonNull android.view.KeyEvent);
method public boolean onKeyLongPress(int, @NonNull android.view.KeyEvent);
method public boolean onKeyMultiple(int, int, @NonNull android.view.KeyEvent);
method public boolean onKeyUp(int, @NonNull android.view.KeyEvent);
- method public void onMediaViewSizeChanged(int, int);
+ method public void onMediaViewSizeChanged(@Px int, @Px int);
method public abstract void onRelease();
method public void onResetInteractiveApp();
method public abstract boolean onSetSurface(@Nullable android.view.Surface);
method public void onSetTeletextAppEnabled(boolean);
method public void onSignalStrength(int);
+ method public void onSigningResult(@NonNull String, @NonNull byte[]);
method public void onStartInteractiveApp();
method public void onStopInteractiveApp();
method public void onStreamVolume(float);
@@ -26222,6 +26259,7 @@ package android.media.tv.interactive {
method @CallSuper public void requestCurrentChannelLcn();
method @CallSuper public void requestCurrentChannelUri();
method @CallSuper public void requestCurrentTvInputId();
+ method @CallSuper public void requestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
method @CallSuper public void requestStreamVolume();
method @CallSuper public void requestTrackInfoList();
method @CallSuper public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle);
@@ -26229,6 +26267,19 @@ package android.media.tv.interactive {
method @CallSuper public void setVideoBounds(@NonNull android.graphics.Rect);
}
+ public final class TvInteractiveAppServiceInfo implements android.os.Parcelable {
+ ctor public TvInteractiveAppServiceInfo(@NonNull android.content.Context, @NonNull android.content.ComponentName);
+ method public int describeContents();
+ method @NonNull public String getId();
+ method @Nullable public android.content.pm.ServiceInfo getServiceInfo();
+ method @NonNull public int getSupportedTypes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.interactive.TvInteractiveAppServiceInfo> CREATOR;
+ field public static final int INTERACTIVE_APP_TYPE_ATSC = 2; // 0x2
+ field public static final int INTERACTIVE_APP_TYPE_GINGA = 4; // 0x4
+ field public static final int INTERACTIVE_APP_TYPE_HBBTV = 1; // 0x1
+ }
+
public class TvInteractiveAppView extends android.view.ViewGroup {
ctor public TvInteractiveAppView(@NonNull android.content.Context);
ctor public TvInteractiveAppView(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
@@ -26238,6 +26289,7 @@ package android.media.tv.interactive {
method public void createBiInteractiveApp(@NonNull android.net.Uri, @Nullable android.os.Bundle);
method public void destroyBiInteractiveApp(@NonNull String);
method public boolean dispatchUnhandledInputEvent(@NonNull android.view.InputEvent);
+ method @Nullable public android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener getOnUnhandledInputEventListener();
method public void onAttachedToWindow();
method public void onDetachedFromWindow();
method public void onLayout(boolean, int, int, int, int);
@@ -26250,6 +26302,7 @@ package android.media.tv.interactive {
method public void sendCurrentChannelLcn(int);
method public void sendCurrentChannelUri(@Nullable android.net.Uri);
method public void sendCurrentTvInputId(@Nullable String);
+ method public void sendSigningResult(@NonNull String, @NonNull byte[]);
method public void sendStreamVolume(float);
method public void sendTrackInfoList(@Nullable java.util.List<android.media.tv.TvTrackInfo>);
method public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.TvInteractiveAppCallback);
@@ -26258,6 +26311,11 @@ package android.media.tv.interactive {
method public int setTvView(@Nullable android.media.tv.TvView);
method public void startInteractiveApp();
method public void stopInteractiveApp();
+ field public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias";
+ field public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate";
+ field public static final String BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS = "http_additional_headers";
+ field public static final String BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT = "http_user_agent";
+ field public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key";
}
public static interface TvInteractiveAppView.OnUnhandledInputEventListener {
@@ -26271,6 +26329,7 @@ package android.media.tv.interactive {
method public void onRequestCurrentChannelLcn(@NonNull String);
method public void onRequestCurrentChannelUri(@NonNull String);
method public void onRequestCurrentTvInputId(@NonNull String);
+ method public void onRequestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
method public void onRequestStreamVolume(@NonNull String);
method public void onRequestTrackInfoList(@NonNull String);
method public void onSetVideoBounds(@NonNull String, @NonNull android.graphics.Rect);
@@ -43796,6 +43855,7 @@ package android.telephony.data {
method public int getNetworkTypeBitmask();
method public String getOperatorNumeric();
method public String getPassword();
+ method public int getProfileId();
method public int getProtocol();
method @Deprecated public java.net.InetAddress getProxyAddress();
method public String getProxyAddressAsString();
@@ -43803,6 +43863,7 @@ package android.telephony.data {
method public int getRoamingProtocol();
method public String getUser();
method public boolean isEnabled();
+ method public boolean isPersistent();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int AUTH_TYPE_CHAP = 2; // 0x2
field public static final int AUTH_TYPE_NONE = 0; // 0x0
@@ -57906,7 +57967,7 @@ package android.window {
}
public interface OnBackInvokedDispatcher {
- method public void registerOnBackInvokedCallback(@NonNull android.window.OnBackInvokedCallback, @IntRange(from=0) int);
+ method public void registerOnBackInvokedCallback(@IntRange(from=0) int, @NonNull android.window.OnBackInvokedCallback);
method public void unregisterOnBackInvokedCallback(@NonNull android.window.OnBackInvokedCallback);
field public static final int PRIORITY_DEFAULT = 0; // 0x0
field public static final int PRIORITY_OVERLAY = 1000000; // 0xf4240
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5df988153752..c8c94b5fca70 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -244,6 +244,7 @@ package android {
field public static final String READ_APP_SPECIFIC_LOCALES = "android.permission.READ_APP_SPECIFIC_LOCALES";
field public static final String READ_CARRIER_APP_INFO = "android.permission.READ_CARRIER_APP_INFO";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
+ field public static final String READ_CLIPBOARD_IN_BACKGROUND = "android.permission.READ_CLIPBOARD_IN_BACKGROUND";
field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
@@ -1079,6 +1080,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int checkProvisioningPrecondition(@NonNull String, @NonNull String);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void finalizeWorkProfileProvisioning(@NonNull android.os.UserHandle, @Nullable android.accounts.Account);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
@@ -1089,8 +1091,6 @@ package android.app.admin {
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
- method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>);
- method @Nullable public String getString(@NonNull String, @NonNull java.util.function.Supplier<java.lang.String>, @NonNull java.lang.Object...);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public int getUserProvisioningState();
method public boolean isDeviceManaged();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
@@ -1103,8 +1103,8 @@ package android.app.admin {
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, android.Manifest.permission.PROVISION_DEMO_DEVICE}) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull String[]);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetStrings(@NonNull String[]);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull java.util.Set<java.lang.String>);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetStrings(@NonNull java.util.Set<java.lang.String>);
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();
@@ -1149,6 +1149,7 @@ package android.app.admin {
field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
field public static final String EXTRA_ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE = "android.app.extra.ROLE_HOLDER_PROVISIONING_INITIATOR_PACKAGE";
field public static final String EXTRA_ROLE_HOLDER_STATE = "android.app.extra.ROLE_HOLDER_STATE";
+ field public static final String EXTRA_ROLE_HOLDER_UPDATE_RESULT_CODE = "android.app.extra.ROLE_HOLDER_UPDATE_RESULT_CODE";
field public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
field public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
@@ -1162,6 +1163,7 @@ package android.app.admin {
field public static final String REQUIRED_APP_MANAGED_PROFILE = "android.app.REQUIRED_APP_MANAGED_PROFILE";
field public static final String REQUIRED_APP_MANAGED_USER = "android.app.REQUIRED_APP_MANAGED_USER";
field public static final int RESULT_DEVICE_OWNER_SET = 123; // 0x7b
+ field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED = 3; // 0x3
field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1; // 0x1
field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2; // 0x2
field public static final int RESULT_UPDATE_ROLE_HOLDER = 2; // 0x2
@@ -3413,6 +3415,8 @@ package android.content.pm {
field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
+ field public static final String FEATURE_EROFS = "android.software.erofs";
+ field public static final String FEATURE_EROFS_LEGACY = "android.software.erofs_legacy";
field public static final String FEATURE_GAME_SERVICE = "android.software.game_service";
field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
@@ -5490,6 +5494,32 @@ package android.location {
method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean);
}
+ public final class GnssExcessPathInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @FloatRange(from=0.0f) public float getAttenuationDb();
+ method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
+ method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+ method @NonNull public android.location.GnssReflectingPlane getReflectingPlane();
+ method public boolean hasAttenuation();
+ method public boolean hasExcessPathLength();
+ method public boolean hasExcessPathLengthUncertainty();
+ method public boolean hasReflectingPlane();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssExcessPathInfo> CREATOR;
+ }
+
+ public static final class GnssExcessPathInfo.Builder {
+ ctor public GnssExcessPathInfo.Builder();
+ method @NonNull public android.location.GnssExcessPathInfo build();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearAttenuationDb();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthMeters();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthUncertaintyMeters();
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setAttenuationDb(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssExcessPathInfo.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+ }
+
public final class GnssMeasurement implements android.os.Parcelable {
method @Nullable public java.util.Collection<android.location.CorrelationVector> getCorrelationVectors();
method @Nullable public android.location.SatellitePvt getSatellitePvt();
@@ -5571,15 +5601,18 @@ package android.location {
public final class GnssSingleSatCorrection implements android.os.Parcelable {
method public int describeContents();
method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
+ method @FloatRange(from=0.0f) public float getCombinedAttenuationDb();
method public int getConstellationType();
method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+ method @NonNull public java.util.List<android.location.GnssExcessPathInfo> getGnssExcessPathInfoList();
method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
- method @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
+ method @Deprecated @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
method @IntRange(from=0) public int getSatelliteId();
+ method public boolean hasCombinedAttenuation();
method public boolean hasExcessPathLength();
method public boolean hasExcessPathLengthUncertainty();
- method public boolean hasReflectingPlane();
+ method @Deprecated public boolean hasReflectingPlane();
method public boolean hasValidSatelliteLineOfSight();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
@@ -5588,15 +5621,18 @@ package android.location {
public static final class GnssSingleSatCorrection.Builder {
ctor public GnssSingleSatCorrection.Builder();
method @NonNull public android.location.GnssSingleSatCorrection build();
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder clearCombinedAttenuationDb();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder setCombinedAttenuationDb(@FloatRange(from=0.0f) float);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+ method @NonNull public android.location.GnssSingleSatCorrection.Builder setGnssExcessPathInfoList(@NonNull java.util.List<android.location.GnssExcessPathInfo>);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+ method @Deprecated @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
}
@@ -10049,9 +10085,9 @@ package android.permission {
method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
- method @BinderThread public void onRevokeOwnPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
+ method @BinderThread public void onRevokeSelfPermissionsOnKill(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull Runnable);
method @Deprecated @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull android.permission.AdminPermissionControlParams, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 2e8bed32665c..a67d002cdddf 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -300,7 +300,6 @@ package android.app {
}
public class LocaleManager {
- method @Nullable public android.os.LocaleList getSystemLocales();
method public void setSystemLocales(@NonNull android.os.LocaleList);
}
@@ -502,6 +501,7 @@ package android.app.admin {
method public void forceUpdateUserSetupComplete(int);
method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages();
method public int getDeviceOwnerType(@NonNull android.content.ComponentName);
+ method @Nullable public String getDevicePolicyManagementRoleHolderUpdaterPackage();
method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String);
method public long getLastBugReportRequestTime();
method public long getLastNetworkLogRetrievalTime();
@@ -512,7 +512,6 @@ package android.app.admin {
method public boolean isFactoryResetProtectionPolicySupported();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean isNewUserDisclaimerAcknowledged();
method public boolean isRemovingAdmin(@NonNull android.content.ComponentName, int);
- method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
method @NonNull public static String operationSafetyReasonToString(int);
method @NonNull public static String operationToString(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void resetDefaultCrossProfileIntentFilters(int);
@@ -521,6 +520,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwnerOnly(@NonNull android.content.ComponentName, @Nullable String, int);
method public void setDeviceOwnerType(@NonNull android.content.ComponentName, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public void setNextOperationSafety(int, int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void setProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName, boolean);
field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
field public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED = "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED";
field public static final int DEVICE_OWNER_TYPE_DEFAULT = 0; // 0x0
@@ -2429,7 +2429,7 @@ package android.service.quicksettings {
package android.service.voice {
public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector {
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]);
+ method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], @NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>);
}
public static final class AlwaysOnHotwordDetector.EventPayload.Builder {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index a5526bc66431..f081a439c49c 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -145,16 +145,16 @@ genrule {
out: ["com/android/internal/util/FrameworkStatsLog.java"],
}
+// Library that provides functionality to log UiEvents in framework space.
+// If this functionality is needed outside the framework, the interfaces library
+// can be re-used and a local implementation is needed.
java_library {
name: "uieventloggerlib",
srcs: [
- "com/android/internal/logging/UiEvent.java",
- "com/android/internal/logging/UiEventLogger.java",
"com/android/internal/logging/UiEventLoggerImpl.java",
- "com/android/internal/logging/InstanceId.java",
- "com/android/internal/logging/InstanceIdSequence.java",
":statslog-framework-java-gen",
],
+ static_libs: ["modules-utils-uieventlogger-interface"],
}
filegroup {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9f1510526bae..0ff070185fcb 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -22,6 +22,7 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import android.Manifest;
+import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -1264,6 +1265,104 @@ public class ActivityManager {
private int mMinWidth;
private int mMinHeight;
+ /**
+ * Provides a convenient way to set the fields of a {@link TaskDescription} when creating a
+ * new instance.
+ */
+ public static final class Builder {
+ /**
+ * Default values for the TaskDescription
+ */
+ @Nullable
+ private String mLabel = null;
+ @DrawableRes
+ private int mIconRes = Resources.ID_NULL;
+ private int mPrimaryColor = 0;
+ private int mBackgroundColor = 0;
+ private int mStatusBarColor = 0;
+ private int mNavigationBarColor = 0;
+
+ /**
+ * Set the label to use in the TaskDescription.
+ * @param label A label and description of the current state of this activity.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setLabel(@Nullable String label) {
+ this.mLabel = label;
+ return this;
+ }
+
+ /**
+ * Set the drawable resource of the icon to use in the TaskDescription.
+ * @param iconRes A drawable resource of an icon that represents the current state of
+ * this activity.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setIcon(@DrawableRes int iconRes) {
+ this.mIconRes = iconRes;
+ return this;
+ }
+
+ /**
+ * Set the primary color to use in the TaskDescription.
+ * @param color A color to override the theme's primary color. The color must be opaque.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setPrimaryColor(@ColorInt int color) {
+ this.mPrimaryColor = color;
+ return this;
+ }
+
+ /**
+ * Set the background color to use in the TaskDescription.
+ * @param color A color to override the theme's background color. The color must be
+ * opaque.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setBackgroundColor(@ColorInt int color) {
+ this.mBackgroundColor = color;
+ return this;
+ }
+
+ /**
+ * Set the status bar color to use in the TaskDescription.
+ * @param color A color to override the theme's status bar color.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setStatusBarColor(@ColorInt int color) {
+ this.mStatusBarColor = color;
+ return this;
+ }
+
+ /**
+ * Set the navigation bar color to use in the TaskDescription.
+ * @param color A color to override the theme's navigation bar color.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public Builder setNavigationBarColor(@ColorInt int color) {
+ this.mNavigationBarColor = color;
+ return this;
+ }
+
+ /**
+ * Build the TaskDescription.
+ * @return the TaskDescription object.
+ */
+ @NonNull
+ public TaskDescription build() {
+ final Icon icon = mIconRes == Resources.ID_NULL ? null :
+ Icon.createWithResource(ActivityThread.currentPackageName(), mIconRes);
+ return new TaskDescription(mLabel, icon, mPrimaryColor, mBackgroundColor,
+ mStatusBarColor, mNavigationBarColor, false, false, RESIZE_MODE_RESIZEABLE,
+ -1, -1, 0);
+ }
+ }
/**
* Creates the TaskDescription to the specified values.
@@ -1273,7 +1372,10 @@ public class ActivityManager {
* activity.
* @param colorPrimary A color to override the theme's primary color. This color must be
* opaque.
+ *
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public TaskDescription(String label, @DrawableRes int iconRes, int colorPrimary) {
this(label, Icon.createWithResource(ActivityThread.currentPackageName(), iconRes),
colorPrimary, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
@@ -1288,7 +1390,10 @@ public class ActivityManager {
* @param label A label and description of the current state of this activity.
* @param iconRes A drawable resource of an icon that represents the current state of this
* activity.
+ *
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public TaskDescription(String label, @DrawableRes int iconRes) {
this(label, Icon.createWithResource(ActivityThread.currentPackageName(), iconRes),
0, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
@@ -1298,14 +1403,20 @@ public class ActivityManager {
* Creates the TaskDescription to the specified values.
*
* @param label A label and description of the current state of this activity.
+ *
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public TaskDescription(String label) {
this(label, null, 0, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
}
/**
* Creates an empty TaskDescription.
+ *
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public TaskDescription() {
this(null, null, 0, 0, 0, 0, false, false, RESIZE_MODE_RESIZEABLE, -1, -1, 0);
}
@@ -1317,7 +1428,8 @@ public class ActivityManager {
* @param icon An icon that represents the current state of this task.
* @param colorPrimary A color to override the theme's primary color. This color must be
* opaque.
- * @deprecated use TaskDescription constructor with icon resource instead
+ *
+ * @deprecated Use {@link Builder} instead.
*/
@Deprecated
public TaskDescription(String label, Bitmap icon, int colorPrimary) {
@@ -1333,7 +1445,8 @@ public class ActivityManager {
*
* @param label A label and description of the current state of this activity.
* @param icon An icon that represents the current state of this activity.
- * @deprecated use TaskDescription constructor with icon resource instead
+ *
+ * @deprecated Use {@link Builder} instead.
*/
@Deprecated
public TaskDescription(String label, Bitmap icon) {
@@ -1635,15 +1748,15 @@ public class ActivityManager {
/**
* @return The color override on the theme's primary color.
*/
+ @ColorInt
public int getPrimaryColor() {
return mColorPrimary;
}
/**
- * @return The background color.
- * @hide
+ * @return The color override on the theme's background color.
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @ColorInt
public int getBackgroundColor() {
return mColorBackground;
}
@@ -1657,15 +1770,17 @@ public class ActivityManager {
}
/**
- * @hide
+ * @return The color override on the theme's status bar color.
*/
+ @ColorInt
public int getStatusBarColor() {
return mStatusBarColor;
}
/**
- * @hide
+ * @return The color override on the theme's navigation bar color.
*/
+ @ColorInt
public int getNavigationBarColor() {
return mNavigationBarColor;
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f5eb1f6e24ed..ac46066997ff 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -77,6 +77,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
import android.system.ErrnoException;
import android.system.Os;
@@ -216,6 +217,12 @@ class ContextImpl extends Context {
@UnsupportedAppUsage
private @Nullable ClassLoader mClassLoader;
+ /**
+ * The {@link com.android.server.wm.WindowToken} representing this instance if it is
+ * {@link #CONTEXT_TYPE_WINDOW_CONTEXT} or {@link #CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI}.
+ * If the type is {@link #CONTEXT_TYPE_ACTIVITY}, then represents the
+ * {@link android.window.WindowContainerToken} of the activity.
+ */
private final @Nullable IBinder mToken;
private final @NonNull UserHandle mUser;
@@ -2180,8 +2187,9 @@ class ContextImpl extends Context {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- getSystemService(PermissionManager.class).revokeOwnPermissionsOnKill(permissions);
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+ getSystemService(PermissionControllerManager.class).revokeSelfPermissionsOnKill(
+ getPackageName(), new ArrayList<String>(permissions));
}
@Override
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 82ff42b41799..a763b1464b6d 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -465,7 +465,8 @@ public class Dialog implements DialogInterface, Window.Callback,
onBackPressed();
}
};
- getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mDefaultBackCallback);
mDefaultBackCallback = null;
}
}
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index 6f49c9e647a4..a138fa1f6fd5 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -191,7 +191,7 @@ public final class GameManager {
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
- public @GameMode boolean isAngleEnabled(@NonNull String packageName) {
+ public boolean isAngleEnabled(@NonNull String packageName) {
try {
return mService.isAngleEnabled(packageName, mContext.getUserId());
} catch (RemoteException e) {
diff --git a/core/java/android/app/ILocaleManager.aidl b/core/java/android/app/ILocaleManager.aidl
index 348cb2d30739..3002c8bb9c3e 100644
--- a/core/java/android/app/ILocaleManager.aidl
+++ b/core/java/android/app/ILocaleManager.aidl
@@ -40,4 +40,9 @@ import android.os.LocaleList;
*/
LocaleList getApplicationLocales(String packageName, int userId);
+ /**
+ * Returns the current system locales.
+ */
+ LocaleList getSystemLocales();
+
} \ No newline at end of file
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index cedf483eb076..e9c29b8aa0a5 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -1103,9 +1103,12 @@ public class KeyguardManager {
}
/**
- * Registers a listener to execute when the keyguard visibility changes.
+ * Registers a listener to execute when the keyguard locked state changes.
*
- * @param listener The listener to add to receive keyguard visibility changes.
+ * @param listener The listener to add to receive keyguard locked state changes.
+ *
+ * @see #isKeyguardLocked()
+ * @see #removeKeyguardLockedStateListener(KeyguardLockedStateListener)
*/
@RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
public void addKeyguardLockedStateListener(@NonNull @CallbackExecutor Executor executor,
@@ -1124,7 +1127,12 @@ public class KeyguardManager {
}
/**
- * Unregisters a listener that executes when the keyguard visibility changes.
+ * Unregisters a listener that executes when the keyguard locked state changes.
+ *
+ * @param listener The listener to remove.
+ *
+ * @see #isKeyguardLocked()
+ * @see #addKeyguardLockedStateListener(Executor, KeyguardLockedStateListener)
*/
@RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
public void removeKeyguardLockedStateListener(@NonNull KeyguardLockedStateListener listener) {
diff --git a/core/java/android/app/LocaleManager.java b/core/java/android/app/LocaleManager.java
index 522dc845f57c..efe9e35d4c64 100644
--- a/core/java/android/app/LocaleManager.java
+++ b/core/java/android/app/LocaleManager.java
@@ -18,7 +18,6 @@ package android.app;
import android.Manifest;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -127,31 +126,36 @@ public class LocaleManager {
}
/**
- * Sets the current system locales to the provided value.
+ * Returns the current system locales, ignoring app-specific overrides.
*
- * @hide
+ * <p><b>Note:</b> Apps should generally access the user's locale preferences as indicated in
+ * their in-process {@link LocaleList}s. However, in case an app-specific locale is set, this
+ * method helps cater to rare use-cases which might require specifically knowing the system
+ * locale.
+ *
+ * <p><b>Note:</b> This API is not user-aware. It returns the system locales for the foreground
+ * user.
*/
- @TestApi
- public void setSystemLocales(@NonNull LocaleList locales) {
+ @NonNull
+ public LocaleList getSystemLocales() {
try {
- Configuration conf = ActivityManager.getService().getConfiguration();
- conf.setLocales(locales);
- ActivityManager.getService().updatePersistentConfiguration(conf);
+ return mService.getSystemLocales();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Returns the current system locales for the device.
+ * Sets the current system locales to the provided value.
*
* @hide
*/
@TestApi
- @Nullable
- public LocaleList getSystemLocales() {
+ public void setSystemLocales(@NonNull LocaleList locales) {
try {
- return ActivityManager.getService().getConfiguration().getLocales();
+ Configuration conf = ActivityManager.getService().getConfiguration();
+ conf.setLocales(locales);
+ ActivityManager.getService().updatePersistentConfiguration(conf);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 89854bbab3e8..ae0fc09e35a6 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -24,6 +24,9 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -39,6 +42,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
import android.view.View;
@@ -520,6 +524,27 @@ public class StatusBarManager {
private final Map<NearbyMediaDevicesProvider, NearbyMediaDevicesProviderWrapper>
nearbyMediaDevicesProviderMap = new HashMap<>();
+ /**
+ * Media controls based on {@link android.app.Notification.MediaStyle} notifications will have
+ * actions based on the media session's {@link android.media.session.PlaybackState}, rather than
+ * the notification's actions.
+ *
+ * These actions will be:
+ * - Play/Pause (depending on whether the current state is a playing state)
+ * - Previous (if declared), or a custom action if the slot is not reserved with
+ * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV}
+ * - Next (if declared), or a custom action if the slot is not reserved with
+ * {@code SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT}
+ * - Custom action
+ * - Custom action
+ *
+ * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
+ * @see androidx.media.utils.MediaConstants#SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ private static final long MEDIA_CONTROL_SESSION_ACTIONS = 203800354L;
+
@UnsupportedAppUsage
private Context mContext;
private IStatusBarService mService;
@@ -1127,6 +1152,21 @@ public class StatusBarManager {
}
}
+ /**
+ * Checks whether the given package should use session-based actions for its media controls.
+ *
+ * @param packageName App posting media controls
+ * @param user Current user handle
+ * @return true if the app supports session actions
+ *
+ * @hide
+ */
+ @RequiresPermission(allOf = {android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ android.Manifest.permission.LOG_COMPAT_CHANGE})
+ public static boolean useMediaSessionActionsForApp(String packageName, UserHandle user) {
+ return CompatChanges.isChangeEnabled(MEDIA_CONTROL_SESSION_ACTIONS, packageName, user);
+ }
+
/** @hide */
public static String windowStateToString(int state) {
if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 32207af22dc1..649f90442536 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -146,15 +146,6 @@
}
],
"file_patterns": ["(/|^)ContextImpl.java"]
- },
- {
- "file_patterns": ["(/|^)LocaleManager.java"],
- "name": "CtsLocaleManagerTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
}
],
"presubmit-large": [
@@ -182,6 +173,16 @@
{
"file_patterns": ["(/|^)ActivityThreadTest.java"],
"name": "FrameworksCoreTests"
+ },
+ // TODO(b/225192026): Move back to presubmit after b/225192026 is fixed
+ {
+ "file_patterns": ["(/|^)LocaleManager.java"],
+ "name": "CtsLocaleManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7269b0d91d02..223e5da5bc6d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -21,6 +21,7 @@ import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.Manifest.permission;
+import android.accounts.Account;
import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
import android.annotation.IntDef;
@@ -1623,14 +1624,26 @@ public class DevicePolicyManager {
"android.app.extra.PROVISIONING_SKIP_EDUCATION_SCREENS";
/**
- * A boolean extra indicating if mobile data should be used during NFC device owner provisioning
- * for downloading the mobile device management application. If {@link
- * #EXTRA_PROVISIONING_WIFI_SSID} is also specified, wifi network will be used instead.
+ * A boolean extra indicating if mobile data should be used during the provisioning flow
+ * for downloading the admin app. If {@link #EXTRA_PROVISIONING_WIFI_SSID} is also specified,
+ * wifi network will be used instead.
*
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
- * provisioning via an NFC bump.
+ * <p>Default value is {@code false}.
*
- * @hide
+ * <p>If this extra is set to {@code true} and {@link #EXTRA_PROVISIONING_WIFI_SSID} is not
+ * specified, this extra has different behaviour depending on the way provisioning is triggered:
+ * <ul>
+ * <li>
+ * For provisioning started via a QR code or an NFC tag, mobile data is always used for
+ * downloading the admin app.
+ * </li>
+ * <li>
+ * For all other provisioning methods, a mobile data connection check is made at the start
+ * of provisioning. If mobile data is connected at that point, the admin app download will
+ * happen using mobile data. If mobile data is not connected at that point, the end-user
+ * will be asked to pick a wifi network and the admin app download will proceed over wifi.
+ * </li>
+ * </ul>
*/
public static final String EXTRA_PROVISIONING_USE_MOBILE_DATA =
"android.app.extra.PROVISIONING_USE_MOBILE_DATA";
@@ -3283,9 +3296,11 @@ public class DevicePolicyManager {
* <p>The activity must handle the device policy management role holder update and set the
* intent result to either {@link Activity#RESULT_OK} if the update was successful, {@link
* #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it encounters a
- * problem that may be solved by relaunching it again, or {@link
- * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters a
- * problem that will not be solved by relaunching it again.
+ * problem that may be solved by relaunching it again, {@link
+ * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED} if role holder
+ * provisioning is disabled, or {@link
+ * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters
+ * any other problem that will not be solved by relaunching it again.
*
* <p>If this activity has additional internal conditions which are not met, it should return
* {@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR}.
@@ -3321,6 +3336,45 @@ public class DevicePolicyManager {
2;
/**
+ * Result code that can be returned by the {@link
+ * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} handler if role holder provisioning
+ * is disabled.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int
+ RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_PROVISIONING_DISABLED = 3;
+
+ /**
+ * An {@code int} extra which contains the result code of the last attempt to update
+ * the device policy management role holder.
+ *
+ * <p>This extra is provided to the device policy management role holder via either {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} or {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_PROFILE} when started after the role holder
+ * had previously returned {@link #RESULT_UPDATE_ROLE_HOLDER}.
+ *
+ * <p>If the role holder update had failed, the role holder can use the value of this extra to
+ * make a decision whether to fail the provisioning flow or to carry on with the older version
+ * of the role holder.
+ *
+ * <p>Possible values can be:
+ * <ul>
+ * <li>{@link Activity#RESULT_OK} if the update was successful
+ * <li>{@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it
+ * encounters a problem that may be solved by relaunching it again.
+ * <li>{@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if
+ * it encounters a problem that will not be solved by relaunching it again.
+ * </ul>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_ROLE_HOLDER_UPDATE_RESULT_CODE =
+ "android.app.extra.ROLE_HOLDER_UPDATE_RESULT_CODE";
+
+ /**
* An {@link Intent} extra which resolves to a custom user consent screen.
*
* <p>If this extra is provided to the device policy management role holder via either {@link
@@ -3340,6 +3394,16 @@ public class DevicePolicyManager {
* <li>General disclaimer relevant to the provisioning mode</li>
* </ul>
*
+ * <p>When this {@link Intent} is started, the following intent extras will be supplied:
+ * <ul>
+ * <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}</li>
+ * <li>{@link #EXTRA_PROVISIONING_MODE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_LOCALE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_LOCAL_TIME}</li>
+ * <li>{@link #EXTRA_PROVISIONING_TIME_ZONE}</li>
+ * <li>{@link #EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS}</li>
+ * </ul>
+ *
* <p>If the custom consent screens are granted by the user {@link Activity#RESULT_OK} is
* returned, otherwise {@link Activity#RESULT_CANCELED} is returned. The device policy
* management role holder should ensure that the provisioning flow terminates immediately if
@@ -14009,12 +14073,12 @@ public class DevicePolicyManager {
/**
* Deprecated. Use {@code markProfileOwnerOnOrganizationOwnedDevice} instead.
* When called by an app targeting SDK level {@link android.os.Build.VERSION_CODES#Q} or
- * below, will behave the same as {@link #markProfileOwnerOnOrganizationOwnedDevice}.
+ * below, will behave the same as {@link #setProfileOwnerOnOrganizationOwnedDevice}.
*
* When called by an app targeting SDK level {@link android.os.Build.VERSION_CODES#R}
* or above, will throw an UnsupportedOperationException when called.
*
- * @deprecated Use {@link #markProfileOwnerOnOrganizationOwnedDevice} instead.
+ * @deprecated Use {@link #setProfileOwnerOnOrganizationOwnedDevice} instead.
*
* @hide
*/
@@ -14029,14 +14093,14 @@ public class DevicePolicyManager {
"This method is deprecated. use markProfileOwnerOnOrganizationOwnedDevice"
+ " instead.");
} else {
- markProfileOwnerOnOrganizationOwnedDevice(who);
+ setProfileOwnerOnOrganizationOwnedDevice(who, true);
}
}
/**
- * Marks the profile owner of the given user as managing an organization-owned device.
- * That will give it access to device identifiers (such as serial number, IMEI and MEID)
- * as well as other privileges.
+ * Sets whether the profile owner of the given user as managing an organization-owned device.
+ * Managing an organization-owned device will give it access to device identifiers (such as
+ * serial number, IMEI and MEID) as well as other privileges.
*
* @hide
*/
@@ -14044,13 +14108,15 @@ public class DevicePolicyManager {
@RequiresPermission(anyOf = {
android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED,
android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS
- }, conditional = true)
- public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who) {
+ }, conditional = true)
+ public void setProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who,
+ boolean isProfileOwnerOnOrganizationOwnedDevice) {
if (mService == null) {
return;
}
try {
- mService.markProfileOwnerOnOrganizationOwnedDevice(who, myUserId());
+ mService.setProfileOwnerOnOrganizationOwnedDevice(who, myUserId(),
+ isProfileOwnerOnOrganizationOwnedDevice);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -14800,6 +14866,28 @@ public class DevicePolicyManager {
}
/**
+ * Called when a managed profile has been provisioned.
+ *
+ * @throws SecurityException if the caller does not hold
+ * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public void finalizeWorkProfileProvisioning(
+ @NonNull UserHandle managedProfileUser, @Nullable Account migratedAccount) {
+ Objects.requireNonNull(managedProfileUser, "managedProfileUser can't be null");
+ if (mService == null) {
+ throw new IllegalStateException("Could not find DevicePolicyManagerService");
+ }
+ try {
+ mService.finalizeWorkProfileProvisioning(managedProfileUser, migratedAccount);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* The localized error message to show to the end-user. If {@code null}, a generic error
* message will be shown.
*/
@@ -15264,16 +15352,16 @@ public class DevicePolicyManager {
* <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
* registered receivers when a resource has been reset successfully.
*
- * @param drawableIds The list of IDs to remove.
+ * @param drawableIds The list of IDs to remove.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
- public void resetDrawables(@NonNull String[] drawableIds) {
+ public void resetDrawables(@NonNull Set<String> drawableIds) {
if (mService != null) {
try {
- mService.resetDrawables(drawableIds);
+ mService.resetDrawables(new ArrayList<>(drawableIds));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -15573,10 +15661,10 @@ public class DevicePolicyManager {
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
- public void resetStrings(@NonNull String[] stringIds) {
+ public void resetStrings(@NonNull Set<String> stringIds) {
if (mService != null) {
try {
- mService.resetStrings(stringIds);
+ mService.resetStrings(new ArrayList<>(stringIds));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -15586,7 +15674,7 @@ public class DevicePolicyManager {
/**
* Returns the appropriate updated string for the {@code stringId} (see
* {@link DevicePolicyResources.Strings}) if one was set using
- * {@link #setStrings}, otherwise returns the string from {@code defaultStringLoader}.
+ * {@code setStrings}, otherwise returns the string from {@code defaultStringLoader}.
*
* <p>Also returns the string from {@code defaultStringLoader} if
* {@link DevicePolicyResources.Strings#UNDEFINED} was passed.
@@ -15598,15 +15686,12 @@ public class DevicePolicyManager {
* notified when a resource has been updated.
*
* <p>Note that each call to this API loads the resource from the package that called
- * {@link #setStrings} to set the updated resource.
+ * {@code setStrings} to set the updated resource.
*
* @param stringId The IDs to get the updated resource for.
* @param defaultStringLoader To get the default string if no updated string was set for
* {@code stringId}.
- *
- * @hide
*/
- @SystemApi
@Nullable
public String getString(
@NonNull @DevicePolicyResources.UpdatableStringId String stringId,
@@ -15649,10 +15734,7 @@ public class DevicePolicyManager {
* @param defaultStringLoader To get the default string if no updated string was set for
* {@code stringId}.
* @param formatArgs The format arguments that will be used for substitution.
- *
- * @hide
*/
- @SystemApi
@Nullable
@SuppressLint("SamShouldBeLast")
public String getString(
@@ -15737,9 +15819,28 @@ public class DevicePolicyManager {
*/
@Nullable
public String getDevicePolicyManagementRoleHolderPackage() {
- String deviceManagerConfig = mContext.getString(
+ String devicePolicyManagementConfig = mContext.getString(
com.android.internal.R.string.config_devicePolicyManagement);
- return extractPackageNameFromDeviceManagerConfig(deviceManagerConfig);
+ return extractPackageNameFromDeviceManagerConfig(devicePolicyManagementConfig);
+ }
+
+ /**
+ * Returns the package name of the device policy management role holder updater.
+ *
+ * <p>If the device policy management role holder updater is not configured for this device,
+ * returns {@code null}.
+ *
+ * @hide
+ */
+ @Nullable
+ @TestApi
+ public String getDevicePolicyManagementRoleHolderUpdaterPackage() {
+ String devicePolicyManagementUpdaterConfig = mContext.getString(
+ com.android.internal.R.string.config_devicePolicyManagementUpdater);
+ if (TextUtils.isEmpty(devicePolicyManagementUpdaterConfig)) {
+ return null;
+ }
+ return devicePolicyManagementUpdaterConfig;
}
/**
diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
index 40ae1f0c11ea..7e951779d2a6 100644
--- a/core/java/android/app/admin/FactoryResetProtectionPolicy.java
+++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -254,4 +255,18 @@ public final class FactoryResetProtectionPolicy implements Parcelable {
return !mFactoryResetProtectionAccounts.isEmpty() && mFactoryResetProtectionEnabled;
}
+ /**
+ * @hide
+ */
+ public void dump(IndentingPrintWriter pw) {
+ pw.print("factoryResetProtectionEnabled=");
+ pw.println(mFactoryResetProtectionEnabled);
+
+ pw.print("factoryResetProtectionAccounts=");
+ pw.increaseIndent();
+ for (int i = 0; i < mFactoryResetProtectionAccounts.size(); i++) {
+ pw.println(mFactoryResetProtectionAccounts.get(i));
+ }
+ pw.decreaseIndent();
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index fb1ca41ccc56..64241aa3312f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -17,6 +17,7 @@
package android.app.admin;
+import android.accounts.Account;
import android.app.admin.DevicePolicyDrawableResource;
import android.app.admin.DevicePolicyStringResource;
import android.app.admin.ParcelableResource;
@@ -476,7 +477,7 @@ interface IDevicePolicyManager {
int getGlobalPrivateDnsMode(in ComponentName admin);
String getGlobalPrivateDnsHost(in ComponentName admin);
- void markProfileOwnerOnOrganizationOwnedDevice(in ComponentName who, int userId);
+ void setProfileOwnerOnOrganizationOwnedDevice(in ComponentName who, int userId, boolean isProfileOwnerOnOrganizationOwnedDevice);
void installUpdateFromFile(in ComponentName admin, in ParcelFileDescriptor updateFileDescriptor, in StartInstallingUpdateCallback listener);
@@ -528,6 +529,8 @@ interface IDevicePolicyManager {
UserHandle createAndProvisionManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage);
void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams, in String callerPackage);
+ void finalizeWorkProfileProvisioning(in UserHandle managedProfileUser, in Account migratedAccount);
+
void setDeviceOwnerType(in ComponentName admin, in int deviceOwnerType);
int getDeviceOwnerType(in ComponentName admin);
@@ -549,14 +552,14 @@ interface IDevicePolicyManager {
List<UserHandle> listForegroundAffiliatedUsers();
void setDrawables(in List<DevicePolicyDrawableResource> drawables);
- void resetDrawables(in String[] drawableIds);
+ void resetDrawables(in List<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);
+ void resetStrings(in List<String> stringIds);
ParcelableResource getString(String stringId);
boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
diff --git a/core/java/android/app/usage/BroadcastResponseStats.java b/core/java/android/app/usage/BroadcastResponseStats.java
index e1d37e1b1ae0..572c45355e42 100644
--- a/core/java/android/app/usage/BroadcastResponseStats.java
+++ b/core/java/android/app/usage/BroadcastResponseStats.java
@@ -29,6 +29,8 @@ import java.util.Objects;
* Class containing a collection of stats related to response events started from an app
* after receiving a broadcast.
*
+ * @see UsageStatsManager#queryBroadcastResponseStats(String, long)
+ * @see UsageStatsManager#clearBroadcastResponseStats(String, long)
* @hide
*/
@SystemApi
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 2a2a9c6e703e..7e142221b15d 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -82,4 +82,6 @@ interface IUsageStatsManager {
int userId);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
void clearBroadcastEvents(String callingPackage, int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG)")
+ String getAppStandbyConstant(String key);
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 3a335f9d151b..b88a51312cd1 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -16,6 +16,7 @@
package android.app.usage;
+import android.Manifest;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -1505,4 +1506,15 @@ public final class UsageStatsManager {
throw re.rethrowFromSystemServer();
}
}
+
+ /** @hide */
+ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
+ @Nullable
+ public String getAppStandbyConstant(@NonNull String key) {
+ try {
+ return mService.getAppStandbyConstant(key);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 60efb4d3ec81..24b1b6adb450 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6508,22 +6508,22 @@ public abstract class Context {
/**
- * Triggers the asynchronous revocation of a permission.
+ * Triggers the asynchronous revocation of a runtime permission. If the permission is not
+ * currently granted, nothing happens (even if later granted by the user).
*
* @param permName The name of the permission to be revoked.
- * @see #revokeOwnPermissionsOnKill(Collection)
+ * @see #revokeSelfPermissionsOnKill(Collection)
+ * @throws IllegalArgumentException if the permission is not a runtime permission
*/
- public void revokeOwnPermissionOnKill(@NonNull String permName) {
- revokeOwnPermissionsOnKill(Collections.singletonList(permName));
+ public void revokeSelfPermissionOnKill(@NonNull String permName) {
+ revokeSelfPermissionsOnKill(Collections.singletonList(permName));
}
/**
* Triggers the revocation of one or more permissions for the calling package. A package is only
- * able to revoke a permission under the following conditions:
- * <ul>
- * <li>Each permission in {@code permissions} must be granted to the calling package.
- * <li>Each permission in {@code permissions} must be a runtime permission.
- * </ul>
+ * able to revoke runtime permissions. If a permission is not currently granted, it is ignored
+ * and will not get revoked (even if later granted by the user). Ultimately, you should never
+ * make assumptions about a permission status as users may grant or revoke them at any time.
* <p>
* Background permissions which have no corresponding foreground permission still granted once
* the revocation is effective will also be revoked.
@@ -6549,8 +6549,9 @@ public abstract class Context {
* @param permissions Collection of permissions to be revoked.
* @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
* @see PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)
+ * @throws IllegalArgumentException if any of the permissions is not a runtime permission
*/
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -7145,8 +7146,9 @@ public abstract class Context {
}
/**
- * Returns token if the {@link Context} is a {@link android.app.WindowContext}. Returns
- * {@code null} otherwise.
+ * Returns the {@link IBinder} representing the associated
+ * {@link com.android.server.wm.WindowToken} if the {@link Context} is a
+ * {@link android.app.WindowContext}. Returns {@code null} otherwise.
*
* @hide
*/
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 9adf17367039..4ecd7761ac4f 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1036,8 +1036,8 @@ public class ContextWrapper extends Context {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- mBase.revokeOwnPermissionsOnKill(permissions);
+ public void revokeSelfPermissionsOnKill(@NonNull Collection<String> permissions) {
+ mBase.revokeSelfPermissionsOnKill(permissions);
}
@Override
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 478befd9c26d..2c207bc90444 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -8903,8 +8903,12 @@ public class Intent implements Parcelable, Cloneable {
* @return the value of an item previously added with putExtra(),
* or null if no Parcelable value was found.
*
+ * @deprecated Use the type-safer {@link #getParcelableExtra(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putExtra(String, Parcelable)
*/
+ @Deprecated
public @Nullable <T extends Parcelable> T getParcelableExtra(String name) {
return mExtras == null ? null : mExtras.<T>getParcelable(name);
}
@@ -8913,12 +8917,31 @@ public class Intent implements Parcelable, Cloneable {
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the object expected.
+ *
+ * @return the value of an item previously added with putExtra(),
+ * or null if no Parcelable value was found.
+ *
+ * @see #putExtra(String, Parcelable)
+ */
+ public @Nullable <T> T getParcelableExtra(@Nullable String name, @NonNull Class<T> clazz) {
+ return mExtras == null ? null : mExtras.getParcelable(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with putExtra(),
* or null if no Parcelable[] value was found.
*
+ * @deprecated Use the type-safer {@link #getParcelableArrayExtra(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putExtra(String, Parcelable[])
*/
+ @Deprecated
public @Nullable Parcelable[] getParcelableArrayExtra(String name) {
return mExtras == null ? null : mExtras.getParcelableArray(name);
}
@@ -8927,13 +8950,34 @@ public class Intent implements Parcelable, Cloneable {
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the items inside the array. This is only verified when unparceling.
+ *
+ * @return the value of an item previously added with putExtra(),
+ * or null if no Parcelable[] value was found.
+ *
+ * @see #putExtra(String, Parcelable[])
+ */
+ @SuppressLint({"ArrayReturn", "NullableCollection"})
+ public @Nullable <T> T[] getParcelableArrayExtra(@Nullable String name,
+ @NonNull Class<T> clazz) {
+ return mExtras == null ? null : mExtras.getParcelableArray(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with
* putParcelableArrayListExtra(), or null if no
* ArrayList<Parcelable> value was found.
*
+ * @deprecated Use the type-safer {@link #getParcelableArrayListExtra(String, Class)} starting
+ * from Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putParcelableArrayListExtra(String, ArrayList)
*/
+ @Deprecated
public @Nullable <T extends Parcelable> ArrayList<T> getParcelableArrayListExtra(String name) {
return mExtras == null ? null : mExtras.<T>getParcelableArrayList(name);
}
@@ -8942,10 +8986,32 @@ public class Intent implements Parcelable, Cloneable {
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the items inside the array list. This is only verified when
+ * unparceling.
+ *
+ * @return the value of an item previously added with
+ * putParcelableArrayListExtra(), or null if no
+ * ArrayList<Parcelable> value was found.
+ *
+ * @see #putParcelableArrayListExtra(String, ArrayList)
+ */
+ @SuppressLint({"ConcreteCollection", "NullableCollection"})
+ public @Nullable <T> ArrayList<T> getParcelableArrayListExtra(@Nullable String name,
+ @NonNull Class<? extends T> clazz) {
+ return mExtras == null ? null : mExtras.<T>getParcelableArrayList(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with putExtra(),
* or null if no Serializable value was found.
*
+ * @deprecated Use the type-safer {@link #getSerializableExtra(String, Class)} starting from
+ * Android {@link Build.VERSION_CODES#TIRAMISU}.
+ *
* @see #putExtra(String, Serializable)
*/
public @Nullable Serializable getSerializableExtra(String name) {
@@ -8956,6 +9022,22 @@ public class Intent implements Parcelable, Cloneable {
* Retrieve extended data from the intent.
*
* @param name The name of the desired item.
+ * @param clazz The type of the object expected.
+ *
+ * @return the value of an item previously added with putExtra(),
+ * or null if no Serializable value was found.
+ *
+ * @see #putExtra(String, Serializable)
+ */
+ public @Nullable <T extends Serializable> T getSerializableExtra(@Nullable String name,
+ @NonNull Class<T> clazz) {
+ return mExtras == null ? null : mExtras.getSerializable(name, clazz);
+ }
+
+ /**
+ * Retrieve extended data from the intent.
+ *
+ * @param name The name of the desired item.
*
* @return the value of an item previously added with
* putIntegerArrayListExtra(), or null if no
diff --git a/core/java/android/content/pm/AppSearchShortcutInfo.java b/core/java/android/content/pm/AppSearchShortcutInfo.java
index f20d1e62e8e7..1b84686bbfcf 100644
--- a/core/java/android/content/pm/AppSearchShortcutInfo.java
+++ b/core/java/android/content/pm/AppSearchShortcutInfo.java
@@ -349,7 +349,7 @@ public class AppSearchShortcutInfo extends GenericDocument {
.setDisabledReason(shortcutInfo.getDisabledReason())
.setPersons(shortcutInfo.getPersons())
.setLocusId(shortcutInfo.getLocusId())
- .setCapabilityBindings(shortcutInfo.getCapabilityBindings())
+ .setCapabilityBindings(shortcutInfo.getCapabilityBindingsInternal())
.setTtlMillis(SHORTCUT_TTL)
.build();
}
diff --git a/core/java/android/content/pm/Capability.aidl b/core/java/android/content/pm/Capability.aidl
new file mode 100644
index 000000000000..df3b1be1ce31
--- /dev/null
+++ b/core/java/android/content/pm/Capability.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm;
+
+parcelable Capability; \ No newline at end of file
diff --git a/core/java/android/content/pm/Capability.java b/core/java/android/content/pm/Capability.java
new file mode 100644
index 000000000000..1597d31828a1
--- /dev/null
+++ b/core/java/android/content/pm/Capability.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Represents a capability that can be performed by an app, also known as App Action.
+ * Capabilities can be associated with a {@link ShortcutInfo}.
+ *
+ * @see ShortcutInfo.Builder#addCapabilityBinding(Capability, CapabilityParams)
+ */
+public final class Capability implements Parcelable {
+
+ @NonNull
+ private final String mName;
+
+ /**
+ * Constructor.
+ * @param name Name of the capability, usually maps to a built-in intent,
+ * e.g. actions.intent.GET_MESSAGE. Note the character "/" is not permitted.
+ * @throws IllegalArgumentException If specified capability name contains the character "/".
+ *
+ * @hide
+ */
+ Capability(@NonNull final String name) {
+ Objects.requireNonNull(name);
+ if (name.contains("/")) {
+ throw new IllegalArgumentException("'/' is not permitted in the capability name");
+ }
+ mName = name;
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @hide
+ */
+ Capability(@NonNull final Capability orig) {
+ this(orig.mName);
+ }
+
+ private Capability(@NonNull final Builder builder) {
+ this(builder.mName);
+ }
+
+ private Capability(@NonNull final Parcel in) {
+ mName = in.readString();
+ }
+
+ /**
+ * Returns the name of the capability. e.g. actions.intent.GET_MESSAGE.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Capability)) {
+ return false;
+ }
+ return mName.equals(((Capability) obj).mName);
+ }
+
+ @Override
+ public int hashCode() {
+ return mName.hashCode();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mName);
+ }
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<Capability> CREATOR =
+ new Parcelable.Creator<Capability>() {
+ @Override
+ public Capability[] newArray(int size) {
+ return new Capability[size];
+ }
+
+ @Override
+ public Capability createFromParcel(@NonNull Parcel in) {
+ return new Capability(in);
+ }
+ };
+
+ /**
+ * Builder class for {@link Capability}.
+ */
+ public static final class Builder {
+
+ @NonNull
+ private final String mName;
+
+ /**
+ * Constructor.
+ * @param name Name of the capability, usually maps to a built-in intent,
+ * e.g. actions.intent.GET_MESSAGE. Note the character "/" is not permitted.
+ * @throws IllegalArgumentException If specified capability name contains the character "/".
+ */
+ public Builder(@NonNull final String name) {
+ Objects.requireNonNull(name);
+ if (name.contains("/")) {
+ throw new IllegalArgumentException("'/' is not permitted in the capability name");
+ }
+ mName = name;
+ }
+
+ /**
+ * Creates an instance of {@link Capability}
+ */
+ @NonNull
+ public Capability build() {
+ return new Capability(this);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/CapabilityParams.aidl b/core/java/android/content/pm/CapabilityParams.aidl
new file mode 100644
index 000000000000..39f12387404f
--- /dev/null
+++ b/core/java/android/content/pm/CapabilityParams.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm;
+
+parcelable CapabilityParams;
diff --git a/core/java/android/content/pm/CapabilityParams.java b/core/java/android/content/pm/CapabilityParams.java
new file mode 100644
index 000000000000..7239bacf1221
--- /dev/null
+++ b/core/java/android/content/pm/CapabilityParams.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Represents the parameters and its matching names which can be associated with a
+ * {@link Capability}.
+ *
+ * @see ShortcutInfo.Builder#addCapabilityBinding(Capability, CapabilityParams)
+ */
+public final class CapabilityParams implements Parcelable {
+
+ @NonNull
+ private final String mName;
+ @NonNull
+ private final String mPrimaryValue;
+ @NonNull
+ private final List<String> mAliases;
+
+ /**
+ * Constructor.
+ * @param name Name of the capability parameter.
+ * Note the character "/" is not permitted.
+ * @param primaryValue The primary value of the parameter.
+ * @param aliases Alternative values of the parameter.
+ */
+ private CapabilityParams(@NonNull final String name,
+ @NonNull final String primaryValue, @Nullable final Collection<String> aliases) {
+ Objects.requireNonNull(name);
+ Objects.requireNonNull(primaryValue);
+ mName = name;
+ mPrimaryValue = primaryValue;
+ mAliases = aliases == null ? Collections.emptyList()
+ : Collections.unmodifiableList(new ArrayList<>(aliases));
+ }
+
+ /**
+ * Copy constructor.
+ * @hide
+ */
+ CapabilityParams(@NonNull final CapabilityParams orig) {
+ this(orig.mName, orig.mPrimaryValue, orig.mAliases);
+ }
+
+ private CapabilityParams(@NonNull final Builder builder) {
+ this(builder.mKey, builder.mPrimaryValue, builder.mAliases);
+ }
+
+ private CapabilityParams(@NonNull final Parcel in) {
+ mName = in.readString();
+ mPrimaryValue = in.readString();
+ final List<String> values = new ArrayList<>();
+ in.readStringList(values);
+ mAliases = Collections.unmodifiableList(values);
+ }
+
+ /**
+ * Name of the parameter.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the primary name of values in this parameter.
+ */
+ @NonNull
+ public String getValue() {
+ return mPrimaryValue;
+ }
+
+ /**
+ * Returns the aliases of the values in ths parameter. Returns an empty list if there are no
+ * aliases.
+ */
+ @NonNull
+ public List<String> getAliases() {
+ return new ArrayList<>(mAliases);
+ }
+
+ /**
+ * A list of values for this parameter. The first value will be the primary name, while the
+ * rest will be alternative names.
+ * @hide
+ */
+ @NonNull
+ List<String> getValues() {
+ if (mAliases == null) {
+ return new ArrayList<>(Collections.singletonList(mPrimaryValue));
+ }
+ final List<String> ret = new ArrayList<>(mAliases.size() + 1);
+ ret.add(mPrimaryValue);
+ ret.addAll(mAliases);
+ return ret;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof CapabilityParams)) {
+ return false;
+ }
+ final CapabilityParams target = (CapabilityParams) obj;
+ return mName.equals(target.mName) && mPrimaryValue.equals(target.mPrimaryValue)
+ && mAliases.equals(target.mAliases);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mPrimaryValue, mAliases);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(mName);
+ dest.writeString(mPrimaryValue);
+ dest.writeStringList(mAliases);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<CapabilityParams> CREATOR =
+ new Parcelable.Creator<CapabilityParams>() {
+ @Override
+ public CapabilityParams[] newArray(int size) {
+ return new CapabilityParams[size];
+ }
+
+ @Override
+ public CapabilityParams createFromParcel(@NonNull Parcel in) {
+ return new CapabilityParams(in);
+ }
+ };
+
+ /**
+ * Builder class for {@link CapabilityParams}.
+ */
+ public static final class Builder {
+
+ @NonNull
+ private final String mKey;
+ @NonNull
+ private String mPrimaryValue;
+ @NonNull
+ private Set<String> mAliases;
+
+ /**
+ * Constructor.
+ * @param key key of the capability parameter.
+ * Note the character "/" is not permitted.
+ * @param value The primary name of value in the {@link CapabilityParams}, cannot be empty.
+ */
+ public Builder(@NonNull final String key, @NonNull final String value) {
+ Objects.requireNonNull(key);
+ if (TextUtils.isEmpty(value)) {
+ throw new IllegalArgumentException("Primary value cannot be empty or null");
+ }
+ mPrimaryValue = value;
+ mKey = key;
+ }
+
+ /**
+ * Add an alias in the {@link CapabilityParams}.
+ */
+ @NonNull
+ public Builder addAlias(@NonNull final String alias) {
+ if (mAliases == null) {
+ mAliases = new ArraySet<>(1);
+ }
+ mAliases.add(alias);
+ return this;
+ }
+
+ /**
+ * Creates an instance of {@link CapabilityParams}
+ * @throws IllegalArgumentException If the specified value is empty.
+ */
+ @NonNull
+ public CapabilityParams build() {
+ return new CapabilityParams(this);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index eefa63f5b8fa..f4de82946253 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -213,7 +213,8 @@ public class PackageInfo implements Parcelable {
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PERMISSIONS} was set. Each value matches
* the corresponding entry in {@link #requestedPermissions}, and will have
- * the flag {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate.
+ * the flags {@link #REQUESTED_PERMISSION_GRANTED} and
+ * {@link #REQUESTED_PERMISSION_NEVER_FOR_LOCATION} set as appropriate.
*/
public int[] requestedPermissionsFlags;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 81c941eedef0..c91ee1395687 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4087,6 +4087,28 @@ public abstract class PackageManager {
"android.software.incremental_delivery";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * has the requisite kernel support for the EROFS filesystem present in 4.19 kernels as a
+ * staging driver, which lacks 0padding and big pcluster support.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_EROFS_LEGACY = "android.software.erofs_legacy";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
+ * has the requisite kernel support for the EROFS filesystem present in 5.10 kernels, which
+ * has 0padding, big pcluster, and chunked index support.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_EROFS = "android.software.erofs";
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device has tuner hardware to support tuner operations.
*
diff --git a/core/java/android/content/pm/SHORTCUT_OWNERS b/core/java/android/content/pm/SHORTCUT_OWNERS
index 3688d5a3a4c7..f8bba473336d 100644
--- a/core/java/android/content/pm/SHORTCUT_OWNERS
+++ b/core/java/android/content/pm/SHORTCUT_OWNERS
@@ -1,7 +1,6 @@
set noparent
+pinyaoting@google.com
+sunnygoyal@google.com
omakoto@google.com
yamasani@google.com
-sunnygoyal@google.com
-mett@google.com
-pinyaoting@google.com
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 41dd5bb3f21d..56d092d8319d 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -52,7 +52,7 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Collection;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -60,7 +60,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* Represents a shortcut that can be published via {@link ShortcutManager}.
@@ -501,7 +500,8 @@ public final class ShortcutInfo implements Parcelable {
mRank = b.mRank;
mExtras = b.mExtras;
mLocusId = b.mLocusId;
- mCapabilityBindings = b.mCapabilityBindings;
+ mCapabilityBindings =
+ cloneCapabilityBindings(b.mCapabilityBindings);
mStartingThemeResName = b.mStartingThemeResId != 0
? b.mContext.getResources().getResourceName(b.mStartingThemeResId) : null;
updateTimestamp();
@@ -652,7 +652,8 @@ public final class ShortcutInfo implements Parcelable {
// Set this bit.
mFlags |= FLAG_KEY_FIELDS_ONLY;
}
- mCapabilityBindings = source.mCapabilityBindings;
+ mCapabilityBindings = cloneCapabilityBindings(
+ source.mCapabilityBindings);
mStartingThemeResName = source.mStartingThemeResName;
}
@@ -1003,7 +1004,8 @@ public final class ShortcutInfo implements Parcelable {
mStartingThemeResName = source.mStartingThemeResName;
}
if (source.mCapabilityBindings != null) {
- mCapabilityBindings = source.mCapabilityBindings;
+ mCapabilityBindings =
+ cloneCapabilityBindings(source.mCapabilityBindings);
}
}
@@ -1447,43 +1449,25 @@ public final class ShortcutInfo implements Parcelable {
* <P>This method can be called multiple times to add multiple parameters to the same
* capability.
*
- * @param capability capability associated with the shortcut. e.g. actions.intent
- * .START_EXERCISE.
- * @param parameterName name of the parameter associated with given capability.
- * e.g. exercise.name.
- * @param parameterValues a list of values for that parameters. The first value will be
- * the primary name, while the rest will be alternative names. If
- * the values are empty, then the parameter will not be saved in
- * the shortcut.
+ * @param capability {@link Capability} associated with the shortcut.
+ * @param capabilityParams Optional {@link CapabilityParams} associated with given
+ * capability.
*/
@NonNull
- public Builder addCapabilityBinding(@NonNull String capability,
- @Nullable String parameterName, @Nullable List<String> parameterValues) {
+ public Builder addCapabilityBinding(@NonNull final Capability capability,
+ @Nullable final CapabilityParams capabilityParams) {
Objects.requireNonNull(capability);
- if (capability.contains("/")) {
- throw new IllegalArgumentException("Illegal character '/' is found in capability");
- }
if (mCapabilityBindings == null) {
mCapabilityBindings = new ArrayMap<>(1);
}
- if (!mCapabilityBindings.containsKey(capability)) {
- mCapabilityBindings.put(capability, new ArrayMap<>(0));
- }
- if (parameterName == null || parameterValues == null || parameterValues.isEmpty()) {
- return this;
- }
- if (parameterName.contains("/")) {
- throw new IllegalArgumentException(
- "Illegal character '/' is found in parameter name");
+ if (!mCapabilityBindings.containsKey(capability.getName())) {
+ mCapabilityBindings.put(capability.getName(), new ArrayMap<>(0));
}
- final Map<String, List<String>> params = mCapabilityBindings.get(capability);
- if (!params.containsKey(parameterName)) {
- params.put(parameterName, parameterValues);
+ if (capabilityParams == null) {
return this;
}
- params.put(parameterName,
- Stream.of(params.get(parameterName), parameterValues)
- .flatMap(Collection::stream).collect(Collectors.toList()));
+ final Map<String, List<String>> params = mCapabilityBindings.get(capability.getName());
+ params.put(capabilityParams.getName(), capabilityParams.getValues());
return this;
}
@@ -2264,41 +2248,78 @@ public final class ShortcutInfo implements Parcelable {
}
/**
+ * Returns an immutable copy of the capability bindings using internal data structure.
* @hide
*/
- public Map<String, Map<String, List<String>>> getCapabilityBindings() {
- return mCapabilityBindings;
+ @Nullable
+ public Map<String, Map<String, List<String>>> getCapabilityBindingsInternal() {
+ return cloneCapabilityBindings(mCapabilityBindings);
+ }
+
+ @Nullable
+ private static Map<String, Map<String, List<String>>> cloneCapabilityBindings(
+ @Nullable final Map<String, Map<String, List<String>>> orig) {
+ if (orig == null) {
+ return null;
+ }
+ final Map<String, Map<String, List<String>>> ret = new ArrayMap<>();
+ for (String capability : orig.keySet()) {
+ final Map<String, List<String>> params = orig.get(capability);
+ final Map<String, List<String>> clone;
+ if (params == null) {
+ clone = null;
+ } else {
+ clone = new ArrayMap<>(params.size());
+ for (String paramName : params.keySet()) {
+ final List<String> paramValues = params.get(paramName);
+ clone.put(paramName, Collections.unmodifiableList(paramValues));
+ }
+ }
+ ret.put(capability, Collections.unmodifiableMap(clone));
+ }
+ return Collections.unmodifiableMap(ret);
}
/**
- * Return true if the shortcut is or can be used in specified capability.
+ * Return a list of {@link Capability} associated with the shortcut.
*/
- public boolean hasCapability(@NonNull String capability) {
- Objects.requireNonNull(capability);
- return mCapabilityBindings != null && mCapabilityBindings.containsKey(capability);
+ @NonNull
+ public List<Capability> getCapabilities() {
+ if (mCapabilityBindings == null) {
+ return new ArrayList<>(0);
+ }
+ return mCapabilityBindings.keySet().stream().map(Capability::new)
+ .collect(Collectors.toList());
}
/**
- * Returns the values of specified parameter in associated with given capability.
+ * Returns the {@link CapabilityParams} in associated with given capability.
*
- * @param capability capability associated with the shortcut. e.g. actions.intent
- * .START_EXERCISE.
- * @param parameterName name of the parameter associated with given capability.
- * e.g. exercise.name.
+ * @param capability {@link Capability} associated with the shortcut.
*/
@NonNull
- public List<String> getCapabilityParameterValues(
- @NonNull String capability, @NonNull String parameterName) {
+ public List<CapabilityParams> getCapabilityParams(@NonNull final Capability capability) {
Objects.requireNonNull(capability);
- Objects.requireNonNull(parameterName);
if (mCapabilityBindings == null) {
- return Collections.emptyList();
- }
- final Map<String, List<String>> param = mCapabilityBindings.get(capability);
- if (param == null || !param.containsKey(parameterName)) {
- return Collections.emptyList();
+ return new ArrayList<>(0);
+ }
+ final Map<String, List<String>> param = mCapabilityBindings.get(capability.getName());
+ if (param == null) {
+ return new ArrayList<>(0);
+ }
+ final List<CapabilityParams> ret = new ArrayList<>(param.size());
+ for (String key : param.keySet()) {
+ final List<String> values = param.get(key);
+ final String primaryValue = values.get(0);
+ final List<String> aliases = values.size() == 1
+ ? Collections.emptyList() : values.subList(1, values.size());
+ CapabilityParams.Builder builder = new CapabilityParams.Builder(key, primaryValue);
+ for (String alias : aliases) {
+ builder = builder.addAlias(alias);
+ }
+ ret.add(builder.build());
}
- return param.get(parameterName);
+ return ret;
}
private ShortcutInfo(Parcel source) {
@@ -2357,7 +2378,7 @@ public final class ShortcutInfo implements Parcelable {
final Map<String, Map<String, List<String>>> capabilityBindings =
new ArrayMap<>(rawCapabilityBindings.size());
rawCapabilityBindings.forEach(capabilityBindings::put);
- mCapabilityBindings = capabilityBindings;
+ mCapabilityBindings = cloneCapabilityBindings(capabilityBindings);
}
}
@@ -2695,6 +2716,6 @@ public final class ShortcutInfo implements Parcelable {
mPersons = persons;
mLocusId = locusId;
mStartingThemeResName = startingThemeResName;
- mCapabilityBindings = capabilityBindings;
+ mCapabilityBindings = cloneCapabilityBindings(capabilityBindings);
}
}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index a05f5c927b29..c8bbb0c1994d 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -79,6 +79,13 @@ public final class AssetManager implements AutoCloseable {
@GuardedBy("sSync") private static ArraySet<ApkAssets> sSystemApkAssetsSet;
/**
+ * Cookie value to use when the actual cookie is unknown. This value tells the system to search
+ * all the ApkAssets for the asset.
+ * @hide
+ */
+ public static final int COOKIE_UNKNOWN = -1;
+
+ /**
* Mode for {@link #open(String, int)}: no specific information about how
* data will be accessed.
*/
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7e070bc06056..29221b801ef6 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -923,14 +923,15 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
if (mService == null) {
Slog.w(TAG, "onFingerDown: no fingerprint service");
return;
}
try {
- mService.onPointerDown(sensorId, x, y, minor, major);
+ mService.onPointerDown(requestId, sensorId, x, y, minor, major);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -940,14 +941,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
if (mService == null) {
Slog.w(TAG, "onFingerDown: no fingerprint service");
return;
}
try {
- mService.onPointerUp(sensorId);
+ mService.onPointerUp(requestId, sensorId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -957,14 +958,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onUiReady(int sensorId) {
+ public void onUiReady(long requestId, int sensorId) {
if (mService == null) {
Slog.w(TAG, "onUiReady: no fingerprint service");
return;
}
try {
- mService.onUiReady(sensorId);
+ mService.onUiReady(requestId, sensorId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index cbff8b11a72a..12114aa3fa33 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -155,13 +155,13 @@ interface IFingerprintService {
void addAuthenticatorsRegisteredCallback(IFingerprintAuthenticatorsRegisteredCallback callback);
// Notifies about a finger touching the sensor area.
- void onPointerDown(int sensorId, int x, int y, float minor, float major);
+ void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major);
// Notifies about a finger leaving the sensor area.
- void onPointerUp(int sensorId);
+ void onPointerUp(long requestId, int sensorId);
// Notifies about the fingerprint UI being ready (e.g. HBM illumination is enabled).
- void onUiReady(int sensorId);
+ void onUiReady(long requestId, int sensorId);
// Sets the controller for managing the UDFPS overlay.
void setUdfpsOverlayController(in IUdfpsOverlayController controller);
diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
index 3cca1b38e5e2..dbb8e40f3a71 100644
--- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
+++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
@@ -23,7 +23,7 @@ import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
*/
oneway interface IUdfpsOverlayController {
// Shows the overlay for the given sensor with a reason from BiometricOverlayConstants.
- void showUdfpsOverlay(int sensorId, int reason, IUdfpsOverlayControllerCallback callback);
+ void showUdfpsOverlay(long requestId, int sensorId, int reason, IUdfpsOverlayControllerCallback callback);
// Hides the overlay.
void hideUdfpsOverlay(int sensorId);
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 0f9075b498ae..03d11515c0a8 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -294,8 +294,8 @@ final class NavigationBarController {
dest.setTouchableInsets(
ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- // TODO(b/205803355): See if we can use View#OnLayoutChangeListener().
- // TODO(b/205803355): See if we can replace DecorView#mNavigationColorViewState.view
+ // TODO(b/215443343): See if we can use View#OnLayoutChangeListener().
+ // TODO(b/215443343): See if we can replace DecorView#mNavigationColorViewState.view
boolean zOrderChanged = false;
if (decor instanceof ViewGroup) {
ViewGroup decorGroup = (ViewGroup) decor;
diff --git a/core/java/android/inputmethodservice/navigationbar/DeadZone.java b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
index 4cfd8139d912..382b6b074962 100644
--- a/core/java/android/inputmethodservice/navigationbar/DeadZone.java
+++ b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
@@ -148,7 +148,7 @@ final class DeadZone {
if (DEBUG) {
Log.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
}
- //TODO(b/205803355): call mNavBarController.touchAutoDim(mDisplayId); here
+ //TODO(b/215443343): call mNavBarController.touchAutoDim(mDisplayId); here
int size = (int) getSize(event.getEventTime());
// In the vertical orientation consume taps along the left edge.
// In horizontal orientation consume taps along the top edge.
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
index cfdb6caab9d3..92d358fe1663 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
@@ -89,7 +89,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
public KeyButtonView(Context context, AttributeSet attrs) {
super(context, attrs);
- // TODO(b/205803355): Figure out better place to set this.
+ // TODO(b/215443343): Figure out better place to set this.
switch (getId()) {
case com.android.internal.R.id.input_method_nav_back:
mCode = KEYCODE_BACK;
@@ -285,11 +285,11 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
private void sendEvent(int action, int flags, long when) {
if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
if (action == MotionEvent.ACTION_UP) {
- // TODO(b/205803355): Implement notifyBackAction();
+ // TODO(b/215443343): Implement notifyBackAction();
}
}
- // TODO(b/205803355): Consolidate this logic to somewhere else.
+ // TODO(b/215443343): Consolidate this logic to somewhere else.
if (mContext instanceof InputMethodService) {
final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index 0eb4cf3ecadf..b05f7cf241e3 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -60,7 +60,7 @@ public class SntpClient {
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;
- private static final int NTP_PORT = 123;
+ public static final int STANDARD_NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_MODE_SERVER = 4;
private static final int NTP_MODE_BROADCAST = 5;
@@ -108,18 +108,21 @@ public class SntpClient {
* Sends an SNTP request to the given host and processes the response.
*
* @param host host name of the server.
+ * @param port port of the server.
* @param timeout network timeout in milliseconds. the timeout doesn't include the DNS lookup
* time, and it applies to each individual query to the resolved addresses of
* the NTP server.
* @param network network over which to send the request.
* @return true if the transaction was successful.
*/
- public boolean requestTime(String host, int timeout, Network network) {
+ public boolean requestTime(String host, int port, int timeout, Network network) {
final Network networkForResolv = network.getPrivateDnsBypassingCopy();
try {
final InetAddress[] addresses = networkForResolv.getAllByName(host);
for (int i = 0; i < addresses.length; i++) {
- if (requestTime(addresses[i], NTP_PORT, timeout, networkForResolv)) return true;
+ if (requestTime(addresses[i], port, timeout, networkForResolv)) {
+ return true;
+ }
}
} catch (UnknownHostException e) {
Log.w(TAG, "Unknown host: " + host);
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index c021c079ae2e..a0f6598640ba 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -125,7 +125,6 @@ interface IStorageManager {
boolean isUserKeyUnlocked(int userId) = 65;
void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66;
void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67;
- boolean isConvertibleToFBE() = 68;
void addUserKeyAuth(int userId, int serialNumber, in byte[] secret) = 70;
void fixateNewestUserKeyAuth(int userId) = 71;
void fstrim(int flags, IVoldTaskListener listener) = 72;
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index c9dd06cfaa43..e3f02e73a41f 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -59,6 +59,6 @@ oneway interface IPermissionController {
void getHibernationEligibility(
in String packageName,
in AndroidFuture callback);
- void revokeOwnPermissionsOnKill(in String packageName, in List<String> permissions,
+ void revokeSelfPermissionsOnKill(in String packageName, in List<String> permissions,
in AndroidFuture callback);
}
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 619c8705ddae..6a93b354f4da 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -76,8 +76,6 @@ interface IPermissionManager {
List<SplitPermissionInfoParcelable> getSplitPermissions();
- void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
-
void startOneTimePermissionSession(String packageName, int userId, long timeout,
long revokeAfterKilledDelay, int importanceToResetTimer,
int importanceToKeepSessionAlive);
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index a005ab4e6ac7..3c2c7f03761b 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -916,15 +916,15 @@ public final class PermissionControllerManager {
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
*
- * @see Context#revokeOwnPermissionsOnKill(java.util.Collection)
+ * @see Context#revokeSelfPermissionsOnKill(java.util.Collection)
*
* @hide
*/
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void revokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions) {
mRemoteService.postAsync(service -> {
AndroidFuture<Void> callback = new AndroidFuture<>();
- service.revokeOwnPermissionsOnKill(packageName, permissions, callback);
+ service.revokeSelfPermissionsOnKill(packageName, permissions, callback);
return callback;
}).whenComplete((result, err) -> {
if (err != null) {
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 3292e7110ee5..4efffc5a11ef 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -40,6 +40,7 @@ import android.compat.annotation.Disabled;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -339,10 +340,10 @@ public abstract class PermissionControllerService extends Service {
* @param permissions List of permissions to be revoked.
* @param callback Callback waiting for operation to be complete.
*
- * @see PermissionManager#revokeOwnPermissionsOnKill(java.util.Collection)
+ * @see android.content.Context#revokeSelfPermissionsOnKill(java.util.Collection)
*/
@BinderThread
- public void onRevokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void onRevokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull Runnable callback) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -703,13 +704,19 @@ public abstract class PermissionControllerService extends Service {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
+ public void revokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull AndroidFuture callback) {
try {
- enforceSomePermissionsGrantedToCaller(
- Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
Objects.requireNonNull(callback);
- onRevokeOwnPermissionsOnKill(packageName, permissions,
+
+ final int callingUid = Binder.getCallingUid();
+ int targetPackageUid = getPackageManager().getPackageUid(packageName,
+ PackageManager.PackageInfoFlags.of(0));
+ if (targetPackageUid != callingUid) {
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+ }
+ onRevokeSelfPermissionsOnKill(packageName, permissions,
() -> callback.complete(null));
} catch (Throwable t) {
callback.completeExceptionally(t);
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index c509de6bb5e1..7a797ce28870 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -76,7 +76,6 @@ import com.android.internal.annotations.Immutable;
import com.android.internal.util.CollectionUtils;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -626,19 +625,6 @@ public final class PermissionManager {
}
/**
- * @see Context#revokeOwnPermissionsOnKill(Collection)
- * @hide
- */
- public void revokeOwnPermissionsOnKill(@NonNull Collection<String> permissions) {
- try {
- mPermissionManager.revokeOwnPermissionsOnKill(mContext.getPackageName(),
- new ArrayList<String>(permissions));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Gets the state flags associated with a permission.
*
* @param packageName the package name for which to get the flags
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 0b57842cde11..4ed939c48bd7 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -47,6 +47,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.icu.text.ListFormatter;
+import android.location.LocationManager;
import android.media.AudioManager;
import android.os.Process;
import android.os.UserHandle;
@@ -411,10 +412,13 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
}
/**
- * Returns true if the app supports subattribution.
+ * Returns true if the app satisfies subattribution policies and supports it
*/
private boolean isSubattributionSupported(String packageName, int uid) {
try {
+ if (!isLocationProvider(packageName)) {
+ return false;
+ }
PackageManager userPkgManager =
getUserContext(UserHandle.getUserHandleForUid(uid)).getPackageManager();
ApplicationInfo appInfo = userPkgManager.getApplicationInfoAsUser(packageName,
@@ -430,6 +434,15 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
}
/**
+ * @param packageName
+ * @return If the package is location provider
+ */
+ private boolean isLocationProvider(String packageName) {
+ return Objects.requireNonNull(
+ mContext.getSystemService(LocationManager.class)).isProviderPackage(packageName);
+ }
+
+ /**
* Get the raw usages from the system, and then parse out the ones that are not recent enough,
* determine which permission group each belongs in, and removes duplicates (if the same app
* uses multiple permissions of the same group). Stores the package name, attribution tag, user,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a6ad5e5863df..5191c9583379 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2143,10 +2143,10 @@ public final class Settings {
/**
* Intent extra: The id of a setting restricted by supervisors.
* <p>
- * Type: Integer with a value from the SupervisorVerificationSetting annotation below.
+ * Type: Integer with a value from the one of the SUPERVISOR_VERIFICATION_* constants below.
* <ul>
- * <li>{@link #SUPERVISOR_VERIFICATION_SETTING_UNKNOWN}
- * <li>{@link #SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS}
+ * <li>{@see #SUPERVISOR_VERIFICATION_SETTING_UNKNOWN}
+ * <li>{@see #SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS}
* </ul>
* </p>
*/
@@ -2154,12 +2154,14 @@ public final class Settings {
"android.provider.extra.SUPERVISOR_RESTRICTED_SETTING_KEY";
/**
- * Unknown setting.
+ * The unknown setting can usually be ignored and is used for compatibility with future
+ * supervisor settings.
*/
public static final int SUPERVISOR_VERIFICATION_SETTING_UNKNOWN = 0;
/**
- * Biometric settings for supervisors.
+ * Settings for supervisors to control what kinds of biometric sensors, such a face and
+ * fingerprint scanners, can be used on the device.
*/
public static final int SUPERVISOR_VERIFICATION_SETTING_BIOMETRICS = 1;
diff --git a/core/java/android/service/displayhash/DisplayHashingService.java b/core/java/android/service/displayhash/DisplayHashingService.java
index f22d40ea4d5e..3fac23b61a4b 100644
--- a/core/java/android/service/displayhash/DisplayHashingService.java
+++ b/core/java/android/service/displayhash/DisplayHashingService.java
@@ -68,9 +68,6 @@ public abstract class DisplayHashingService extends Service {
private DisplayHashingServiceWrapper mWrapper;
private Handler mHandler;
- public DisplayHashingService() {
- }
-
@Override
public void onCreate() {
super.onCreate();
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index bec5d1be57fd..bc42da6b4c97 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -851,7 +851,8 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
public void triggerHardwareRecognitionEventForTest(int status, int soundModelHandle,
boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs,
- boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data) {
+ boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data,
+ @NonNull List<KeyphraseRecognitionExtra> keyphraseRecognitionExtras) {
Log.d(TAG, "triggerHardwareRecognitionEventForTest()");
synchronized (mLock) {
if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
@@ -862,7 +863,8 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
mModelManagementService.triggerHardwareRecognitionEventForTest(
new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable,
captureSession, captureDelayMs, capturePreambleMs, triggerInData,
- captureFormat, data, null /* keyphraseExtras */),
+ captureFormat, data, keyphraseRecognitionExtras.toArray(
+ new KeyphraseRecognitionExtra[0])),
mInternalCallback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index aebc5e86605a..01a037ae3495 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -140,6 +140,10 @@ public class NtpTrustedTime implements TrustedTime {
/** An in-memory config override for use during tests. */
@Nullable
+ private Integer mPortForTests;
+
+ /** An in-memory config override for use during tests. */
+ @Nullable
private Duration mTimeoutForTests;
// Declared volatile and accessed outside of synchronized blocks to avoid blocking reads during
@@ -163,9 +167,11 @@ public class NtpTrustedTime implements TrustedTime {
* Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
* test value, i.e. so the normal value will be used next time.
*/
- public void setServerConfigForTests(@Nullable String hostname, @Nullable Duration timeout) {
+ public void setServerConfigForTests(
+ @Nullable String hostname, @Nullable Integer port, @Nullable Duration timeout) {
synchronized (this) {
mHostnameForTests = hostname;
+ mPortForTests = port;
mTimeoutForTests = timeout;
}
}
@@ -195,8 +201,9 @@ public class NtpTrustedTime implements TrustedTime {
if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
final SntpClient client = new SntpClient();
final String serverName = connectionInfo.getServer();
+ final int port = connectionInfo.getPort();
final int timeoutMillis = connectionInfo.getTimeoutMillis();
- if (client.requestTime(serverName, timeoutMillis, network)) {
+ if (client.requestTime(serverName, port, timeoutMillis, network)) {
long ntpCertainty = client.getRoundTripTime() / 2;
mTimeResult = new TimeResult(
client.getNtpTime(), client.getNtpTimeReference(), ntpCertainty);
@@ -297,10 +304,12 @@ public class NtpTrustedTime implements TrustedTime {
private static class NtpConnectionInfo {
@NonNull private final String mServer;
+ private final int mPort;
private final int mTimeoutMillis;
- NtpConnectionInfo(@NonNull String server, int timeoutMillis) {
+ NtpConnectionInfo(@NonNull String server, int port, int timeoutMillis) {
mServer = Objects.requireNonNull(server);
+ mPort = port;
mTimeoutMillis = timeoutMillis;
}
@@ -309,6 +318,11 @@ public class NtpTrustedTime implements TrustedTime {
return mServer;
}
+ @NonNull
+ public int getPort() {
+ return mPort;
+ }
+
int getTimeoutMillis() {
return mTimeoutMillis;
}
@@ -317,6 +331,7 @@ public class NtpTrustedTime implements TrustedTime {
public String toString() {
return "NtpConnectionInfo{"
+ "mServer='" + mServer + '\''
+ + ", mPort='" + mPort + '\''
+ ", mTimeoutMillis=" + mTimeoutMillis
+ '}';
}
@@ -341,6 +356,13 @@ public class NtpTrustedTime implements TrustedTime {
}
}
+ final Integer port;
+ if (mPortForTests != null) {
+ port = mPortForTests;
+ } else {
+ port = SntpClient.STANDARD_NTP_PORT;
+ }
+
final int timeoutMillis;
if (mTimeoutForTests != null) {
timeoutMillis = (int) mTimeoutForTests.toMillis();
@@ -350,7 +372,8 @@ public class NtpTrustedTime implements TrustedTime {
timeoutMillis = Settings.Global.getInt(
resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis);
}
- return TextUtils.isEmpty(hostname) ? null : new NtpConnectionInfo(hostname, timeoutMillis);
+ return TextUtils.isEmpty(hostname) ? null :
+ new NtpConnectionInfo(hostname, port, timeoutMillis);
}
/** Prints debug information. */
diff --git a/core/java/android/util/TimingsTraceLog.java b/core/java/android/util/TimingsTraceLog.java
index 066709fd8744..48a5ceae1aef 100644
--- a/core/java/android/util/TimingsTraceLog.java
+++ b/core/java/android/util/TimingsTraceLog.java
@@ -147,7 +147,7 @@ public class TimingsTraceLog {
* Logs a duration so it can be parsed by external tools for performance reporting.
*/
public void logDuration(String name, long timeMs) {
- Slog.d(mTag, name + " took to complete: " + timeMs + "ms");
+ Slog.v(mTag, name + " took to complete: " + timeMs + "ms");
}
/**
diff --git a/core/java/android/view/ContentRecordingSession.java b/core/java/android/view/ContentRecordingSession.java
index db4ec1155e64..c66c70af0656 100644
--- a/core/java/android/view/ContentRecordingSession.java
+++ b/core/java/android/view/ContentRecordingSession.java
@@ -66,10 +66,11 @@ public final class ContentRecordingSession implements Parcelable {
private int mContentToRecord = RECORD_CONTENT_DISPLAY;
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@VisibleForTesting
@Nullable
@@ -192,10 +193,11 @@ public final class ContentRecordingSession implements Parcelable {
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @VisibleForTesting @Nullable IBinder getTokenToRecord() {
@@ -231,10 +233,11 @@ public final class ContentRecordingSession implements Parcelable {
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @NonNull ContentRecordingSession setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -390,10 +393,11 @@ public final class ContentRecordingSession implements Parcelable {
}
/**
- * The window token of the layer of the hierarchy to record.
- * The display content if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_DISPLAY}, or task if {@link #getContentToRecord()} is
- * {@link RecordContent#RECORD_CONTENT_TASK}.
+ * {The token of the layer of the hierarchy to record.
+ * If {@link #getContentToRecord()} is @link RecordContent#RECORD_CONTENT_DISPLAY}, then
+ * represents the WindowToken corresponding to the DisplayContent to record.
+ * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
+ * represents the {@link android.window.WindowContainerToken} of the Task to record.
*/
@DataClass.Generated.Member
public @NonNull Builder setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
@@ -433,7 +437,7 @@ public final class ContentRecordingSession implements Parcelable {
}
@DataClass.Generated(
- time = 1644843382972L,
+ time = 1645803878639L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java",
inputSignatures = "public static final int RECORD_CONTENT_DISPLAY\npublic static final int RECORD_CONTENT_TASK\nprivate int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @com.android.internal.annotations.VisibleForTesting @android.annotation.Nullable android.os.IBinder mTokenToRecord\npublic static android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static boolean isValid(android.view.ContentRecordingSession)\npublic static boolean isSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)")
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 190adbdfd5db..61098d60566f 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -55,10 +55,10 @@ public class HandwritingInitiator {
*/
private final int mTouchSlop;
/**
- * The timeout used to distinguish tap from handwriting. If the stylus doesn't move before this
- * timeout, it's not considered as handwriting.
+ * The timeout used to distinguish tap or long click from handwriting. If the stylus doesn't
+ * move before this timeout, it's not considered as handwriting.
*/
- private final long mTapTimeoutInMillis;
+ private final long mHandwritingTimeoutInMillis;
private State mState = new State();
private final HandwritingAreaTracker mHandwritingAreasTracker = new HandwritingAreaTracker();
@@ -90,7 +90,7 @@ public class HandwritingInitiator {
public HandwritingInitiator(@NonNull ViewConfiguration viewConfiguration,
@NonNull InputMethodManager inputMethodManager) {
mTouchSlop = viewConfiguration.getScaledTouchSlop();
- mTapTimeoutInMillis = ViewConfiguration.getTapTimeout();
+ mHandwritingTimeoutInMillis = ViewConfiguration.getLongPressTimeout();
mImm = inputMethodManager;
}
@@ -145,7 +145,7 @@ public class HandwritingInitiator {
final long timeElapsed =
motionEvent.getEventTime() - mState.mStylusDownTimeInMillis;
- if (timeElapsed > mTapTimeoutInMillis) {
+ if (timeElapsed > mHandwritingTimeoutInMillis) {
reset();
return;
}
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index a13579d0acad..406281d4cade 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -401,7 +401,7 @@ public class SurfaceControlViewHost {
public void relayout(WindowManager.LayoutParams attrs,
WindowlessWindowManager.ResizeCompleteCallback callback) {
mViewRoot.setLayoutParams(attrs, false);
- mViewRoot.setReportNextDraw();
+ mViewRoot.setReportNextDraw(true /* syncBuffer */);
mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback);
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 413855639d09..22ccaae9e3c3 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -50,6 +50,7 @@ import android.view.accessibility.IAccessibilityEmbeddedConnection;
import com.android.internal.view.SurfaceCallbackHelper;
import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
@@ -203,8 +204,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private int mSurfaceFlags = SurfaceControl.HIDDEN;
- private int mPendingReportDraws;
-
/**
* Transaction that should be used from the render thread. This transaction is only thread safe
* with other calls directly from the render thread.
@@ -212,11 +211,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private final SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
/**
- * Used on the main thread to set the transaction that will be synced with the main window.
- */
- private final Transaction mSyncTransaction = new Transaction();
-
- /**
* Transaction that should be used whe
* {@link HardwareRenderer.FrameDrawingCallback#onFrameDraw} is invoked. All
* frame callbacks can use the same transaction since they will be thread safe
@@ -391,31 +385,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
}
- private void performDrawFinished(@Nullable Transaction t) {
- if (t != null) {
- mSyncTransaction.merge(t);
- }
-
- if (mPendingReportDraws > 0) {
- mDrawFinished = true;
- if (mAttachedToWindow) {
- mParent.requestTransparentRegion(SurfaceView.this);
- notifyDrawFinished();
- invalidate();
- }
- } else {
- Log.e(TAG, System.identityHashCode(this) + "finished drawing"
- + " but no pending report draw (extra call"
- + " to draw completion runnable?)");
- }
- }
-
- void notifyDrawFinished() {
- ViewRootImpl viewRoot = getViewRootImpl();
- if (viewRoot != null) {
- viewRoot.pendingDrawFinished(mSyncTransaction);
+ private void performDrawFinished() {
+ mDrawFinished = true;
+ if (mAttachedToWindow) {
+ mParent.requestTransparentRegion(SurfaceView.this);
+ invalidate();
}
- mPendingReportDraws--;
}
@Override
@@ -438,10 +413,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mGlobalListenersAdded = false;
}
- while (mPendingReportDraws > 0) {
- notifyDrawFinished();
- }
-
mRequestedVisible = false;
updateSurface();
@@ -993,10 +964,17 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
return;
}
- final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
- translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction);
final boolean redrawNeeded = sizeChanged || creating || hintChanged
|| (mVisible && !mDrawFinished);
+ final TransactionCallback transactionCallback =
+ redrawNeeded ? new TransactionCallback() : null;
+ if (redrawNeeded && viewRoot.wasRelayoutRequested()) {
+ mBlastBufferQueue.syncNextTransaction(
+ false /* acquireSingleBuffer */,
+ transactionCallback::onTransactionReady);
+ }
+ final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
+ translator, creating, sizeChanged, hintChanged, surfaceUpdateTransaction);
try {
SurfaceHolder.Callback[] callbacks = null;
@@ -1015,9 +993,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mIsCreating = true;
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "visibleChanged -- surfaceCreated");
- if (callbacks == null) {
- callbacks = getSurfaceCallbacks();
- }
+ callbacks = getSurfaceCallbacks();
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceCreated(mSurfaceHolder);
}
@@ -1035,32 +1011,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
}
if (redrawNeeded) {
- if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
- + "surfaceRedrawNeeded");
- if (callbacks == null) {
- callbacks = getSurfaceCallbacks();
- }
-
- final boolean wasRelayoutRequested = viewRoot.wasRelayoutRequested();
- if (wasRelayoutRequested && (mBlastBufferQueue != null)) {
- mBlastBufferQueue.syncNextTransaction(
- false /* acquireSingleBuffer */,
- this::onDrawFinished);
- }
- mPendingReportDraws++;
- viewRoot.drawPending();
- SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() -> {
- if (mBlastBufferQueue != null) {
- mBlastBufferQueue.stopContinuousSyncTransaction();
- }
- // If relayout was requested, then a callback from BBQ will
- // be invoked with the sync transaction. onDrawFinished will be
- // called in there
- if (!wasRelayoutRequested) {
- onDrawFinished(null);
- }
- });
- sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
+ redrawNeeded(callbacks, transactionCallback);
}
}
} finally {
@@ -1079,6 +1030,64 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
}
+ private void redrawNeeded(SurfaceHolder.Callback[] callbacks,
+ @Nullable TransactionCallback transactionCallback) {
+ if (DEBUG) {
+ Log.i(TAG, System.identityHashCode(this) + " surfaceRedrawNeeded");
+ }
+ final SurfaceHolder.Callback[] capturedCallbacks =
+ callbacks == null ? getSurfaceCallbacks() : callbacks;
+
+ ViewRootImpl viewRoot = getViewRootImpl();
+ boolean isVriSync = viewRoot.addToSync(syncBufferCallback ->
+ redrawNeededAsync(capturedCallbacks, () -> {
+ if (mBlastBufferQueue != null) {
+ mBlastBufferQueue.stopContinuousSyncTransaction();
+ }
+
+ Transaction t = null;
+ if (transactionCallback != null && mBlastBufferQueue != null) {
+ t = transactionCallback.waitForTransaction();
+ }
+ // If relayout was requested, then a callback from BBQ will
+ // be invoked with the sync transaction. onDrawFinished will be
+ // called in there
+ syncBufferCallback.onBufferReady(t);
+ onDrawFinished();
+ }));
+
+ // If isVriSync, then everything was setup in the addToSync.
+ if (isVriSync) {
+ return;
+ }
+
+ redrawNeededAsync(capturedCallbacks, this::onDrawFinished);
+ }
+
+ private void redrawNeededAsync(SurfaceHolder.Callback[] callbacks,
+ Runnable callbacksCollected) {
+ SurfaceCallbackHelper sch = new SurfaceCallbackHelper(callbacksCollected);
+ sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
+ }
+
+ private static class TransactionCallback {
+ private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+ private Transaction mTransaction;
+
+ Transaction waitForTransaction() {
+ try {
+ mCountDownLatch.await();
+ } catch (InterruptedException e) {
+ }
+ return mTransaction;
+ }
+
+ void onTransactionReady(Transaction t) {
+ mTransaction = t;
+ mCountDownLatch.countDown();
+ }
+ }
+
/**
* Copy the Surface from the SurfaceControl or the blast adapter.
*
@@ -1189,13 +1198,13 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat);
}
- private void onDrawFinished(@Nullable Transaction t) {
+ private void onDrawFinished() {
if (DEBUG) {
Log.i(TAG, System.identityHashCode(this) + " "
+ "finishedDrawing");
}
- runOnUiThread(() -> performDrawFinished(t));
+ runOnUiThread(this::performDrawFinished);
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b72725ad2c32..17887d3447be 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -583,11 +583,15 @@ public final class ViewRootImpl implements ViewParent,
boolean mReportNextDraw;
+
/**
- * Set whether the draw should use blast sync. This is in case the draw is canceled,
- * but will be rescheduled. We still want the next draw to be sync.
+ * Set whether the draw should send the buffer to system server. When set to true, VRI will
+ * create a sync transaction with BBQ and send the resulting buffer to system server. If false,
+ * VRI will not try to sync a buffer in BBQ, but still report when a draw occurred.
+ *
+ * Default is true since we normally want to sync the buffer.
*/
- boolean mNextDrawUseBlastSync;
+ private boolean mSyncBuffer = true;
boolean mFullRedrawNeeded;
boolean mNewSurfaceNeeded;
@@ -808,6 +812,10 @@ public final class ViewRootImpl implements ViewParent,
return mHandwritingInitiator;
}
+ private final SurfaceSyncer mSurfaceSyncer = new SurfaceSyncer();
+ private int mLastSyncId = -1;
+ private SurfaceSyncer.SyncBufferCallback mSyncBufferCallback;
+
/**
* Keeps track of the last frame number that was attempted to draw. Should only be accessed on
* the RenderThread.
@@ -2880,8 +2888,6 @@ public final class ViewRootImpl implements ViewParent,
mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance);
}
}
- final boolean wasReportNextDraw = mReportNextDraw;
- boolean useBlastSync = mNextDrawUseBlastSync;
if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
|| mForceNextWindowRelayout) {
@@ -2923,9 +2929,6 @@ public final class ViewRootImpl implements ViewParent,
Log.d(mTag, "Relayout called with blastSync");
}
reportNextDraw();
- if (isHardwareEnabled()) {
- useBlastSync = true;
- }
}
final boolean surfaceControlChanged =
@@ -3164,7 +3167,7 @@ public final class ViewRootImpl implements ViewParent,
// done to achieve a more hermetic fix for S, but it's entirely
// possible that checking the most recent value is actually more
// correct here.
- if (!mStopped || wasReportNextDraw) {
+ if (!mStopped || mReportNextDraw) {
if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
|| dispatchApplyInsets || updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
@@ -3233,7 +3236,7 @@ public final class ViewRootImpl implements ViewParent,
prepareSurfaces();
}
- final boolean didLayout = layoutRequested && (!mStopped || wasReportNextDraw);
+ final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
@@ -3426,51 +3429,40 @@ public final class ViewRootImpl implements ViewParent,
mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);
- // Remember if we must report the next draw.
- if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
+ // If we already got a request for blast sync, then we don't want to unset mSyncBuffer
+ if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0
+ && !mReportNextDraw) {
reportNextDraw();
+ mSyncBuffer = false;
}
- boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
- if (mBLASTDrawConsumer != null) {
- useBlastSync = true;
+ boolean cancelAndRedraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
+ if (!cancelAndRedraw) {
+ createSyncIfNeeded();
}
- if (!cancelDraw) {
+ if (!isViewVisible) {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
- mPendingTransitions.get(i).startChangingAnimations();
+ mPendingTransitions.get(i).endChangingAnimations();
}
mPendingTransitions.clear();
}
- performDraw(useBlastSync);
- mNextDrawUseBlastSync = false;
- } else {
- if (isViewVisible) {
- // Try again
- mNextDrawUseBlastSync = useBlastSync;
- scheduleTraversals();
- } else {
- if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
- for (int i = 0; i < mPendingTransitions.size(); ++i) {
- mPendingTransitions.get(i).endChangingAnimations();
- }
- mPendingTransitions.clear();
- }
- // We may never draw since it's not visible. Report back that we're finished
- // drawing.
- if (!wasReportNextDraw && mReportNextDraw) {
- mReportNextDraw = false;
- pendingDrawFinished();
- }
-
- // Make sure the consumer is not waiting if the view root was just made invisible.
- if (mBLASTDrawConsumer != null) {
- mBLASTDrawConsumer.accept(null);
- mBLASTDrawConsumer = null;
+ if (mSyncBufferCallback != null) {
+ mSyncBufferCallback.onBufferReady(null);
+ }
+ } else if (cancelAndRedraw) {
+ // Try again
+ scheduleTraversals();
+ } else {
+ if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
+ for (int i = 0; i < mPendingTransitions.size(); ++i) {
+ mPendingTransitions.get(i).startChangingAnimations();
}
+ mPendingTransitions.clear();
}
+ performDraw();
}
if (mAttachInfo.mContentCaptureEvents != null) {
@@ -3479,6 +3471,46 @@ public final class ViewRootImpl implements ViewParent,
mIsInTraversal = false;
mRelayoutRequested = false;
+
+ if (!cancelAndRedraw) {
+ mReportNextDraw = false;
+ mSyncBufferCallback = null;
+ mSyncBuffer = true;
+ if (mLastSyncId != -1) {
+ mSurfaceSyncer.markSyncReady(mLastSyncId);
+ mLastSyncId = -1;
+ }
+ }
+ }
+
+ private void createSyncIfNeeded() {
+ // Started a sync already.
+ if (mLastSyncId != -1) {
+ return;
+ }
+
+ Consumer<Transaction> syncConsumer = null;
+ if (mBLASTDrawConsumer != null) {
+ syncConsumer = mBLASTDrawConsumer;
+ mBLASTDrawConsumer = null;
+ } else if (mReportNextDraw) {
+ syncConsumer = transaction -> {
+ mSurfaceChangedTransaction.merge(transaction);
+ reportDrawFinished();
+ };
+ }
+
+ if (syncConsumer != null) {
+ final Consumer<Transaction> capturedSyncConsumer = syncConsumer;
+ mLastSyncId = mSurfaceSyncer.setupSync(transaction -> {
+ // Callback will be invoked on executor thread so post to main thread.
+ mHandler.postAtFrontOfQueue(() -> capturedSyncConsumer.accept(transaction));
+ });
+ if (DEBUG_BLAST) {
+ Log.d(mTag, "Setup new sync id=" + mLastSyncId);
+ }
+ mSurfaceSyncer.addToSync(mLastSyncId, mSyncTarget);
+ }
}
private void notifyContentCatpureEvents() {
@@ -4092,54 +4124,10 @@ public final class ViewRootImpl implements ViewParent,
}
}
- /**
- * A count of the number of calls to pendingDrawFinished we
- * require to notify the WM drawing is complete.
- */
- int mDrawsNeededToReport = 0;
-
- /**
- * Delay notifying WM of draw finished until
- * a balanced call to pendingDrawFinished.
- */
- void drawPending() {
- mDrawsNeededToReport++;
- }
-
- void pendingDrawFinished(Transaction t) {
- if (mDrawsNeededToReport == 0) {
- throw new RuntimeException("Unbalanced drawPending/pendingDrawFinished calls");
- }
-
- if (t != null) {
- if (DEBUG_BLAST) {
- Log.d(mTag, "Merging transaction into main window transaction");
- }
- mSurfaceChangedTransaction.merge(t);
- }
-
- mDrawsNeededToReport--;
- if (mDrawsNeededToReport == 0) {
- reportDrawFinished();
- } else if (DEBUG_BLAST) {
- Log.d(mTag, "pendingDrawFinished. Waiting on draw reported mDrawsNeededToReport="
- + mDrawsNeededToReport);
- }
- }
-
- void pendingDrawFinished() {
- pendingDrawFinished(null);
- }
-
- private void postDrawFinished() {
- mHandler.sendEmptyMessage(MSG_DRAW_FINISHED);
- }
-
private void reportDrawFinished() {
if (DEBUG_BLAST) {
- Log.d(mTag, "reportDrawFinished");
+ Log.d(mTag, "reportDrawFinished " + Debug.getCallers(5));
}
- mDrawsNeededToReport = 0;
try {
mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, Integer.MAX_VALUE);
@@ -4158,6 +4146,14 @@ public final class ViewRootImpl implements ViewParent,
return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled();
}
+ boolean addToSync(SurfaceSyncer.SyncTarget syncable) {
+ if (mLastSyncId == -1) {
+ return false;
+ }
+ mSurfaceSyncer.addToSync(mLastSyncId, syncable);
+ return true;
+ }
+
private void addFrameCommitCallbackIfNeeded() {
if (!isHardwareEnabled()) {
return;
@@ -4188,188 +4184,81 @@ public final class ViewRootImpl implements ViewParent,
});
}
- private HardwareRenderer.FrameCommitCallback createFrameCommitCallbackForSync(
- boolean useBlastSync, boolean reportNextDraw, Consumer<Transaction> blastSyncConsumer) {
- return didProduceBuffer -> {
- if (DEBUG_BLAST) {
- Log.d(mTag, "Received frameCommittedCallback "
- + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum
- + " didProduceBuffer=" + didProduceBuffer);
- }
-
- // If frame wasn't drawn, clear out the next transaction so it doesn't affect the next
- // draw attempt. The next transaction and transaction complete callback were only set
- // for the current draw attempt.
- final Transaction pendingTransactions;
- if (!didProduceBuffer) {
- mBlastBufferQueue.syncNextTransaction(null);
- // Get the transactions that were sent to mergeWithNextTransaction since the
- // frame didn't draw on this vsync. It's possible the frame will draw later, but
- // it's better to not be sync than to block on a frame that may never come.
- pendingTransactions = mBlastBufferQueue.gatherPendingTransactions(
- mRtLastAttemptedDrawFrameNum);
- if (!useBlastSync && !reportNextDraw) {
- pendingTransactions.apply();
- }
- } else {
- pendingTransactions = null;
- }
- // Post at front of queue so the buffer can be processed immediately and allow RT
- // to continue processing new buffers. If RT tries to process buffers before the sync
- // buffer is applied, the new buffers will not get acquired and could result in a
- // deadlock. UI thread would wait on RT, but RT would be blocked waiting for a free
- // buffer.
- mHandler.postAtFrontOfQueue(() -> {
- if (!didProduceBuffer && useBlastSync) {
- mSurfaceChangedTransaction.merge(pendingTransactions);
- if (blastSyncConsumer != null) {
- blastSyncConsumer.accept(mSurfaceChangedTransaction);
- }
- }
-
- // This is to ensure pendingDrawFinished is only called exactly one time per draw
- // attempt when reportNextDraw is true. Since, we sometimes create a sync
- // transaction callback, the callback will handle calling pendingDrawFinished.
- // However, there are cases where the transaction callback may not be called.
- // 1. If useBlastSync is false, then we know that a sync transaction callback was
- // not created so we won't invoke pendingDrawFinished there.
- // 2. If the draw didn't produce a frame, didProduceBuffer == false, then we know
- // the sync transaction callback will not be invoked even if one was set up.
- if (reportNextDraw && (!didProduceBuffer || !useBlastSync)) {
- pendingDrawFinished();
- }
- });
-
- };
- }
-
@Nullable
- private FrameDrawingCallback createFrameDrawingCallbackIfNeeded(boolean useBlastSync,
- boolean reportNextDraw) {
+ private void registerFrameDrawingCallbackForBlur() {
if (!isHardwareEnabled()) {
- return null;
+ return;
}
final boolean hasBlurUpdates = mBlurRegionAggregator.hasUpdates();
final boolean needsCallbackForBlur = hasBlurUpdates || mBlurRegionAggregator.hasRegions();
- if (!useBlastSync && !needsCallbackForBlur && !reportNextDraw && !mHasPendingTransactions) {
- return null;
- }
-
- final Consumer<SurfaceControl.Transaction> blastSyncConsumer = mBLASTDrawConsumer;
- mBLASTDrawConsumer = null;
-
- if (DEBUG_BLAST) {
- Log.d(mTag, "Creating frameDrawingCallback"
- + " nextDrawUseBlastSync=" + useBlastSync
- + " reportNextDraw=" + reportNextDraw
- + " hasBlurUpdates=" + hasBlurUpdates
- + " hasBlastSyncConsumer=" + (blastSyncConsumer != null)
- + " mHasPendingTransactions=" + mHasPendingTransactions);
+ if (!needsCallbackForBlur) {
+ return;
}
final BackgroundBlurDrawable.BlurRegion[] blurRegionsForFrame =
- needsCallbackForBlur ? mBlurRegionAggregator.getBlurRegionsCopyForRT() : null;
- final boolean hasPendingTransactions = mHasPendingTransactions;
- mHasPendingTransactions = false;
-
+ mBlurRegionAggregator.getBlurRegionsCopyForRT();
// The callback will run on the render thread.
- return new FrameDrawingCallback() {
- @Override
- public void onFrameDraw(long frame) {
- }
+ registerRtFrameCallback((frame) -> mBlurRegionAggregator
+ .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates));
+ }
+ private void registerCallbackForPendingTransactions() {
+ registerRtFrameCallback(new FrameDrawingCallback() {
@Override
public HardwareRenderer.FrameCommitCallback onFrameDraw(int syncResult, long frame) {
- if (DEBUG_BLAST) {
- Log.d(mTag,
- "Received frameDrawingCallback syncResult=" + syncResult + " frameNum="
- + frame + ".");
- }
-
- mRtLastAttemptedDrawFrameNum = frame;
-
- if (needsCallbackForBlur) {
- mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame,
- blurRegionsForFrame, hasBlurUpdates);
- }
-
- if (mBlastBufferQueue == null) {
- return null;
- }
-
- if (!useBlastSync && !reportNextDraw && !hasPendingTransactions) {
- return null;
- }
-
- // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
- // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
- // any blast sync or commit callback, and the code should directly call
- // pendingDrawFinished.
if ((syncResult
& (SYNC_LOST_SURFACE_REWARD_IF_FOUND | SYNC_CONTEXT_IS_STOPPED)) != 0) {
- if (reportNextDraw) {
- mHandler.postAtFrontOfQueue(() -> pendingDrawFinished());
- }
+ mBlastBufferQueue.applyPendingTransactions(frame);
return null;
}
- if (DEBUG_BLAST) {
- Log.d(mTag, "Setting up sync and frameCommitCallback");
- }
-
- if (useBlastSync) {
- // Frame callbacks will always occur after submitting draw requests and before
- // the draw actually occurs. This will ensure that we set the next transaction
- // for the frame that's about to get drawn and not on a previous frame.
- mBlastBufferQueue.syncNextTransaction(
- t -> {
- mHandler.postAtFrontOfQueue(() -> {
- mSurfaceChangedTransaction.merge(t);
- if (blastSyncConsumer != null) {
- blastSyncConsumer.accept(mSurfaceChangedTransaction);
- }
+ return didProduceBuffer -> {
+ if (!didProduceBuffer) {
+ mBlastBufferQueue.applyPendingTransactions(frame);
+ }
+ };
- if (reportNextDraw) {
- pendingDrawFinished();
- }
- });
- });
- }
+ }
- return createFrameCommitCallbackForSync(useBlastSync, reportNextDraw,
- blastSyncConsumer);
+ @Override
+ public void onFrameDraw(long frame) {
}
- };
+ });
}
- private void performDraw(boolean useBlastSync) {
+ private void performDraw() {
if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
return;
} else if (mView == null) {
return;
}
- final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw || useBlastSync;
+ final boolean fullRedrawNeeded = mFullRedrawNeeded || mSyncBufferCallback != null;
mFullRedrawNeeded = false;
mIsDrawing = true;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
- FrameDrawingCallback frameDrawingCallback = createFrameDrawingCallbackIfNeeded(useBlastSync,
- mReportNextDraw);
- if (frameDrawingCallback != null) {
- mAttachInfo.mThreadedRenderer.registerRtFrameCallback(frameDrawingCallback);
- }
+ registerFrameDrawingCallbackForBlur();
addFrameCommitCallbackIfNeeded();
- boolean usingAsyncReport = isHardwareEnabled() && (useBlastSync || mReportNextDraw);
+
+ boolean usingAsyncReport = isHardwareEnabled() && mSyncBufferCallback != null;
+ if (usingAsyncReport) {
+ registerCallbacksForSync(mSyncBuffer, mSyncBufferCallback);
+ } else if (mHasPendingTransactions) {
+ // These callbacks are only needed if there's no sync involved and there were calls to
+ // applyTransactionOnDraw. These callbacks check if the draw failed for any reason and
+ // apply those transactions directly so they don't get stuck forever.
+ registerCallbackForPendingTransactions();
+ }
+ mHasPendingTransactions = false;
try {
boolean canUseAsync = draw(fullRedrawNeeded);
if (usingAsyncReport && !canUseAsync) {
mAttachInfo.mThreadedRenderer.setFrameCallback(null);
usingAsyncReport = false;
- mAttachInfo.mThreadedRenderer.unregisterRtFrameCallback(frameDrawingCallback);
}
} finally {
mIsDrawing = false;
@@ -4387,7 +4276,6 @@ public final class ViewRootImpl implements ViewParent,
}
if (mReportNextDraw) {
- mReportNextDraw = false;
// if we're using multi-thread renderer, wait for the window frame draws
if (mWindowDrawCountDown != null) {
@@ -4408,7 +4296,11 @@ public final class ViewRootImpl implements ViewParent,
}
if (mSurfaceHolder != null && mSurface.isValid()) {
- SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::postDrawFinished);
+ final SurfaceSyncer.SyncBufferCallback syncBufferCallback = mSyncBufferCallback;
+ SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() ->
+ mHandler.post(() -> syncBufferCallback.onBufferReady(null)));
+ mSyncBufferCallback = null;
+
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
@@ -4416,9 +4308,11 @@ public final class ViewRootImpl implements ViewParent,
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mThreadedRenderer.fence();
}
- pendingDrawFinished();
}
}
+ if (mSyncBufferCallback != null && !usingAsyncReport) {
+ mSyncBufferCallback.onBufferReady(null);
+ }
if (mPerformContentCapture) {
performContentCaptureInitialReport();
}
@@ -5427,7 +5321,6 @@ public final class ViewRootImpl implements ViewParent,
private static final int MSG_REQUEST_KEYBOARD_SHORTCUTS = 26;
private static final int MSG_UPDATE_POINTER_ICON = 27;
private static final int MSG_POINTER_CAPTURE_CHANGED = 28;
- private static final int MSG_DRAW_FINISHED = 29;
private static final int MSG_INSETS_CHANGED = 30;
private static final int MSG_INSETS_CONTROL_CHANGED = 31;
private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 32;
@@ -5490,8 +5383,6 @@ public final class ViewRootImpl implements ViewParent,
return "MSG_UPDATE_POINTER_ICON";
case MSG_POINTER_CAPTURE_CHANGED:
return "MSG_POINTER_CAPTURE_CHANGED";
- case MSG_DRAW_FINISHED:
- return "MSG_DRAW_FINISHED";
case MSG_INSETS_CHANGED:
return "MSG_INSETS_CHANGED";
case MSG_INSETS_CONTROL_CHANGED:
@@ -5724,9 +5615,6 @@ public final class ViewRootImpl implements ViewParent,
final boolean hasCapture = msg.arg1 != 0;
handlePointerCaptureChanged(hasCapture);
} break;
- case MSG_DRAW_FINISHED: {
- pendingDrawFinished();
- } break;
case MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED: {
systemGestureExclusionChanged();
} break;
@@ -9908,8 +9796,8 @@ public final class ViewRootImpl implements ViewParent,
}
private void reportNextDraw() {
- if (mReportNextDraw == false) {
- drawPending();
+ if (DEBUG_BLAST) {
+ Log.d(mTag, "reportNextDraw " + Debug.getCallers(5));
}
mReportNextDraw = true;
}
@@ -9920,9 +9808,14 @@ public final class ViewRootImpl implements ViewParent,
* This method is only supposed to be used to speed up the interaction from SystemUI and window
* manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
* unless you fully understand this interaction.
+ *
+ * @param syncBuffer If true, the transaction that contains the buffer from the draw should be
+ * sent to system to be synced. If false, VRI will not try to sync the buffer,
+ * but only report back that a buffer was drawn.
* @hide
*/
- public void setReportNextDraw() {
+ public void setReportNextDraw(boolean syncBuffer) {
+ mSyncBuffer = syncBuffer;
reportNextDraw();
invalidate();
}
@@ -10923,7 +10816,7 @@ public final class ViewRootImpl implements ViewParent,
}
};
mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
- mCompatOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatOnBackInvokedCallback);
}
private void unregisterCompatOnBackInvokedCallback() {
@@ -10948,14 +10841,15 @@ public final class ViewRootImpl implements ViewParent,
return mWindowSession;
}
- private void registerCallbacksForSync(
+ private void registerCallbacksForSync(boolean syncBuffer,
final SurfaceSyncer.SyncBufferCallback syncBufferCallback) {
if (!isHardwareEnabled()) {
- // TODO: correctly handle when hardware disabled
- syncBufferCallback.onBufferReady(null);
return;
}
+ if (DEBUG_BLAST) {
+ Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer);
+ }
mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
@Override
public void onFrameDraw(long frame) {
@@ -10984,7 +10878,9 @@ public final class ViewRootImpl implements ViewParent,
Log.d(mTag, "Setting up sync and frameCommitCallback");
}
- mBlastBufferQueue.syncNextTransaction(t -> syncBufferCallback.onBufferReady(t));
+ if (syncBuffer) {
+ mBlastBufferQueue.syncNextTransaction(syncBufferCallback::onBufferReady);
+ }
return didProduceBuffer -> {
if (DEBUG_BLAST) {
@@ -10998,18 +10894,40 @@ public final class ViewRootImpl implements ViewParent,
// were only set for the current draw attempt.
if (!didProduceBuffer) {
mBlastBufferQueue.syncNextTransaction(null);
+
// Gather the transactions that were sent to mergeWithNextTransaction
// since the frame didn't draw on this vsync. It's possible the frame will
// draw later, but it's better to not be sync than to block on a frame that
// may never come.
syncBufferCallback.onBufferReady(
mBlastBufferQueue.gatherPendingTransactions(frame));
+ return;
+ }
+
+ // If we didn't request to sync a buffer, then we won't get the
+ // syncNextTransaction callback. Instead, just report back to the Syncer so it
+ // knows that this sync request is complete.
+ if (!syncBuffer) {
+ syncBufferCallback.onBufferReady(null);
}
};
}
});
}
- public final SurfaceSyncer.SyncTarget mSyncTarget =
- syncBufferCallback -> registerCallbacksForSync(syncBufferCallback);
+ public final SurfaceSyncer.SyncTarget mSyncTarget = this::readyToSync;
+
+ private void readyToSync(SurfaceSyncer.SyncBufferCallback syncBufferCallback) {
+ if (mSyncBufferCallback != null) {
+ Log.d(mTag, "Already set sync for the next draw.");
+ mSyncBufferCallback.onBufferReady(null);
+ }
+ if (DEBUG_BLAST) {
+ Log.d(mTag, "Setting syncFrameCallback");
+ }
+ mSyncBufferCallback = syncBufferCallback;
+ if (!mIsInTraversal && !mTraversalScheduled) {
+ scheduleTraversals();
+ }
+ }
}
diff --git a/core/java/android/window/OnBackInvokedCallback.java b/core/java/android/window/OnBackInvokedCallback.java
index dcd80fd76e09..400a56f2c485 100644
--- a/core/java/android/window/OnBackInvokedCallback.java
+++ b/core/java/android/window/OnBackInvokedCallback.java
@@ -33,7 +33,7 @@ import android.view.View;
* within the same priority. Between different pirorities, callbacks with higher priority
* are invoked first.
*
- * See {@link OnBackInvokedDispatcher#registerOnBackInvokedCallback(OnBackInvokedCallback, int)}
+ * See {@link OnBackInvokedDispatcher#registerOnBackInvokedCallback(int, OnBackInvokedCallback)}
* for specifying callback priority.
*/
public interface OnBackInvokedCallback {
diff --git a/core/java/android/window/OnBackInvokedDispatcher.java b/core/java/android/window/OnBackInvokedDispatcher.java
index 63e6d30c8c0b..5eed8cde8c7c 100644
--- a/core/java/android/window/OnBackInvokedDispatcher.java
+++ b/core/java/android/window/OnBackInvokedDispatcher.java
@@ -94,15 +94,15 @@ public interface OnBackInvokedDispatcher {
* Within the same priority level, callbacks are invoked in the reverse order in which
* they are registered. Higher priority callbacks are invoked before lower priority ones.
*
+ * @param priority The priority of the callback.
* @param callback The callback to be registered. If the callback instance has been already
* registered, the existing instance (no matter its priority) will be
* unregistered and registered again.
- * @param priority The priority of the callback.
* @throws {@link IllegalArgumentException} if the priority is negative.
*/
- @SuppressLint({"SamShouldBeLast", "ExecutorRegistration"})
+ @SuppressLint({"ExecutorRegistration"})
void registerOnBackInvokedCallback(
- @NonNull OnBackInvokedCallback callback, @Priority @IntRange(from = 0) int priority);
+ @Priority @IntRange(from = 0) int priority, @NonNull OnBackInvokedCallback callback);
/**
* Unregisters a {@link OnBackInvokedCallback}.
diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
index cf17a2116aac..2b2f5e945710 100644
--- a/core/java/android/window/ProxyOnBackInvokedDispatcher.java
+++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
@@ -44,7 +44,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
/**
* List of pair representing an {@link OnBackInvokedCallback} and its associated priority.
*
- * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(OnBackInvokedCallback, int)
+ * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(int, OnBackInvokedCallback)
*/
private final List<Pair<OnBackInvokedCallback, Integer>> mCallbacks = new ArrayList<>();
private final Object mLock = new Object();
@@ -52,7 +52,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
@Override
public void registerOnBackInvokedCallback(
- @NonNull OnBackInvokedCallback callback, int priority) {
+ int priority, @NonNull OnBackInvokedCallback callback) {
if (DEBUG) {
Log.v(TAG, String.format("Pending register %s. Actual=%s", callback,
mActualDispatcherOwner));
@@ -91,7 +91,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
mCallbacks.add(Pair.create(callback, priority));
if (mActualDispatcherOwner != null) {
mActualDispatcherOwner.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
- callback, priority);
+ priority, callback);
}
}
}
@@ -115,7 +115,7 @@ public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
for (Pair<OnBackInvokedCallback, Integer> callbackPair : mCallbacks) {
int priority = callbackPair.second;
if (priority >= 0) {
- dispatcher.registerOnBackInvokedCallback(callbackPair.first, priority);
+ dispatcher.registerOnBackInvokedCallback(priority, callbackPair.first);
} else {
dispatcher.registerSystemOnBackInvokedCallback(callbackPair.first);
}
diff --git a/core/java/android/window/WindowInfosListener.java b/core/java/android/window/WindowInfosListener.java
index 9d4545c6e25d..8db5a5eb0e47 100644
--- a/core/java/android/window/WindowInfosListener.java
+++ b/core/java/android/window/WindowInfosListener.java
@@ -17,6 +17,7 @@
package android.window;
import android.graphics.Matrix;
+import android.util.Pair;
import android.util.Size;
import android.view.InputWindowHandle;
@@ -47,9 +48,13 @@ public abstract class WindowInfosListener {
/**
* Register the WindowInfosListener.
+ *
+ * @return The cached values for InputWindowHandles and DisplayInfos. This is the last updated
+ * value that was sent from SurfaceFlinger to this particular process. If there was nothing
+ * registered previously, then the data can be empty.
*/
- public void register() {
- nativeRegister(mNativeListener);
+ public Pair<InputWindowHandle[], DisplayInfo[]> register() {
+ return nativeRegister(mNativeListener);
}
/**
@@ -60,7 +65,7 @@ public abstract class WindowInfosListener {
}
private static native long nativeCreate(WindowInfosListener thiz);
- private static native void nativeRegister(long ptr);
+ private static native Pair<InputWindowHandle[], DisplayInfo[]> nativeRegister(long ptr);
private static native void nativeUnregister(long ptr);
private static native long nativeGetFinalizer();
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index d046cefee5f7..97573c291340 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -83,7 +83,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
// TODO: Take an Executor for the callback to run on.
@Override
public void registerOnBackInvokedCallback(
- @NonNull OnBackInvokedCallback callback, @Priority int priority) {
+ @Priority int priority, @NonNull OnBackInvokedCallback callback) {
if (priority < 0) {
throw new IllegalArgumentException("Application registered OnBackInvokedCallback "
+ "cannot have negative priority. Priority: " + priority);
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 34c47ede99f0..06bc4b56901a 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -33,6 +33,7 @@ import android.annotation.Nullable;
import android.graphics.HardwareRendererObserver;
import android.os.Handler;
import android.os.Trace;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
@@ -188,6 +189,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
if (mBeginVsyncId != INVALID_ID) {
mSurfaceControlWrapper.addJankStatsListener(
FrameTracker.this, mSurfaceControl);
+ markEvent("FT#deferMonitoring");
postTraceStartMarker();
}
}
@@ -241,8 +243,9 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
if (mSurfaceControl != null) {
if (mDeferMonitoring) {
+ markEvent("FT#deferMonitoring");
// Normal case, we begin the instrument from the very beginning,
- // except the first frame.
+ // will exclude the first frame.
postTraceStartMarker();
} else {
// If we don't begin the instrument from the very beginning,
@@ -272,6 +275,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
return;
}
mTracingStarted = true;
+ markEvent("FT#begin");
Trace.beginAsyncSection(mSession.getName(), (int) mBeginVsyncId);
}
}
@@ -295,6 +299,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
Log.d(TAG, "end: " + mSession.getName()
+ ", end=" + mEndVsyncId + ", reason=" + reason);
}
+ markEvent("FT#end#" + reason);
Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
mSession.setReason(reason);
@@ -322,6 +327,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
reason == REASON_CANCEL_NOT_BEGUN || reason == REASON_CANCEL_SAME_VSYNC;
if (mCancelled || (mEndVsyncId != INVALID_ID && !cancelFromEnd)) return false;
mCancelled = true;
+ markEvent("FT#cancel#" + reason);
// We don't need to end the trace section if it never begun.
if (mTracingStarted) {
Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId);
@@ -343,6 +349,11 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
}
+ private void markEvent(String desc) {
+ Trace.beginSection(TextUtils.formatSimple("%s#%s", mSession.getName(), desc));
+ Trace.endSection();
+ }
+
private void notifyCujEvent(String action) {
if (mListener == null) return;
mListener.onCujEvents(mSession, action);
diff --git a/core/java/com/android/internal/logging/InstanceId.java b/core/java/com/android/internal/logging/InstanceId.java
deleted file mode 100644
index c90d851201a2..000000000000
--- a/core/java/com/android/internal/logging/InstanceId.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.logging;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * An opaque identifier used to disambiguate which logs refer to a particular instance of some
- * UI element. Useful when there might be multiple instances simultaneously active.
- * Obtain from InstanceIdSequence. Clipped to range [0, INSTANCE_ID_MAX].
- */
-public final class InstanceId implements Parcelable {
- // At most 20 bits: ~1m possibilities, ~0.5% probability of collision in 100 values
- static final int INSTANCE_ID_MAX = 1 << 20;
-
- private final int mId;
- InstanceId(int id) {
- mId = min(max(0, id), INSTANCE_ID_MAX);
- }
-
- private InstanceId(Parcel in) {
- this(in.readInt());
- }
-
- @VisibleForTesting
- public int getId() {
- return mId;
- }
-
- /**
- * Create a fake instance ID for testing purposes. Not for production use. See also
- * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence.
- * @param id The ID you want to assign.
- * @return new InstanceId.
- */
- @VisibleForTesting
- public static InstanceId fakeInstanceId(int id) {
- return new InstanceId(id);
- }
-
- @Override
- public int hashCode() {
- return mId;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof InstanceId)) {
- return false;
- }
- return mId == ((InstanceId) obj).mId;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mId);
- }
-
- public static final Parcelable.Creator<InstanceId> CREATOR =
- new Parcelable.Creator<InstanceId>() {
- @Override
- public InstanceId createFromParcel(Parcel in) {
- return new InstanceId(in);
- }
-
- @Override
- public InstanceId[] newArray(int size) {
- return new InstanceId[size];
- }
- };
-
-}
diff --git a/core/java/com/android/internal/logging/InstanceIdSequence.java b/core/java/com/android/internal/logging/InstanceIdSequence.java
deleted file mode 100644
index 34643105b965..000000000000
--- a/core/java/com/android/internal/logging/InstanceIdSequence.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.logging;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.security.SecureRandom;
-import java.util.Random;
-
-/**
- * Generates random InstanceIds in range [1, instanceIdMax] for passing to
- * UiEventLogger.logWithInstanceId(). Holds a SecureRandom, which self-seeds on
- * first use; try to give it a long lifetime. Safe for concurrent use.
- */
-public class InstanceIdSequence {
- protected final int mInstanceIdMax;
- private final Random mRandom = new SecureRandom();
-
- /**
- * Constructs a sequence with identifiers [1, instanceIdMax]. Capped at INSTANCE_ID_MAX.
- * @param instanceIdMax Limiting value of identifiers. Normally positive: otherwise you get
- * an all-1 sequence.
- */
- public InstanceIdSequence(int instanceIdMax) {
- mInstanceIdMax = min(max(1, instanceIdMax), InstanceId.INSTANCE_ID_MAX);
- }
-
- /**
- * Gets the next instance from the sequence. Safe for concurrent use.
- * @return new InstanceId
- */
- public InstanceId newInstanceId() {
- return newInstanceIdInternal(1 + mRandom.nextInt(mInstanceIdMax));
- }
-
- /**
- * Factory function for instance IDs, used for testing.
- * @param id
- * @return new InstanceId(id)
- */
- @VisibleForTesting
- protected InstanceId newInstanceIdInternal(int id) {
- return new InstanceId(id);
- }
-}
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
deleted file mode 100644
index 5378b03fe1c5..000000000000
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.logging;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-/**
- * Logging interface for UI events. Normal implementation is UiEventLoggerImpl.
- * For testing, use fake implementation UiEventLoggerFake.
- *
- * See go/sysui-event-logs and UiEventReported atom in atoms.proto.
- */
-public interface UiEventLogger {
- /** Put your Event IDs in enums that implement this interface, and document them using the
- * UiEventEnum annotation.
- * Event IDs must be globally unique. This will be enforced by tooling (forthcoming).
- * OEMs should use event IDs above 100000 and below 1000000 (1 million).
- */
- interface UiEventEnum {
-
- /**
- * Tag used to request new UI Event IDs via presubmit analysis.
- *
- * <p>Use RESERVE_NEW_UI_EVENT_ID as the constructor parameter for a new {@link EventEnum}
- * to signal the presubmit analyzer to reserve a new ID for the event. The new ID will be
- * returned as a Gerrit presubmit finding. Do not submit {@code RESERVE_NEW_UI_EVENT_ID} as
- * the constructor parameter for any event.
- *
- * <pre>
- * &#064;UiEvent(doc = "Briefly describe the interaction when this event will be logged")
- * UNIQUE_EVENT_NAME(RESERVE_NEW_UI_EVENT_ID);
- * </pre>
- */
- int RESERVE_NEW_UI_EVENT_ID = Integer.MIN_VALUE; // Negative IDs are ignored by the logger.
-
- int getId();
- }
-
- /**
- * Log a simple event, with no package information. Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- */
- void log(@NonNull UiEventEnum event);
-
- /**
- * Log a simple event with an instance id, without package information.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log().
- */
- void log(@NonNull UiEventEnum event, @Nullable InstanceId instance);
-
- /**
- * Log an event with package information. Does nothing if event.getId() <= 0.
- * Give both uid and packageName if both are known, but one may be omitted if unknown.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- */
- void log(@NonNull UiEventEnum event, int uid, @Nullable String packageName);
-
- /**
- * Log an event with package information and an instance ID.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to log().
- */
- void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
- @Nullable InstanceId instance);
-
- /**
- * Log an event with ranked-choice information along with package.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- * @param position the position picked.
- */
- void logWithPosition(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
- int position);
-
- /**
- * Log an event with ranked-choice information along with package and instance ID.
- * Does nothing if event.getId() <= 0.
- * @param event an enum implementing UiEventEnum interface.
- * @param uid the uid of the relevant app, if known (0 otherwise).
- * @param packageName the package name of the relevant app, if known (null otherwise).
- * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to
- * logWithPosition().
- * @param position the position picked.
- */
- void logWithInstanceIdAndPosition(@NonNull UiEventEnum event, int uid,
- @Nullable String packageName, @Nullable InstanceId instance, int position);
-}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 3b46f627265b..8901c0774783 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4763,8 +4763,11 @@ public class BatteryStatsImpl extends BatteryStats {
if (Process.isSdkSandboxUid(uid)) {
return Process.getAppUidForSdkSandboxUid(uid);
}
- int isolated = mIsolatedUids.get(uid, -1);
- return isolated > 0 ? isolated : uid;
+ return mapIsolatedUid(uid);
+ }
+
+ private int mapIsolatedUid(int uid) {
+ return mIsolatedUids.get(/*key=*/uid, /*valueIfKeyNotFound=*/uid);
}
@GuardedBy("this")
@@ -5215,7 +5218,7 @@ public class BatteryStatsImpl extends BatteryStats {
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
} else {
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
- mappedUid, null, getPowerManagerWakeLockLevel(type), name,
+ mapIsolatedUid(uid), null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE);
}
}
@@ -5269,7 +5272,7 @@ public class BatteryStatsImpl extends BatteryStats {
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
} else {
FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED,
- mappedUid, null, getPowerManagerWakeLockLevel(type), name,
+ mapIsolatedUid(uid), null, getPowerManagerWakeLockLevel(type), name,
FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE);
}
@@ -5693,7 +5696,10 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
private void noteStartGpsLocked(int uid, WorkChain workChain,
long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ final int mappedUid = mapUid(uid);
if (mGpsNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
@@ -5703,21 +5709,24 @@ public class BatteryStatsImpl extends BatteryStats {
mGpsNesting++;
if (workChain == null) {
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, uid, null,
- FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
+ mapIsolatedUid(uid), null, FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
} else {
FrameworkStatsLog.write(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
workChain.getUids(), workChain.getTags(),
FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
}
- getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteStartGps(elapsedRealtimeMs);
+ getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs).noteStartGps(elapsedRealtimeMs);
}
@GuardedBy("this")
private void noteStopGpsLocked(int uid, WorkChain workChain,
long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ final int mappedUid = mapUid(uid);
mGpsNesting--;
if (mGpsNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
@@ -5729,14 +5738,15 @@ public class BatteryStatsImpl extends BatteryStats {
}
if (workChain == null) {
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, uid, null,
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED,
+ mapIsolatedUid(uid), null,
FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF);
} else {
FrameworkStatsLog.write(FrameworkStatsLog.GPS_SCAN_STATE_CHANGED, workChain.getUids(),
workChain.getTags(), FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF);
}
- getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteStopGps(elapsedRealtimeMs);
+ getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs).noteStopGps(elapsedRealtimeMs);
}
@GuardedBy("this")
@@ -7154,7 +7164,10 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
private void noteBluetoothScanStartedLocked(WorkChain workChain, int uid,
boolean isUnoptimized, long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ uid = mapUid(uid);
if (mBluetoothScanNesting == 0) {
mHistoryCur.states2 |= HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: "
@@ -7194,7 +7207,10 @@ public class BatteryStatsImpl extends BatteryStats {
@GuardedBy("this")
private void noteBluetoothScanStoppedLocked(WorkChain workChain, int uid,
boolean isUnoptimized, long elapsedRealtimeMs, long uptimeMs) {
- uid = getAttributionUid(uid, workChain);
+ if (workChain != null) {
+ uid = workChain.getAttributionUid();
+ }
+ uid = mapUid(uid);
mBluetoothScanNesting--;
if (mBluetoothScanNesting == 0) {
mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
@@ -7207,14 +7223,6 @@ public class BatteryStatsImpl extends BatteryStats {
.noteBluetoothScanStoppedLocked(elapsedRealtimeMs, isUnoptimized);
}
- private int getAttributionUid(int uid, WorkChain workChain) {
- if (workChain != null) {
- return mapUid(workChain.getAttributionUid());
- }
-
- return mapUid(uid);
- }
-
@GuardedBy("this")
public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws, boolean isUnoptimized) {
noteBluetoothScanStoppedFromSourceLocked(ws, isUnoptimized,
diff --git a/core/java/com/android/internal/os/KernelAllocationStats.java b/core/java/com/android/internal/os/KernelAllocationStats.java
index 1c3f8b0bf095..58d51e327ade 100644
--- a/core/java/com/android/internal/os/KernelAllocationStats.java
+++ b/core/java/com/android/internal/os/KernelAllocationStats.java
@@ -24,21 +24,29 @@ public final class KernelAllocationStats {
/** Process dma-buf stats. */
public static final class ProcessDmabuf {
+ public final int uid;
+ public final String processName;
+ public final int oomScore;
+
/** Size of buffers retained by the process. */
public final int retainedSizeKb;
/** Number of buffers retained by the process. */
public final int retainedBuffersCount;
- /** Size of buffers mapped to the address space. */
- public final int mappedSizeKb;
- /** Count of buffers mapped to the address space. */
- public final int mappedBuffersCount;
+ /** Size of buffers shared with Surface Flinger. */
+ public final int surfaceFlingerSizeKb;
+ /** Count of buffers shared with Surface Flinger. */
+ public final int surfaceFlingerCount;
- ProcessDmabuf(int retainedSizeKb, int retainedBuffersCount,
- int mappedSizeKb, int mappedBuffersCount) {
+ ProcessDmabuf(int uid, String processName, int oomScore, int retainedSizeKb,
+ int retainedBuffersCount, int surfaceFlingerSizeKb,
+ int surfaceFlingerCount) {
+ this.uid = uid;
+ this.processName = processName;
+ this.oomScore = oomScore;
this.retainedSizeKb = retainedSizeKb;
this.retainedBuffersCount = retainedBuffersCount;
- this.mappedSizeKb = mappedSizeKb;
- this.mappedBuffersCount = mappedBuffersCount;
+ this.surfaceFlingerSizeKb = surfaceFlingerSizeKb;
+ this.surfaceFlingerCount = surfaceFlingerCount;
}
}
@@ -47,7 +55,7 @@ public final class KernelAllocationStats {
* stats could not be read.
*/
@Nullable
- public static native ProcessDmabuf getDmabufAllocations(int pid);
+ public static native ProcessDmabuf[] getDmabufAllocations();
/** Pid to gpu memory size. */
public static final class ProcessGpuMem {
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index cc7e9d95b4f8..db41d333e1d4 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -31,9 +31,11 @@ import android.os.FileUtils;
import android.os.Process;
import android.os.SystemProperties;
import android.os.Trace;
+import android.os.VintfRuntimeInfo;
import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.permission.PermissionManager.SplitPermissionInfo;
+import android.sysprop.ApexProperties;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -56,7 +58,10 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -1187,7 +1192,8 @@ public class SystemConfig {
boolean systemExt = permFile.toPath().startsWith(
Environment.getSystemExtDirectory().toPath() + "/");
boolean apex = permFile.toPath().startsWith(
- Environment.getApexDirectory().toPath() + "/");
+ Environment.getApexDirectory().toPath() + "/")
+ && ApexProperties.updatable().orElse(false);
if (vendor) {
readPrivAppPermissions(parser, mVendorPrivAppPermissions,
mVendorPrivAppDenyPermissions);
@@ -1445,6 +1451,14 @@ public class SystemConfig {
addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
}
+ if (isFilesystemSupported("erofs")) {
+ if (isKernelVersionAtLeast(5, 10)) {
+ addFeature(PackageManager.FEATURE_EROFS, 0);
+ } else if (isKernelVersionAtLeast(4, 19)) {
+ addFeature(PackageManager.FEATURE_EROFS_LEGACY, 0);
+ }
+ }
+
for (String featureName : mUnavailableFeatures) {
removeFeature(featureName);
}
@@ -1814,4 +1828,29 @@ public class SystemConfig {
private static boolean isSystemProcess() {
return Process.myUid() == Process.SYSTEM_UID;
}
+
+ private static boolean isFilesystemSupported(String fs) {
+ try {
+ final byte[] fsTableData = Files.readAllBytes(Paths.get("/proc/filesystems"));
+ final String fsTable = new String(fsTableData, StandardCharsets.UTF_8);
+ return fsTable.contains("\t" + fs + "\n");
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ private static boolean isKernelVersionAtLeast(int major, int minor) {
+ final String kernelVersion = VintfRuntimeInfo.getKernelVersion();
+ final String[] parts = kernelVersion.split("\\.");
+ if (parts.length < 2) {
+ return false;
+ }
+ try {
+ final int majorVersion = Integer.parseInt(parts[0]);
+ final int minorVersion = Integer.parseInt(parts[1]);
+ return majorVersion > major || (majorVersion == major && minorVersion >= minor);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 3a76745cc4d9..a1be88440c97 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -272,6 +272,7 @@ cc_library_shared {
"libinput",
"libcamera_client",
"libcamera_metadata",
+ "libprocinfo",
"libsqlite",
"libEGL",
"libGLESv1_CM",
diff --git a/core/jni/android_window_WindowInfosListener.cpp b/core/jni/android_window_WindowInfosListener.cpp
index 08c9f20b0815..aae2549df429 100644
--- a/core/jni/android_window_WindowInfosListener.cpp
+++ b/core/jni/android_window_WindowInfosListener.cpp
@@ -44,6 +44,11 @@ static struct {
jmethodID ctor;
} gDisplayInfoClassInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+} gPairClassInfo;
+
static jclass gInputWindowHandleClass;
jobject fromDisplayInfo(JNIEnv* env, gui::DisplayInfo displayInfo) {
@@ -57,6 +62,30 @@ jobject fromDisplayInfo(JNIEnv* env, gui::DisplayInfo displayInfo) {
displayInfo.logicalHeight, matrixObj.get());
}
+static jobjectArray fromWindowInfos(JNIEnv* env, const std::vector<WindowInfo>& windowInfos) {
+ jobjectArray jWindowHandlesArray =
+ env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass, nullptr);
+ for (int i = 0; i < windowInfos.size(); i++) {
+ ScopedLocalRef<jobject>
+ jWindowHandle(env,
+ android_view_InputWindowHandle_fromWindowInfo(env, windowInfos[i]));
+ env->SetObjectArrayElement(jWindowHandlesArray, i, jWindowHandle.get());
+ }
+
+ return jWindowHandlesArray;
+}
+
+static jobjectArray fromDisplayInfos(JNIEnv* env, const std::vector<DisplayInfo>& displayInfos) {
+ jobjectArray jDisplayInfoArray =
+ env->NewObjectArray(displayInfos.size(), gDisplayInfoClassInfo.clazz, nullptr);
+ for (int i = 0; i < displayInfos.size(); i++) {
+ ScopedLocalRef<jobject> jDisplayInfo(env, fromDisplayInfo(env, displayInfos[i]));
+ env->SetObjectArrayElement(jDisplayInfoArray, i, jDisplayInfo.get());
+ }
+
+ return jDisplayInfoArray;
+}
+
struct WindowInfosListener : public gui::WindowInfosListener {
WindowInfosListener(JNIEnv* env, jobject listener)
: mListener(env->NewWeakGlobalRef(listener)) {}
@@ -72,26 +101,8 @@ struct WindowInfosListener : public gui::WindowInfosListener {
return;
}
- ScopedLocalRef<jobjectArray>
- jWindowHandlesArray(env,
- env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass,
- nullptr));
- for (int i = 0; i < windowInfos.size(); i++) {
- ScopedLocalRef<jobject>
- jWindowHandle(env,
- android_view_InputWindowHandle_fromWindowInfo(env,
- windowInfos[i]));
- env->SetObjectArrayElement(jWindowHandlesArray.get(), i, jWindowHandle.get());
- }
-
- ScopedLocalRef<jobjectArray>
- jDisplayInfoArray(env,
- env->NewObjectArray(displayInfos.size(),
- gDisplayInfoClassInfo.clazz, nullptr));
- for (int i = 0; i < displayInfos.size(); i++) {
- ScopedLocalRef<jobject> jDisplayInfo(env, fromDisplayInfo(env, displayInfos[i]));
- env->SetObjectArrayElement(jDisplayInfoArray.get(), i, jDisplayInfo.get());
- }
+ ScopedLocalRef<jobjectArray> jWindowHandlesArray(env, fromWindowInfos(env, windowInfos));
+ ScopedLocalRef<jobjectArray> jDisplayInfoArray(env, fromDisplayInfos(env, displayInfos));
env->CallVoidMethod(listener, gListenerClassInfo.onWindowInfosChanged,
jWindowHandlesArray.get(), jDisplayInfoArray.get());
@@ -124,9 +135,16 @@ void destroyNativeService(void* ptr) {
listener->decStrong((void*)nativeCreate);
}
-void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
+jobject nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
sp<WindowInfosListener> listener = reinterpret_cast<WindowInfosListener*>(ptr);
- SurfaceComposerClient::getDefault()->addWindowInfosListener(listener);
+ std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>> initialInfo;
+ SurfaceComposerClient::getDefault()->addWindowInfosListener(listener, &initialInfo);
+
+ ScopedLocalRef<jobjectArray> jWindowHandlesArray(env, fromWindowInfos(env, initialInfo.first));
+ ScopedLocalRef<jobjectArray> jDisplayInfoArray(env, fromDisplayInfos(env, initialInfo.second));
+
+ return env->NewObject(gPairClassInfo.clazz, gPairClassInfo.ctor, jWindowHandlesArray.get(),
+ jDisplayInfoArray.get());
}
void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
@@ -141,7 +159,7 @@ static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{"nativeCreate", "(Landroid/window/WindowInfosListener;)J", (void*)nativeCreate},
- {"nativeRegister", "(J)V", (void*)nativeRegister},
+ {"nativeRegister", "(J)Landroid/util/Pair;", (void*)nativeRegister},
{"nativeUnregister", "(J)V", (void*)nativeUnregister},
{"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer}};
@@ -166,6 +184,12 @@ int register_android_window_WindowInfosListener(JNIEnv* env) {
gDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gDisplayInfoClassInfo.ctor = env->GetMethodID(gDisplayInfoClassInfo.clazz, "<init>",
"(IIILandroid/graphics/Matrix;)V");
+
+ clazz = env->FindClass("android/util/Pair");
+ gPairClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+ gPairClassInfo.ctor = env->GetMethodID(gPairClassInfo.clazz, "<init>",
+ "(Ljava/lang/Object;Ljava/lang/Object;)V");
+
return 0;
}
diff --git a/core/jni/com_android_internal_os_KernelAllocationStats.cpp b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
index e0a24430e739..5b104977f1d8 100644
--- a/core/jni/com_android_internal_os_KernelAllocationStats.cpp
+++ b/core/jni/com_android_internal_os_KernelAllocationStats.cpp
@@ -13,12 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <dmabufinfo/dmabufinfo.h>
#include <jni.h>
#include <meminfo/sysmeminfo.h>
+#include <procinfo/process.h>
#include "core_jni_helpers.h"
+using DmaBuffer = ::android::dmabufinfo::DmaBuffer;
+using android::base::ReadFileToString;
+using android::base::StringPrintf;
+
namespace {
static jclass gProcessDmabufClazz;
static jmethodID gProcessDmabufCtor;
@@ -28,30 +35,127 @@ static jmethodID gProcessGpuMemCtor;
namespace android {
-static jobject KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject, jint pid) {
- std::vector<dmabufinfo::DmaBuffer> buffers;
- if (!dmabufinfo::ReadDmaBufMapRefs(pid, &buffers)) {
+struct PidDmaInfo {
+ uid_t uid;
+ std::string cmdline;
+ int oomScoreAdj;
+};
+
+static jobjectArray KernelAllocationStats_getDmabufAllocations(JNIEnv *env, jobject) {
+ std::vector<DmaBuffer> buffers;
+
+ if (!dmabufinfo::ReadDmaBufs(&buffers)) {
return nullptr;
}
- jint mappedSize = 0;
- jint mappedCount = buffers.size();
- for (const auto &buffer : buffers) {
- mappedSize += buffer.size();
+
+ // Create a reverse map from pid to dmabufs
+ // Store dmabuf inodes & sizes for later processing.
+ std::unordered_map<pid_t, std::set<ino_t>> pidToInodes;
+ std::unordered_map<ino_t, long> inodeToSize;
+ for (auto &buf : buffers) {
+ for (auto pid : buf.pids()) {
+ pidToInodes[pid].insert(buf.inode());
+ }
+ inodeToSize[buf.inode()] = buf.size();
+ }
+
+ pid_t surfaceFlingerPid = -1;
+ // The set of all inodes that are being retained by SurfaceFlinger. Buffers
+ // shared between another process and SF will appear in this set.
+ std::set<ino_t> surfaceFlingerBufferInodes;
+ // The set of all inodes that are being retained by any process other
+ // than SurfaceFlinger. Buffers shared between another process and SF will
+ // appear in this set.
+ std::set<ino_t> otherProcessBufferInodes;
+
+ // Find SurfaceFlinger pid & get cmdlines, oomScoreAdj, etc for each pid
+ // holding any DMA buffers.
+ std::unordered_map<pid_t, PidDmaInfo> pidDmaInfos;
+ for (const auto &pidToInodeEntry : pidToInodes) {
+ pid_t pid = pidToInodeEntry.first;
+
+ android::procinfo::ProcessInfo processInfo;
+ if (!android::procinfo::GetProcessInfo(pid, &processInfo)) {
+ continue;
+ }
+
+ std::string cmdline;
+ if (!ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &cmdline)) {
+ continue;
+ }
+
+ // cmdline strings are null-delimited, so we split on \0 here
+ if (cmdline.substr(0, cmdline.find('\0')) == "/system/bin/surfaceflinger") {
+ if (surfaceFlingerPid == -1) {
+ surfaceFlingerPid = pid;
+ surfaceFlingerBufferInodes = pidToInodes[pid];
+ } else {
+ LOG(ERROR) << "getDmabufAllocations found multiple SF processes; pid1: " << pid
+ << ", pid2:" << surfaceFlingerPid;
+ surfaceFlingerPid = -2; // Used as a sentinel value below
+ }
+ } else {
+ otherProcessBufferInodes.insert(pidToInodes[pid].begin(), pidToInodes[pid].end());
+ }
+
+ std::string oomScoreAdjStr;
+ if (!ReadFileToString(StringPrintf("/proc/%d/oom_score_adj", pid), &oomScoreAdjStr)) {
+ continue;
+ }
+
+ pidDmaInfos[pid] = PidDmaInfo{.uid = processInfo.uid,
+ .cmdline = cmdline,
+ .oomScoreAdj = atoi(oomScoreAdjStr.c_str())};
+ }
+
+ if (surfaceFlingerPid < 0) {
+ LOG(ERROR) << "getDmabufAllocations could not identify SurfaceFlinger "
+ << "process via /proc/pid/cmdline";
}
- mappedSize /= 1024;
-
- jint retainedSize = -1;
- jint retainedCount = -1;
- if (dmabufinfo::ReadDmaBufFdRefs(pid, &buffers)) {
- retainedCount = buffers.size();
- retainedSize = 0;
- for (const auto &buffer : buffers) {
- retainedSize += buffer.size();
+
+ jobjectArray ret = env->NewObjectArray(pidDmaInfos.size(), gProcessDmabufClazz, NULL);
+ int retArrayIndex = 0;
+ for (const auto &pidDmaInfosEntry : pidDmaInfos) {
+ pid_t pid = pidDmaInfosEntry.first;
+
+ // For all processes apart from SurfaceFlinger, this set will store the
+ // dmabuf inodes that are shared with SF. For SF, it will store the inodes
+ // that are shared with any other process.
+ std::set<ino_t> sharedBuffers;
+ if (pid == surfaceFlingerPid) {
+ set_intersection(surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+ otherProcessBufferInodes.begin(), otherProcessBufferInodes.end(),
+ std::inserter(sharedBuffers, sharedBuffers.end()));
+ } else if (surfaceFlingerPid > 0) {
+ set_intersection(pidToInodes[pid].begin(), pidToInodes[pid].end(),
+ surfaceFlingerBufferInodes.begin(), surfaceFlingerBufferInodes.end(),
+ std::inserter(sharedBuffers, sharedBuffers.begin()));
+ } // If surfaceFlingerPid < 0; it means we failed to identify it, and
+ // the SF-related fields below should be left empty.
+
+ long totalSize = 0;
+ long sharedBuffersSize = 0;
+ for (const auto &inode : pidToInodes[pid]) {
+ totalSize += inodeToSize[inode];
+ if (sharedBuffers.count(inode)) {
+ sharedBuffersSize += inodeToSize[inode];
+ }
}
- retainedSize /= 1024;
+
+ jobject obj = env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor,
+ /* uid */ pidDmaInfos[pid].uid,
+ /* process name */
+ env->NewStringUTF(pidDmaInfos[pid].cmdline.c_str()),
+ /* oomscore */ pidDmaInfos[pid].oomScoreAdj,
+ /* retainedSize */ totalSize / 1024,
+ /* retainedCount */ pidToInodes[pid].size(),
+ /* sharedWithSurfaceFlinger size */ sharedBuffersSize / 1024,
+ /* sharedWithSurfaceFlinger count */ sharedBuffers.size());
+
+ env->SetObjectArrayElement(ret, retArrayIndex++, obj);
}
- return env->NewObject(gProcessDmabufClazz, gProcessDmabufCtor, retainedSize, retainedCount,
- mappedSize, mappedCount);
+
+ return ret;
}
static jobject KernelAllocationStats_getGpuAllocations(JNIEnv *env) {
@@ -74,7 +178,7 @@ static jobject KernelAllocationStats_getGpuAllocations(JNIEnv *env) {
}
static const JNINativeMethod methods[] = {
- {"getDmabufAllocations", "(I)Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
+ {"getDmabufAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessDmabuf;",
(void *)KernelAllocationStats_getDmabufAllocations},
{"getGpuAllocations", "()[Lcom/android/internal/os/KernelAllocationStats$ProcessGpuMem;",
(void *)KernelAllocationStats_getGpuAllocations},
@@ -86,7 +190,8 @@ int register_com_android_internal_os_KernelAllocationStats(JNIEnv *env) {
jclass clazz =
FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessDmabuf");
gProcessDmabufClazz = MakeGlobalRefOrDie(env, clazz);
- gProcessDmabufCtor = GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(IIII)V");
+ gProcessDmabufCtor =
+ GetMethodIDOrDie(env, gProcessDmabufClazz, "<init>", "(ILjava/lang/String;IIIII)V");
clazz = FindClassOrDie(env, "com/android/internal/os/KernelAllocationStats$ProcessGpuMem");
gProcessGpuMemClazz = MakeGlobalRefOrDie(env, clazz);
@@ -94,4 +199,4 @@ int register_com_android_internal_os_KernelAllocationStats(JNIEnv *env) {
return res;
}
-} // namespace android
+} // namespace android \ No newline at end of file
diff --git a/core/proto/android/os/appbatterystats.proto b/core/proto/android/os/appbatterystats.proto
new file mode 100644
index 000000000000..8769ebb74979
--- /dev/null
+++ b/core/proto/android/os/appbatterystats.proto
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.os;
+
+option java_multiple_files = true;
+
+message AppBatteryStatsProto {
+ message UidStats {
+ optional int32 uid = 1;
+
+ message ProcessStateStats {
+ enum ProcessState {
+ UNSPECIFIED = 0;
+ FOREGROUND = 1;
+ BACKGROUND = 2;
+ FOREGROUND_SERVICE = 3;
+ CACHED = 4;
+ }
+
+ optional ProcessState process_state = 1;
+
+ // Time spent in this state in the past 24 hours
+ optional int64 duration_ms = 2;
+ // Estimated power consumed in this state in the past 24 hours
+ optional double power_mah = 3;
+ }
+
+ repeated ProcessStateStats process_state_stats = 2;
+ }
+
+ repeated UidStats uid_stats = 1;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d652b2ff4f4a..0c194db02128 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -528,6 +528,7 @@
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
+ <protected-broadcast android:name="android.app.action.MANAGED_PROFILE_PROVISIONED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
<protected-broadcast android:name="com.android.bluetooth.map.USER_CONFIRM_TIMEOUT" />
@@ -720,10 +721,12 @@
<!-- Added in T -->
<protected-broadcast android:name="android.safetycenter.action.REFRESH_SAFETY_SOURCES" />
+ <protected-broadcast android:name="android.safetycenter.action.SAFETY_CENTER_ENABLED_CHANGED" />
<protected-broadcast android:name="android.app.action.DEVICE_POLICY_RESOURCE_UPDATED" />
<protected-broadcast android:name="android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER" />
<protected-broadcast android:name="android.service.autofill.action.DELAYED_FILL" />
<protected-broadcast android:name="android.app.action.PROVISIONING_COMPLETED" />
+ <protected-broadcast android:name="android.app.action.LOST_MODE_LOCATION_UPDATE" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -6051,10 +6054,10 @@
<permission android:name="android.permission.MANAGE_APPOPS"
android:protectionLevel="signature" />
- <!-- @hide Permission that allows background clipboard access.
- <p>Not for use by third-party applications. -->
+ <!-- @SystemApi Permission that allows background clipboard access.
+ @hide Not for use by third-party applications. -->
<permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|role" />
<!-- @hide Permission that suppresses the notification when the clipboard is accessed.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION"
diff --git a/core/tests/coretests/src/android/net/SntpClientTest.java b/core/tests/coretests/src/android/net/SntpClientTest.java
index ba7df1e218d9..267fc2b636d6 100644
--- a/core/tests/coretests/src/android/net/SntpClientTest.java
+++ b/core/tests/coretests/src/android/net/SntpClientTest.java
@@ -295,7 +295,8 @@ public class SntpClientTest {
@Test
public void testDnsResolutionFailure() throws Exception {
- assertFalse(mClient.requestTime("ntp.server.doesnotexist.example", 5000, mNetwork));
+ assertFalse(mClient.requestTime("ntp.server.doesnotexist.example",
+ SntpClient.STANDARD_NTP_PORT, 5000, mNetwork));
}
@Test
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index 1ae9649dfe06..e303934c4aad 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -60,7 +60,7 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class HandwritingInitiatorTest {
private static final int TOUCH_SLOP = 8;
- private static final long TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
+ private static final long TIMEOUT = ViewConfiguration.getLongPressTimeout();
private static final Rect sHwArea = new Rect(100, 200, 500, 500);
private HandwritingInitiator mHandwritingInitiator;
@@ -177,7 +177,7 @@ public class HandwritingInitiatorTest {
}
@Test
- public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTapTimeOut() {
+ public void onTouchEvent_notStartHandwriting_when_stylusMove_afterTimeOut() {
mHandwritingInitiator.onInputConnectionCreated(mTestView);
final int x1 = 10;
final int y1 = 10;
@@ -187,7 +187,7 @@ public class HandwritingInitiatorTest {
final int x2 = x1 + TOUCH_SLOP * 2;
final int y2 = y1;
- final long time2 = time1 + TAP_TIMEOUT + 10L;
+ final long time2 = time1 + TIMEOUT + 10L;
MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, time2);
mHandwritingInitiator.onTouchEvent(stylusEvent2);
diff --git a/core/tests/coretests/src/android/window/BackNavigationTest.java b/core/tests/coretests/src/android/window/BackNavigationTest.java
index 8fa48ef5494d..94a149b09d54 100644
--- a/core/tests/coretests/src/android/window/BackNavigationTest.java
+++ b/core/tests/coretests/src/android/window/BackNavigationTest.java
@@ -111,12 +111,12 @@ public class BackNavigationTest {
CountDownLatch backRegisteredLatch = new CountDownLatch(1);
mScenario.onActivity(activity -> {
activity.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
- new OnBackInvokedCallback() {
+ 0, new OnBackInvokedCallback() {
@Override
public void onBackInvoked() {
backInvokedLatch.countDown();
}
- }, 0
+ }
);
backRegisteredLatch.countDown();
});
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index f8c994416f46..212f4ed92b8c 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -77,9 +77,9 @@ public class WindowOnBackInvokedDispatcherTest {
ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
verify(mWindowSession, times(2)).setOnBackInvokedCallback(
Mockito.eq(mWindow),
@@ -102,9 +102,9 @@ public class WindowOnBackInvokedDispatcherTest {
ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+ OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback1);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
verify(mWindowSession).setOnBackInvokedCallback(
Mockito.eq(mWindow), captor.capture(),
@@ -118,9 +118,9 @@ public class WindowOnBackInvokedDispatcherTest {
@Test
public void propagatesTopCallback_withRemoval() throws RemoteException {
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
reset(mWindowSession);
mDispatcher.unregisterOnBackInvokedCallback(mCallback1);
@@ -139,16 +139,17 @@ public class WindowOnBackInvokedDispatcherTest {
ArgumentCaptor<IOnBackInvokedCallback> captor =
ArgumentCaptor.forClass(IOnBackInvokedCallback.class);
- mDispatcher.registerOnBackInvokedCallback(mCallback1,
- OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+ mDispatcher.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_OVERLAY,
+ mCallback1
+ );
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback2);
mDispatcher.registerOnBackInvokedCallback(
- mCallback1, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCallback1);
reset(mWindowSession);
mDispatcher.registerOnBackInvokedCallback(
- mCallback2, OnBackInvokedDispatcher.PRIORITY_OVERLAY);
+ OnBackInvokedDispatcher.PRIORITY_OVERLAY, mCallback2);
verify(mWindowSession).setOnBackInvokedCallback(
Mockito.eq(mWindow),
captor.capture(),
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index ec45a016507a..625f52a87ecf 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -232,7 +232,7 @@ public final class LooperStatsTest {
assertThat(entry3.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerSecond");
assertThat(entry3.messageName).startsWith(
- "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda5");
+ "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda");
assertThat(entry3.messageCount).isEqualTo(1);
assertThat(entry3.recordedMessageCount).isEqualTo(1);
assertThat(entry3.exceptionCount).isEqualTo(0);
diff --git a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
index 5dc44d21c6b7..8de919681006 100644
--- a/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
+++ b/core/tests/mockingcoretests/src/android/util/TimingsTraceLogTest.java
@@ -123,7 +123,7 @@ public class TimingsTraceLogTest {
public void testLogDuration() throws Exception {
TimingsTraceLog log = new TimingsTraceLog(TAG, TRACE_TAG_APP, 10);
log.logDuration("logro", 42);
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), contains("logro took to complete: 42ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
}
@Test
@@ -134,7 +134,7 @@ public class TimingsTraceLogTest {
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("test took to complete: \\dms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
}
@Test
@@ -149,8 +149,8 @@ public class TimingsTraceLogTest {
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
}
@Test
@@ -170,9 +170,9 @@ public class TimingsTraceLogTest {
verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L3"));
verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(3));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L2 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L1 took to complete: \\d+ms")));
- verify((MockedVoidMethod) () -> Slog.d(eq(TAG), matches("L3 took to complete: \\d+ms")),
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L3 took to complete: \\d+ms")),
never());
verify((MockedVoidMethod) () -> Slog.w(TAG, "not tracing duration of 'L3' "
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index d1873a0f40cf..2d1db716b700 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -76,5 +76,8 @@
<permission name="android.permission.FORCE_STOP_PACKAGES" />
<permission name="android.permission.ACCESS_FPS_COUNTER" />
<permission name="android.permission.CHANGE_CONFIGURATION" />
+ <permission name="android.permission.LOG_COMPAT_CHANGE" />
+ <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <permission name="android.permission.READ_DEVICE_CONFIG" />
</privapp-permissions>
</permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index e898f570a6b8..4449c48d28bb 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2257,6 +2257,12 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/TransitionController.java"
},
+ "264036181": {
+ "message": "Unable to retrieve task to start recording for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"269576220": {
"message": "Resuming rotation after drag",
"level": "DEBUG",
@@ -2761,6 +2767,12 @@
"group": "WM_DEBUG_WALLPAPER",
"at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
},
+ "736003885": {
+ "message": "Unable to retrieve the task token to start recording for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"736692676": {
"message": "Config is relaunching %s",
"level": "VERBOSE",
@@ -2791,6 +2803,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "778774915": {
+ "message": "Unable to record task since feature is disabled %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONTENT_RECORDING",
+ "at": "com\/android\/server\/wm\/ContentRecorder.java"
+ },
"781471998": {
"message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
"level": "WARN",
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 61f7facf0916..a2f5301e353f 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -329,7 +329,7 @@ public class Typeface {
FontFamily.Builder familyBuilder = null;
for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) {
final Font.Builder fontBuilder = new Font.Builder(mgr, fontFile.getFileName(),
- false /* isAsset */, 0 /* cookie */)
+ false /* isAsset */, AssetManager.COOKIE_UNKNOWN)
.setTtcIndex(fontFile.getTtcIndex())
.setFontVariationSettings(fontFile.getVariationSettings());
if (fontFile.getWeight() != Typeface.RESOLVE_BY_FONT_TABLE) {
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index cd7936d50dff..abd0be9c2872 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -179,7 +179,7 @@ public final class Font {
*/
public Builder(@NonNull AssetManager am, @NonNull String path) {
try {
- mBuffer = createBuffer(am, path, true /* is asset */, 0 /* cookie */);
+ mBuffer = createBuffer(am, path, true /* is asset */, AssetManager.COOKIE_UNKNOWN);
} catch (IOException e) {
mException = e;
}
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 58f79f3600de..13d12b3589c0 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
@@ -1049,10 +1049,17 @@ public class BubbleStackView extends FrameLayout
private final Runnable mAnimateTemporarilyInvisibleImmediate = () -> {
if (mTemporarilyInvisible && mFlyout.getVisibility() != View.VISIBLE) {
+ // To calculate a distance, bubble stack needs to be moved to become hidden,
+ // we need to take into account that the bubble stack is positioned on the edge
+ // of the available screen rect, which can be offset by system bars and cutouts.
if (mStackAnimationController.isStackOnLeftSide()) {
- animate().translationX(-mBubbleSize).start();
+ int availableRectOffsetX =
+ mPositioner.getAvailableRect().left - mPositioner.getScreenRect().left;
+ animate().translationX(-(mBubbleSize + availableRectOffsetX)).start();
} else {
- animate().translationX(mBubbleSize).start();
+ int availableRectOffsetX =
+ mPositioner.getAvailableRect().right - mPositioner.getScreenRect().right;
+ animate().translationX(mBubbleSize - availableRectOffsetX).start();
}
} else {
animate().translationX(0).start();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index be713a59a816..e5a755c35add 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -166,8 +166,7 @@ public class PipTransition extends PipTransitionController {
mExitTransition = null;
mHasFadeOut = false;
if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(null, null);
- mFinishCallback = null;
+ callFinishCallback(null /* wct */);
mFinishTransaction = null;
throw new RuntimeException("Previous callback not called, aborting exit PIP.");
}
@@ -232,6 +231,11 @@ public class PipTransition extends PipTransitionController {
return false;
}
+ /** Helper to identify whether this handler is currently the one playing an animation */
+ private boolean isAnimatingLocally() {
+ return mFinishTransaction != null;
+ }
+
@Nullable
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@@ -282,9 +286,11 @@ public class PipTransition extends PipTransitionController {
if (enteringPip) {
mPipTransitionState.setTransitionState(ENTERED_PIP);
}
- // If there is an expected exit transition, then the exit will be "merged" into this
- // transition so don't fire the finish-callback in that case.
- if (mExitTransition == null && mFinishCallback != null) {
+ // If we have an exit transition, but aren't playing a transition locally, it
+ // means we're expecting the exit transition will be "merged" into another transition
+ // (likely a remote like launcher), so don't fire the finish-callback here -- wait until
+ // the exit transition is merged.
+ if ((mExitTransition == null || isAnimatingLocally()) && mFinishCallback != null) {
WindowContainerTransaction wct = new WindowContainerTransaction();
prepareFinishResizeTransaction(taskInfo, destinationBounds,
direction, wct);
@@ -305,12 +311,19 @@ public class PipTransition extends PipTransitionController {
mSurfaceTransactionHelper.crop(mFinishTransaction, leash, finishBounds);
}
mFinishTransaction = null;
- mFinishCallback.onTransitionFinished(wct, null /* callback */);
- mFinishCallback = null;
+ callFinishCallback(wct);
}
finishResizeForMenu(destinationBounds);
}
+ private void callFinishCallback(WindowContainerTransaction wct) {
+ // Need to unset mFinishCallback first because onTransitionFinished can re-enter this
+ // handler if there is a pending PiP animation.
+ final Transitions.TransitionFinishCallback finishCallback = mFinishCallback;
+ mFinishCallback = null;
+ finishCallback.onTransitionFinished(wct, null /* callback */);
+ }
+
@Override
public void forceFinishTransition() {
if (mFinishCallback == null) return;
@@ -572,8 +585,7 @@ public class PipTransition extends PipTransitionController {
mHasFadeOut = false;
if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
- mFinishCallback = null;
+ callFinishCallback(null /* wct */);
mFinishTransaction = null;
throw new RuntimeException("Previous callback not called, aborting entering PIP.");
}
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 177b4a8b5982..2da5becae8f5 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
@@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
@@ -325,8 +326,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
}
- public void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
- @Nullable Bundle options) {
+ public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
+ @SplitPosition int position, @Nullable Bundle options) {
if (!ENABLE_SHELL_TRANSITIONS) {
startIntentLegacy(intent, fillInIntent, position, options);
return;
@@ -335,6 +336,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
try {
options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
null /* wct */);
+
+ // Flag this as a no-user-action launch to prevent sending user leaving event to the
+ // current top activity since it's going to be put into another side of the split. This
+ // prevents the current top activity from going into pip mode due to user leaving event.
+ if (fillInIntent == null) {
+ fillInIntent = new Intent();
+ }
+ fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
+
intent.send(mContext, 0, fillInIntent, null /* onFinished */, null /* handler */,
null /* requiredPermission */, options);
} catch (PendingIntent.CanceledException e) {
@@ -342,7 +352,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
}
- private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
+ private void startIntentLegacy(PendingIntent intent, @Nullable Intent fillInIntent,
@SplitPosition int position, @Nullable Bundle options) {
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
mStageCoordinator.prepareEvictChildTasks(position, evictWct);
@@ -393,6 +403,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
final WindowContainerTransaction wct = new WindowContainerTransaction();
options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);
+
+ // Flag this as a no-user-action launch to prevent sending user leaving event to the current
+ // top activity since it's going to be put into another side of the split. This prevents the
+ // current top activity from going into pip mode due to user leaving event.
+ if (fillInIntent == null) {
+ fillInIntent = new Intent();
+ }
+ fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
+
wct.sendPendingIntent(intent, fillInIntent, options);
mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
}
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index dd272cd5ff7d..c24cabb287de 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -310,6 +310,11 @@ bool HardwareBitmapUploader::has1010102Support() {
return has101012Support;
}
+bool HardwareBitmapUploader::hasAlpha8Support() {
+ static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
+ return hasAlpha8Support;
+}
+
static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
FormatInfo formatInfo;
switch (skBitmap.info().colorType()) {
@@ -363,6 +368,13 @@ static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
}
formatInfo.format = GL_RGBA;
break;
+ case kAlpha_8_SkColorType:
+ formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8_UNORM;
+ formatInfo.format = GL_R8;
+ formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.vkFormat = VK_FORMAT_R8_UNORM;
+ break;
default:
ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
formatInfo.valid = false;
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 34f43cd8a198..81057a24c29c 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -30,11 +30,13 @@ public:
#ifdef __ANDROID__
static bool hasFP16Support();
static bool has1010102Support();
+ static bool hasAlpha8Support();
#else
static bool hasFP16Support() {
return true;
}
static bool has1010102Support() { return true; }
+ static bool hasAlpha8Support() { return true; }
#endif
};
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 1a89cfd5d0ad..67f47580a70f 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -104,6 +104,10 @@ sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
+ if (bitmap.colorType() == kAlpha_8_SkColorType &&
+ !uirenderer::HardwareBitmapUploader::hasAlpha8Support()) {
+ return nullptr;
+ }
return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
#else
return Bitmap::allocateHeapBitmap(bitmap.info());
diff --git a/location/java/android/location/GnssExcessPathInfo.java b/location/java/android/location/GnssExcessPathInfo.java
new file mode 100644
index 000000000000..72b2374bad8f
--- /dev/null
+++ b/location/java/android/location/GnssExcessPathInfo.java
@@ -0,0 +1,375 @@
+/*
+ * 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.location;
+
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo.EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Contains the info of an excess path signal caused by reflection
+ *
+ * @hide
+ */
+@SystemApi
+public final class GnssExcessPathInfo implements Parcelable {
+
+ private static final int HAS_EXCESS_PATH_LENGTH_MASK = EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH;
+ private static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK =
+ EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC;
+ private static final int HAS_REFLECTING_PLANE_MASK = EXCESS_PATH_INFO_HAS_REFLECTING_PLANE;
+ private static final int HAS_ATTENUATION_MASK = EXCESS_PATH_INFO_HAS_ATTENUATION;
+
+ /* A bitmask of fields present in this object (see HAS_* constants defined above) */
+ private final int mFlags;
+ private final float mExcessPathLengthMeters;
+ private final float mExcessPathLengthUncertaintyMeters;
+ @Nullable
+ private final GnssReflectingPlane mReflectingPlane;
+ private final float mAttenuationDb;
+
+ private GnssExcessPathInfo(
+ int flags,
+ float excessPathLengthMeters,
+ float excessPathLengthUncertaintyMeters,
+ @Nullable GnssReflectingPlane reflectingPlane,
+ float attenuationDb) {
+ mFlags = flags;
+ mExcessPathLengthMeters = excessPathLengthMeters;
+ mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mReflectingPlane = reflectingPlane;
+ mAttenuationDb = attenuationDb;
+ }
+
+ /**
+ * Gets a bitmask of fields present in this object.
+ *
+ * <p>This API exists for JNI since it is easier for JNI to get one integer flag than looking up
+ * several has* methods.
+ * @hide
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
+ public boolean hasExcessPathLength() {
+ return (mFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+ }
+
+ /**
+ * Returns the excess path length to be subtracted from pseudorange before using it in
+ * calculating location.
+ *
+ * <p>{@link #hasExcessPathLength()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getExcessPathLengthMeters() {
+ if (!hasExcessPathLength()) {
+ throw new UnsupportedOperationException(
+ "getExcessPathLengthMeters() is not supported when hasExcessPathLength() is "
+ + "false");
+ }
+ return mExcessPathLengthMeters;
+ }
+
+ /** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
+ public boolean hasExcessPathLengthUncertainty() {
+ return (mFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+ }
+
+ /**
+ * Returns the error estimate (1-sigma) for the excess path length estimate.
+ *
+ * <p>{@link #hasExcessPathLengthUncertainty()} must be true when calling this method.
+ * Otherwise, an {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getExcessPathLengthUncertaintyMeters() {
+ if (!hasExcessPathLengthUncertainty()) {
+ throw new UnsupportedOperationException(
+ "getExcessPathLengthUncertaintyMeters() is not supported when "
+ + "hasExcessPathLengthUncertainty() is false");
+ }
+ return mExcessPathLengthUncertaintyMeters;
+ }
+
+ /**
+ * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+ *
+ * <p>Returns false if the satellite signal goes through multiple reflections or if reflection
+ * plane serving is not supported.
+ */
+ public boolean hasReflectingPlane() {
+ return (mFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+ }
+
+ /**
+ * Returns the reflecting plane characteristics at which the signal has bounced.
+ *
+ * <p>{@link #hasReflectingPlane()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @NonNull
+ public GnssReflectingPlane getReflectingPlane() {
+ if (!hasReflectingPlane()) {
+ throw new UnsupportedOperationException(
+ "getReflectingPlane() is not supported when hasReflectingPlane() is false");
+ }
+ return mReflectingPlane;
+ }
+
+ /** Returns {@code true} if {@link #getAttenuationDb()} is valid. */
+ public boolean hasAttenuation() {
+ return (mFlags & HAS_ATTENUATION_MASK) != 0;
+ }
+
+ /**
+ * Returns the expected reduction of signal strength of this path in non-negative dB.
+ *
+ * <p>{@link #hasAttenuation()} must be true when calling this method. Otherwise, an
+ * {@link UnsupportedOperationException} will be thrown.
+ */
+ @FloatRange(from = 0.0f)
+ public float getAttenuationDb() {
+ if (!hasAttenuation()) {
+ throw new UnsupportedOperationException(
+ "getAttenuationDb() is not supported when hasAttenuation() is false");
+ }
+ return mAttenuationDb;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int parcelFlags) {
+ parcel.writeInt(mFlags);
+ if (hasExcessPathLength()) {
+ parcel.writeFloat(mExcessPathLengthMeters);
+ }
+ if (hasExcessPathLengthUncertainty()) {
+ parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+ }
+ if (hasReflectingPlane()) {
+ mReflectingPlane.writeToParcel(parcel, parcelFlags);
+ }
+ if (hasAttenuation()) {
+ parcel.writeFloat(mAttenuationDb);
+ }
+ }
+
+ public static final @NonNull Creator<GnssExcessPathInfo> CREATOR =
+ new Creator<GnssExcessPathInfo>() {
+ @Override
+ @NonNull
+ public GnssExcessPathInfo createFromParcel(@NonNull Parcel parcel) {
+ int flags = parcel.readInt();
+ float excessPathLengthMeters =
+ (flags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+ ? parcel.readFloat() : 0;
+ float excessPathLengthUncertaintyMeters =
+ (flags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+ ? parcel.readFloat() : 0;
+ GnssReflectingPlane reflectingPlane =
+ (flags & HAS_REFLECTING_PLANE_MASK) != 0
+ ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+ float attenuationDb =
+ (flags & HAS_ATTENUATION_MASK) != 0
+ ? parcel.readFloat() : 0;
+ return new GnssExcessPathInfo(flags, excessPathLengthMeters,
+ excessPathLengthUncertaintyMeters, reflectingPlane, attenuationDb);
+ }
+
+ @Override
+ public GnssExcessPathInfo[] newArray(int i) {
+ return new GnssExcessPathInfo[i];
+ }
+ };
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof GnssExcessPathInfo) {
+ GnssExcessPathInfo that = (GnssExcessPathInfo) obj;
+ return this.mFlags == that.mFlags
+ && (!hasExcessPathLength() || Float.compare(this.mExcessPathLengthMeters,
+ that.mExcessPathLengthMeters) == 0)
+ && (!hasExcessPathLengthUncertainty() || Float.compare(
+ this.mExcessPathLengthUncertaintyMeters,
+ that.mExcessPathLengthUncertaintyMeters) == 0)
+ && (!hasReflectingPlane() || Objects.equals(this.mReflectingPlane,
+ that.mReflectingPlane))
+ && (!hasAttenuation() || Float.compare(this.mAttenuationDb,
+ that.mAttenuationDb) == 0);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFlags,
+ mExcessPathLengthMeters,
+ mExcessPathLengthUncertaintyMeters,
+ mReflectingPlane,
+ mAttenuationDb);
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("GnssExcessPathInfo[");
+ if (hasExcessPathLength()) {
+ builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+ }
+ if (hasExcessPathLengthUncertainty()) {
+ builder.append(" ExcessPathLengthUncertaintyMeters=").append(
+ mExcessPathLengthUncertaintyMeters);
+ }
+ if (hasReflectingPlane()) {
+ builder.append(" ReflectingPlane=").append(mReflectingPlane);
+ }
+ if (hasAttenuation()) {
+ builder.append(" AttenuationDb=").append(mAttenuationDb);
+ }
+ builder.append(']');
+ return builder.toString();
+ }
+
+ /** Builder for {@link GnssExcessPathInfo}. */
+ public static final class Builder {
+ private int mFlags;
+ private float mExcessPathLengthMeters;
+ private float mExcessPathLengthUncertaintyMeters;
+ @Nullable
+ private GnssReflectingPlane mReflectingPlane;
+ private float mAttenuationDb;
+
+ /** Constructor for {@link Builder}. */
+ public Builder() {}
+
+ /**
+ * Sets the excess path length to be subtracted from pseudorange before using it in
+ * calculating location.
+ */
+ @NonNull
+ public Builder setExcessPathLengthMeters(
+ @FloatRange(from = 0.0f) float excessPathLengthMeters) {
+ Preconditions.checkArgumentInRange(excessPathLengthMeters, 0, Float.MAX_VALUE,
+ "excessPathLengthMeters");
+ mExcessPathLengthMeters = excessPathLengthMeters;
+ mFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the excess path length.
+ *
+ * <p>This is to negate {@link #setExcessPathLengthMeters} call.
+ */
+ @NonNull
+ public Builder clearExcessPathLengthMeters() {
+ mExcessPathLengthMeters = 0;
+ mFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+ return this;
+ }
+
+ /** Sets the error estimate (1-sigma) for the excess path length estimate */
+ @NonNull
+ public Builder setExcessPathLengthUncertaintyMeters(
+ @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
+ Preconditions.checkArgumentInRange(excessPathLengthUncertaintyMeters, 0,
+ Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+ mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the error estimate (1-sigma) for the excess path length estimate
+ *
+ * <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
+ */
+ @NonNull
+ public Builder clearExcessPathLengthUncertaintyMeters() {
+ mExcessPathLengthUncertaintyMeters = 0;
+ mFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ return this;
+ }
+
+ /** Sets the reflecting plane information */
+ @NonNull
+ public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
+ mReflectingPlane = reflectingPlane;
+ if (reflectingPlane != null) {
+ mFlags |= HAS_REFLECTING_PLANE_MASK;
+ } else {
+ mFlags &= ~HAS_REFLECTING_PLANE_MASK;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the attenuation value in dB.
+ */
+ @NonNull
+ public Builder setAttenuationDb(@FloatRange(from = 0.0f) float attenuationDb) {
+ Preconditions.checkArgumentInRange(attenuationDb, 0, Float.MAX_VALUE,
+ "attenuationDb");
+ mAttenuationDb = attenuationDb;
+ mFlags |= HAS_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the attenuation value in dB.
+ *
+ * <p>This is to negate {@link #setAttenuationDb(float)} call.
+ */
+ @NonNull
+ public Builder clearAttenuationDb() {
+ mAttenuationDb = 0;
+ mFlags &= ~HAS_ATTENUATION_MASK;
+ return this;
+ }
+
+ /** Builds a {@link GnssExcessPathInfo} instance as specified by this builder. */
+ @NonNull
+ public GnssExcessPathInfo build() {
+ return new GnssExcessPathInfo(
+ mFlags,
+ mExcessPathLengthMeters,
+ mExcessPathLengthUncertaintyMeters,
+ mReflectingPlane,
+ mAttenuationDb);
+ }
+ }
+}
diff --git a/location/java/android/location/GnssReflectingPlane.java b/location/java/android/location/GnssReflectingPlane.java
index 1acdd1ecce0b..115cbec5e4de 100644
--- a/location/java/android/location/GnssReflectingPlane.java
+++ b/location/java/android/location/GnssReflectingPlane.java
@@ -22,9 +22,14 @@ import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* Holds the characteristics of the reflecting plane that a satellite signal has bounced from.
*
+ * <p>Starting with Android T, this class supports {@link #equals} and {@link #hashCode}, which
+ * are not supported before that.
+ *
* @hide
*/
@SystemApi
@@ -107,24 +112,41 @@ public final class GnssReflectingPlane implements Parcelable {
}
};
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeDouble(mLatitudeDegrees);
+ parcel.writeDouble(mLongitudeDegrees);
+ parcel.writeDouble(mAltitudeMeters);
+ parcel.writeDouble(mAzimuthDegrees);
+ }
+
@NonNull
@Override
public String toString() {
- final String format = " %-29s = %s\n";
- StringBuilder builder = new StringBuilder("ReflectingPlane:\n");
- builder.append(String.format(format, "LatitudeDegrees = ", mLatitudeDegrees));
- builder.append(String.format(format, "LongitudeDegrees = ", mLongitudeDegrees));
- builder.append(String.format(format, "AltitudeMeters = ", mAltitudeMeters));
- builder.append(String.format(format, "AzimuthDegrees = ", mAzimuthDegrees));
+ StringBuilder builder = new StringBuilder("ReflectingPlane[");
+ builder.append(" LatitudeDegrees=").append(mLatitudeDegrees);
+ builder.append(" LongitudeDegrees=").append(mLongitudeDegrees);
+ builder.append(" AltitudeMeters=").append(mAltitudeMeters);
+ builder.append(" AzimuthDegrees=").append(mAzimuthDegrees);
+ builder.append(']');
return builder.toString();
}
@Override
- public void writeToParcel(@NonNull Parcel parcel, int flags) {
- parcel.writeDouble(mLatitudeDegrees);
- parcel.writeDouble(mLongitudeDegrees);
- parcel.writeDouble(mAltitudeMeters);
- parcel.writeDouble(mAzimuthDegrees);
+ public boolean equals(Object obj) {
+ if (obj instanceof GnssReflectingPlane) {
+ GnssReflectingPlane that = (GnssReflectingPlane) obj;
+ return Double.compare(this.mLatitudeDegrees, that.mLatitudeDegrees) == 0
+ && Double.compare(this.mLongitudeDegrees, that.mLongitudeDegrees) == 0
+ && Double.compare(this.mAltitudeMeters, that.mAltitudeMeters) == 0
+ && Double.compare(this.mAzimuthDegrees, that.mAzimuthDegrees) == 0;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mLatitudeDegrees, mLatitudeDegrees, mAltitudeMeters, mAzimuthDegrees);
}
/** Builder for {@link GnssReflectingPlane} */
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index 262630b79cb0..a7fce0aaaf6c 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -16,6 +16,11 @@
package android.location;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+import static android.hardware.gnss.measurement_corrections.SingleSatCorrection.SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+
import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -26,6 +31,8 @@ import android.os.Parcelable;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -36,106 +43,47 @@ import java.util.Objects;
@SystemApi
public final class GnssSingleSatCorrection implements Parcelable {
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mProbSatIsLos}.
- *
- * @hide
- */
- public static final int HAS_PROB_SAT_IS_LOS_MASK = 1 << 0;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mExcessPathLengthMeters}.
- *
- * @hide
- */
- public static final int HAS_EXCESS_PATH_LENGTH_MASK = 1 << 1;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mExcessPathLengthUncertaintyMeters}.
- *
- * @hide
- */
- public static final int HAS_EXCESS_PATH_LENGTH_UNC_MASK = 1 << 2;
-
- /**
- * Bit mask for {@link #mSingleSatCorrectionFlags} indicating the presence of {@link
- * #mReflectingPlane}.
- *
- * @hide
- */
- public static final int HAS_REFLECTING_PLANE_MASK = 1 << 3;
+ private static final int HAS_PROB_SAT_IS_LOS_MASK =
+ SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY;
+ private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH;
+ private static final int HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC;
+ private static final int HAS_COMBINED_ATTENUATION_MASK =
+ SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
- /** A bitmask of fields present in this object (see HAS_* constants defined above) */
+ /* A bitmask of fields present in this object (see HAS_* constants defined above). */
private final int mSingleSatCorrectionFlags;
- /** Defines the constellation of the given satellite as defined in {@link GnssStatus}. */
- @GnssStatus.ConstellationType
private final int mConstellationType;
-
- /**
- * Satellite vehicle ID number
- *
- * <p>Interpretation depends on {@link GnssStatus#getSvid(int)}.
- */
- @IntRange(from = 0)
private final int mSatId;
-
- /**
- * Carrier frequency of the signal to be corrected, for example it can be the GPS center
- * frequency for L1 = 1,575,420,000 Hz, varying GLO channels, etc.
- *
- * <p>For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two correction
- * objects will be reported for this same satellite, in one of the correction objects, all the
- * values related to L1 will be filled, and in the other all of the values related to L5 will be
- * filled.
- */
- @FloatRange(from = 0.0f, fromInclusive = false)
private final float mCarrierFrequencyHz;
-
- /**
- * The probability that the satellite is estimated to be in Line-of-Sight condition at the given
- * location.
- */
- @FloatRange(from = 0.0f, to = 1.0f)
private final float mProbSatIsLos;
+ private final float mCombinedExcessPathLengthMeters;
+ private final float mCombinedExcessPathLengthUncertaintyMeters;
+ private final float mCombinedAttenuationDb;
- /**
- * Excess path length to be subtracted from pseudorange before using it in calculating location.
- */
- @FloatRange(from = 0.0f)
- private final float mExcessPathLengthMeters;
-
- /** Error estimate (1-sigma) for the Excess path length estimate */
- @FloatRange(from = 0.0f)
- private final float mExcessPathLengthUncertaintyMeters;
-
- /**
- * Defines the reflecting plane location and azimuth information
- *
- * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
- * signal goes through multiple reflections or if reflection plane serving is not supported.
- */
- @Nullable
- private final GnssReflectingPlane mReflectingPlane;
+ @NonNull
+ private final List<GnssExcessPathInfo> mGnssExcessPathInfoList;
private GnssSingleSatCorrection(int singleSatCorrectionFlags, int constellationType, int satId,
float carrierFrequencyHz, float probSatIsLos, float excessPathLengthMeters,
- float excessPathLengthUncertaintyMeters, GnssReflectingPlane reflectingPlane) {
+ float excessPathLengthUncertaintyMeters,
+ float combinedAttenuationDb,
+ @NonNull List<GnssExcessPathInfo> gnssExcessPathInfoList) {
mSingleSatCorrectionFlags = singleSatCorrectionFlags;
mConstellationType = constellationType;
mSatId = satId;
mCarrierFrequencyHz = carrierFrequencyHz;
mProbSatIsLos = probSatIsLos;
- mExcessPathLengthMeters = excessPathLengthMeters;
- mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
- mReflectingPlane = reflectingPlane;
+ mCombinedExcessPathLengthMeters = excessPathLengthMeters;
+ mCombinedExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+ mCombinedAttenuationDb = combinedAttenuationDb;
+ mGnssExcessPathInfoList = gnssExcessPathInfoList;
}
/**
- * Gets a bitmask of fields present in this object
+ * Gets a bitmask of fields present in this object.
*
* @hide
*/
@@ -193,29 +141,46 @@ public final class GnssSingleSatCorrection implements Parcelable {
}
/**
- * Returns the Excess path length to be subtracted from pseudorange before using it in
+ * Returns the combined excess path length to be subtracted from pseudorange before using it in
* calculating location.
*/
@FloatRange(from = 0.0f)
public float getExcessPathLengthMeters() {
- return mExcessPathLengthMeters;
+ return mCombinedExcessPathLengthMeters;
}
- /** Returns the error estimate (1-sigma) for the Excess path length estimate */
+ /** Returns the error estimate (1-sigma) for the combined excess path length estimate. */
@FloatRange(from = 0.0f)
public float getExcessPathLengthUncertaintyMeters() {
- return mExcessPathLengthUncertaintyMeters;
+ return mCombinedExcessPathLengthUncertaintyMeters;
}
/**
- * Returns the reflecting plane characteristics at which the signal has bounced
+ * Returns the combined expected reduction of signal strength for this satellite in
+ * non-negative dB.
+ */
+ @FloatRange(from = 0.0f)
+ public float getCombinedAttenuationDb() {
+ return mCombinedAttenuationDb;
+ }
+
+ /**
+ * Returns the reflecting plane characteristics at which the signal has bounced.
*
- * <p>The flag HAS_REFLECTING_PLANE will be used to set this value to invalid if the satellite
- * signal goes through multiple reflections or if reflection plane serving is not supported
+ * @deprecated Combined excess path does not have a reflecting plane.
*/
@Nullable
+ @Deprecated
public GnssReflectingPlane getReflectingPlane() {
- return mReflectingPlane;
+ return null;
+ }
+
+ /**
+ * Returns the list of {@link GnssExcessPathInfo} associated with this satellite signal.
+ */
+ @NonNull
+ public List<GnssExcessPathInfo> getGnssExcessPathInfoList() {
+ return mGnssExcessPathInfoList;
}
/** Returns {@code true} if {@link #getProbabilityLineOfSight()} is valid. */
@@ -225,17 +190,27 @@ public final class GnssSingleSatCorrection implements Parcelable {
/** Returns {@code true} if {@link #getExcessPathLengthMeters()} is valid. */
public boolean hasExcessPathLength() {
- return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0;
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0;
}
/** Returns {@code true} if {@link #getExcessPathLengthUncertaintyMeters()} is valid. */
public boolean hasExcessPathLengthUncertainty() {
- return (mSingleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK) != 0;
}
- /** Returns {@code true} if {@link #getReflectingPlane()} is valid. */
+ /**
+ * Returns {@code true} if {@link #getReflectingPlane()} is valid.
+ *
+ * @deprecated Combined excess path does not have a reflecting plane.
+ */
+ @Deprecated
public boolean hasReflectingPlane() {
- return (mSingleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0;
+ return false;
+ }
+
+ /** Returns {@code true} if {@link #getCombinedAttenuationDb()} is valid. */
+ public boolean hasCombinedAttenuation() {
+ return (mSingleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0;
}
@Override
@@ -253,14 +228,15 @@ public final class GnssSingleSatCorrection implements Parcelable {
parcel.writeFloat(mProbSatIsLos);
}
if (hasExcessPathLength()) {
- parcel.writeFloat(mExcessPathLengthMeters);
+ parcel.writeFloat(mCombinedExcessPathLengthMeters);
}
if (hasExcessPathLengthUncertainty()) {
- parcel.writeFloat(mExcessPathLengthUncertaintyMeters);
+ parcel.writeFloat(mCombinedExcessPathLengthUncertaintyMeters);
}
- if (hasReflectingPlane()) {
- mReflectingPlane.writeToParcel(parcel, flags);
+ if (hasCombinedAttenuation()) {
+ parcel.writeFloat(mCombinedAttenuationDb);
}
+ parcel.writeTypedList(mGnssExcessPathInfoList);
}
public static final Creator<GnssSingleSatCorrection> CREATOR =
@@ -274,18 +250,21 @@ public final class GnssSingleSatCorrection implements Parcelable {
float carrierFrequencyHz = parcel.readFloat();
float probSatIsLos = (singleSatCorrectionFlags & HAS_PROB_SAT_IS_LOS_MASK) != 0
? parcel.readFloat() : 0;
- float excessPathLengthMeters =
- (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_MASK) != 0
+ float combinedExcessPathLengthMeters =
+ (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_MASK) != 0
? parcel.readFloat() : 0;
- float excessPathLengthUncertaintyMeters =
- (singleSatCorrectionFlags & HAS_EXCESS_PATH_LENGTH_UNC_MASK) != 0
+ float combinedExcessPathLengthUncertaintyMeters =
+ (singleSatCorrectionFlags & HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK)
+ != 0 ? parcel.readFloat() : 0;
+ float combinedAttenuationDb =
+ (singleSatCorrectionFlags & HAS_COMBINED_ATTENUATION_MASK) != 0
? parcel.readFloat() : 0;
- GnssReflectingPlane reflectingPlane =
- (singleSatCorrectionFlags & HAS_REFLECTING_PLANE_MASK) != 0
- ? GnssReflectingPlane.CREATOR.createFromParcel(parcel) : null;
+ List<GnssExcessPathInfo> gnssExcessPathInfoList = parcel.createTypedArrayList(
+ GnssExcessPathInfo.CREATOR);
return new GnssSingleSatCorrection(singleSatCorrectionFlags, constellationType,
- satId, carrierFrequencyHz, probSatIsLos, excessPathLengthMeters,
- excessPathLengthUncertaintyMeters, reflectingPlane);
+ satId, carrierFrequencyHz, probSatIsLos, combinedExcessPathLengthMeters,
+ combinedExcessPathLengthUncertaintyMeters, combinedAttenuationDb,
+ gnssExcessPathInfoList);
}
@Override
@@ -296,56 +275,24 @@ public final class GnssSingleSatCorrection implements Parcelable {
@Override
public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof GnssSingleSatCorrection)) {
- return false;
- }
-
- GnssSingleSatCorrection other = (GnssSingleSatCorrection) obj;
- if (mConstellationType != other.mConstellationType) {
- return false;
- }
- if (mSatId != other.mSatId) {
- return false;
- }
- if (Float.compare(mCarrierFrequencyHz, other.mCarrierFrequencyHz) != 0) {
- return false;
- }
-
- if (hasValidSatelliteLineOfSight() != other.hasValidSatelliteLineOfSight()) {
- return false;
- }
- if (hasValidSatelliteLineOfSight()
- && Float.compare(mProbSatIsLos, other.mProbSatIsLos) != 0) {
- return false;
- }
-
- if (hasExcessPathLength() != other.hasExcessPathLength()) {
- return false;
- }
- if (hasExcessPathLength()
- && Float.compare(mExcessPathLengthMeters, other.mExcessPathLengthMeters) != 0) {
- return false;
- }
-
- if (hasExcessPathLengthUncertainty() != other.hasExcessPathLengthUncertainty()) {
- return false;
- }
- if (hasExcessPathLengthUncertainty() && Float.compare(mExcessPathLengthUncertaintyMeters,
- other.mExcessPathLengthUncertaintyMeters) != 0) {
- return false;
- }
-
- if (hasReflectingPlane() != other.hasReflectingPlane()) {
- return false;
- }
- if (hasReflectingPlane()
- && !mReflectingPlane.equals(other.mReflectingPlane)) {
- return false;
- }
- return true;
+ if (obj instanceof GnssSingleSatCorrection) {
+ GnssSingleSatCorrection that = (GnssSingleSatCorrection) obj;
+ return this.mSingleSatCorrectionFlags == that.mSingleSatCorrectionFlags
+ && this.mConstellationType == that.mConstellationType
+ && this.mSatId == that.mSatId
+ && Float.compare(mCarrierFrequencyHz, that.mCarrierFrequencyHz) == 0
+ && (!hasValidSatelliteLineOfSight() || Float.compare(mProbSatIsLos,
+ that.mProbSatIsLos) == 0)
+ && (!hasExcessPathLength() || Float.compare(mCombinedExcessPathLengthMeters,
+ that.mCombinedExcessPathLengthMeters) == 0)
+ && (!hasExcessPathLengthUncertainty() || Float.compare(
+ mCombinedExcessPathLengthUncertaintyMeters,
+ that.mCombinedExcessPathLengthUncertaintyMeters) == 0)
+ && (!hasCombinedAttenuation() || Float.compare(mCombinedAttenuationDb,
+ that.mCombinedAttenuationDb) == 0)
+ && mGnssExcessPathInfoList.equals(that.mGnssExcessPathInfoList);
+ }
+ return false;
}
@Override
@@ -355,9 +302,10 @@ public final class GnssSingleSatCorrection implements Parcelable {
mSatId,
mCarrierFrequencyHz,
mProbSatIsLos,
- mExcessPathLengthMeters,
- mExcessPathLengthUncertaintyMeters,
- mReflectingPlane);
+ mCombinedExcessPathLengthMeters,
+ mCombinedExcessPathLengthUncertaintyMeters,
+ mCombinedAttenuationDb,
+ mGnssExcessPathInfoList);
}
@NonNull
@@ -371,14 +319,19 @@ public final class GnssSingleSatCorrection implements Parcelable {
builder.append(" ProbSatIsLos=").append(mProbSatIsLos);
}
if (hasExcessPathLength()) {
- builder.append(" ExcessPathLengthMeters=").append(mExcessPathLengthMeters);
+ builder.append(" CombinedExcessPathLengthMeters=").append(
+ mCombinedExcessPathLengthMeters);
}
if (hasExcessPathLengthUncertainty()) {
- builder.append(" ExcessPathLengthUncertaintyMeters=").append(
- mExcessPathLengthUncertaintyMeters);
+ builder.append(" CombinedExcessPathLengthUncertaintyMeters=").append(
+ mCombinedExcessPathLengthUncertaintyMeters);
}
- if (hasReflectingPlane()) {
- builder.append(" ReflectingPlane=").append(mReflectingPlane);
+ if (hasCombinedAttenuation()) {
+ builder.append(" CombinedAttenuationDb=").append(
+ mCombinedAttenuationDb);
+ }
+ if (!mGnssExcessPathInfoList.isEmpty()) {
+ builder.append(' ').append(mGnssExcessPathInfoList.toString());
}
builder.append(']');
return builder.toString();
@@ -386,21 +339,16 @@ public final class GnssSingleSatCorrection implements Parcelable {
/** Builder for {@link GnssSingleSatCorrection} */
public static final class Builder {
-
- /**
- * For documentation of below fields, see corresponding fields in {@link
- * GnssSingleSatCorrection}.
- */
private int mSingleSatCorrectionFlags;
-
private int mConstellationType;
private int mSatId;
private float mCarrierFrequencyHz;
private float mProbSatIsLos;
- private float mExcessPathLengthMeters;
- private float mExcessPathLengthUncertaintyMeters;
- @Nullable
- private GnssReflectingPlane mReflectingPlane;
+ private float mCombinedExcessPathLengthMeters;
+ private float mCombinedExcessPathLengthUncertaintyMeters;
+ private float mCombinedAttenuationDb;
+ @NonNull
+ private List<GnssExcessPathInfo> mGnssExcessInfoList = new ArrayList<>();
/** Sets the constellation type. */
@NonNull public Builder setConstellationType(
@@ -409,18 +357,18 @@ public final class GnssSingleSatCorrection implements Parcelable {
return this;
}
- /** Sets the Satellite ID defined in the ICD of the given constellation. */
+ /** Sets the satellite ID defined in the ICD of the given constellation. */
@NonNull public Builder setSatelliteId(@IntRange(from = 0) int satId) {
Preconditions.checkArgumentNonnegative(satId, "satId should be non-negative.");
mSatId = satId;
return this;
}
- /** Sets the Carrier frequency in Hz. */
+ /** Sets the carrier frequency in Hz. */
@NonNull public Builder setCarrierFrequencyHz(
@FloatRange(from = 0.0f, fromInclusive = false) float carrierFrequencyHz) {
- Preconditions.checkArgument(
- carrierFrequencyHz >= 0, "carrierFrequencyHz should be non-negative.");
+ Preconditions.checkArgumentInRange(
+ carrierFrequencyHz, 0, Float.MAX_VALUE, "carrierFrequencyHz");
mCarrierFrequencyHz = carrierFrequencyHz;
return this;
}
@@ -450,58 +398,90 @@ public final class GnssSingleSatCorrection implements Parcelable {
}
/**
- * Sets the Excess path length to be subtracted from pseudorange before using it in
+ * Sets the combined excess path length to be subtracted from pseudorange before using it in
* calculating location.
*/
- @NonNull public Builder setExcessPathLengthMeters(
- @FloatRange(from = 0.0f) float excessPathLengthMeters) {
- Preconditions.checkArgument(excessPathLengthMeters >= 0,
- "excessPathLengthMeters should be non-negative.");
- mExcessPathLengthMeters = excessPathLengthMeters;
- mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_MASK;
+ @NonNull
+ public Builder setExcessPathLengthMeters(
+ @FloatRange(from = 0.0f) float combinedExcessPathLengthMeters) {
+ Preconditions.checkArgumentInRange(combinedExcessPathLengthMeters, 0, Float.MAX_VALUE,
+ "excessPathLengthMeters");
+ mCombinedExcessPathLengthMeters = combinedExcessPathLengthMeters;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
return this;
}
/**
- * Clears the Excess path length.
+ * Clears the combined excess path length.
*
* <p>This is to negate {@link #setExcessPathLengthMeters} call.
*/
@NonNull public Builder clearExcessPathLengthMeters() {
- mExcessPathLengthMeters = 0;
- mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_MASK;
+ mCombinedExcessPathLengthMeters = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_MASK;
return this;
}
- /** Sets the error estimate (1-sigma) for the Excess path length estimate */
+ /** Sets the error estimate (1-sigma) for the combined excess path length estimate. */
@NonNull public Builder setExcessPathLengthUncertaintyMeters(
- @FloatRange(from = 0.0f) float excessPathLengthUncertaintyMeters) {
- Preconditions.checkArgument(excessPathLengthUncertaintyMeters >= 0,
- "excessPathLengthUncertaintyMeters should be non-negative.");
- mExcessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
- mSingleSatCorrectionFlags |= HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ @FloatRange(from = 0.0f) float combinedExcessPathLengthUncertaintyMeters) {
+ Preconditions.checkArgumentInRange(combinedExcessPathLengthUncertaintyMeters, 0,
+ Float.MAX_VALUE, "excessPathLengthUncertaintyMeters");
+ mCombinedExcessPathLengthUncertaintyMeters = combinedExcessPathLengthUncertaintyMeters;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
return this;
}
/**
- * Clears the error estimate (1-sigma) for the Excess path length estimate
+ * Clears the error estimate (1-sigma) for the combined excess path length estimate.
*
* <p>This is to negate {@link #setExcessPathLengthUncertaintyMeters} call.
*/
@NonNull public Builder clearExcessPathLengthUncertaintyMeters() {
- mExcessPathLengthUncertaintyMeters = 0;
- mSingleSatCorrectionFlags &= ~HAS_EXCESS_PATH_LENGTH_UNC_MASK;
+ mCombinedExcessPathLengthUncertaintyMeters = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_EXCESS_PATH_LENGTH_UNC_MASK;
return this;
}
- /** Sets the reflecting plane information */
+ /**
+ * Sets the combined attenuation in Db.
+ */
+ @NonNull public Builder setCombinedAttenuationDb(
+ @FloatRange(from = 0.0f) float combinedAttenuationDb) {
+ Preconditions.checkArgumentInRange(combinedAttenuationDb, 0, Float.MAX_VALUE,
+ "combinedAttenuationDb");
+ mCombinedAttenuationDb = combinedAttenuationDb;
+ mSingleSatCorrectionFlags |= HAS_COMBINED_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Clears the combined attenuation.
+ *
+ * <p>This is to negate {@link #setCombinedAttenuationDb} call.
+ */
+ @NonNull public Builder clearCombinedAttenuationDb() {
+ mCombinedAttenuationDb = 0;
+ mSingleSatCorrectionFlags &= ~HAS_COMBINED_ATTENUATION_MASK;
+ return this;
+ }
+
+ /**
+ * Sets the reflecting plane information.
+ *
+ * @deprecated Combined excess path does not have a reflecting plane.
+ */
+ @Deprecated
@NonNull public Builder setReflectingPlane(@Nullable GnssReflectingPlane reflectingPlane) {
- mReflectingPlane = reflectingPlane;
- if (reflectingPlane != null) {
- mSingleSatCorrectionFlags |= HAS_REFLECTING_PLANE_MASK;
- } else {
- mSingleSatCorrectionFlags &= ~HAS_REFLECTING_PLANE_MASK;
- }
+ return this;
+ }
+
+ /**
+ * Sets the collection of {@link GnssExcessPathInfo}.
+ */
+ @NonNull
+ public Builder setGnssExcessPathInfoList(@NonNull List<GnssExcessPathInfo> infoList) {
+ mGnssExcessInfoList = new ArrayList<>(infoList);
return this;
}
@@ -512,9 +492,10 @@ public final class GnssSingleSatCorrection implements Parcelable {
mSatId,
mCarrierFrequencyHz,
mProbSatIsLos,
- mExcessPathLengthMeters,
- mExcessPathLengthUncertaintyMeters,
- mReflectingPlane);
+ mCombinedExcessPathLengthMeters,
+ mCombinedExcessPathLengthUncertaintyMeters,
+ mCombinedAttenuationDb,
+ mGnssExcessInfoList);
}
}
}
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index f1605f1ffe5d..033056cb2a69 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -132,31 +132,31 @@ public class Location implements Parcelable {
}
/**
- * Construct a new Location object that is copied from an existing one.
+ * Constructs a new location copied from the given location.
*/
- public Location(@NonNull Location l) {
- set(l);
+ public Location(@NonNull Location location) {
+ set(location);
}
/**
* Turns this location into a copy of the given location.
*/
- public void set(@NonNull Location l) {
- mFieldsMask = l.mFieldsMask;
- mProvider = l.mProvider;
- mTimeMs = l.mTimeMs;
- mElapsedRealtimeNs = l.mElapsedRealtimeNs;
- mElapsedRealtimeUncertaintyNs = l.mElapsedRealtimeUncertaintyNs;
- mLatitudeDegrees = l.mLatitudeDegrees;
- mLongitudeDegrees = l.mLongitudeDegrees;
- mHorizontalAccuracyMeters = l.mHorizontalAccuracyMeters;
- mAltitudeMeters = l.mAltitudeMeters;
- mAltitudeAccuracyMeters = l.mAltitudeAccuracyMeters;
- mSpeedMetersPerSecond = l.mSpeedMetersPerSecond;
- mSpeedAccuracyMetersPerSecond = l.mSpeedAccuracyMetersPerSecond;
- mBearingDegrees = l.mBearingDegrees;
- mBearingAccuracyDegrees = l.mBearingAccuracyDegrees;
- mExtras = (l.mExtras == null) ? null : new Bundle(l.mExtras);
+ public void set(@NonNull Location location) {
+ mFieldsMask = location.mFieldsMask;
+ mProvider = location.mProvider;
+ mTimeMs = location.mTimeMs;
+ mElapsedRealtimeNs = location.mElapsedRealtimeNs;
+ mElapsedRealtimeUncertaintyNs = location.mElapsedRealtimeUncertaintyNs;
+ mLatitudeDegrees = location.mLatitudeDegrees;
+ mLongitudeDegrees = location.mLongitudeDegrees;
+ mHorizontalAccuracyMeters = location.mHorizontalAccuracyMeters;
+ mAltitudeMeters = location.mAltitudeMeters;
+ mAltitudeAccuracyMeters = location.mAltitudeAccuracyMeters;
+ mSpeedMetersPerSecond = location.mSpeedMetersPerSecond;
+ mSpeedAccuracyMetersPerSecond = location.mSpeedAccuracyMetersPerSecond;
+ mBearingDegrees = location.mBearingDegrees;
+ mBearingAccuracyDegrees = location.mBearingAccuracyDegrees;
+ mExtras = (location.mExtras == null) ? null : new Bundle(location.mExtras);
}
/**
@@ -182,14 +182,13 @@ public class Location implements Parcelable {
}
/**
- * Returns the approximate distance in meters between this
- * location and the given location. Distance is defined using
- * the WGS84 ellipsoid.
+ * Returns the approximate distance in meters between this location and the given location.
+ * Distance is defined using the WGS84 ellipsoid.
*
* @param dest the destination location
* @return the approximate distance in meters
*/
- public @FloatRange float distanceTo(@NonNull Location dest) {
+ public @FloatRange(from = 0.0) float distanceTo(@NonNull Location dest) {
BearingDistanceCache cache = sBearingDistanceCache.get();
// See if we already have the result
if (mLatitudeDegrees != cache.mLat1 || mLongitudeDegrees != cache.mLon1
@@ -201,11 +200,10 @@ public class Location implements Parcelable {
}
/**
- * Returns the approximate initial bearing in degrees East of true
- * North when traveling along the shortest path between this
- * location and the given location. The shortest path is defined
- * using the WGS84 ellipsoid. Locations that are (nearly)
- * antipodal may produce meaningless results.
+ * Returns the approximate initial bearing in degrees east of true north when traveling along
+ * the shortest path between this location and the given location. The shortest path is defined
+ * using the WGS84 ellipsoid. Locations that are (nearly) antipodal may produce meaningless
+ * results.
*
* @param dest the destination location
* @return the initial bearing in degrees
@@ -254,7 +252,7 @@ public class Location implements Parcelable {
* not be used to order or compare locations. Prefer {@link #getElapsedRealtimeNanos} for that
* purpose, as the elapsed realtime clock is guaranteed to be monotonic.
*
- * <p>On the other hand, this method may be useful for presenting a human readable time to the
+ * <p>On the other hand, this method may be useful for presenting a human-readable time to the
* user, or as a heuristic for comparing location fixes across reboot or across devices.
*
* <p>All locations generated by the {@link LocationManager} are guaranteed to have this time
@@ -263,25 +261,24 @@ public class Location implements Parcelable {
*
* @return the Unix epoch time of this location
*/
- public @IntRange long getTime() {
+ public @IntRange(from = 0) long getTime() {
return mTimeMs;
}
/**
* Sets the Unix epoch time of this location fix, in milliseconds since the start of the Unix
- * epoch (00:00:00 January 1, 1970 UTC).
+ * epoch (00:00:00 January 1 1970 UTC).
*
* @param timeMs the Unix epoch time of this location
- * @see #getTime for more information about times / clocks
*/
- public void setTime(@IntRange long timeMs) {
+ public void setTime(@IntRange(from = 0) long timeMs) {
mTimeMs = timeMs;
}
/**
* Return the time of this fix in nanoseconds of elapsed realtime since system boot.
*
- * <p>This value can be compared with {@link android.os.SystemClock#elapsedRealtimeNanos}, to
+ * <p>This value can be compared with {@link android.os.SystemClock#elapsedRealtimeNanos} to
* reliably order or compare locations. This is reliable because elapsed realtime is guaranteed
* to be monotonic and continues to increment even when the system is in deep sleep (unlike
* {@link #getTime}). However, since elapsed realtime is with reference to system boot, it does
@@ -292,7 +289,7 @@ public class Location implements Parcelable {
*
* @return elapsed realtime of this location in nanoseconds
*/
- public @IntRange long getElapsedRealtimeNanos() {
+ public @IntRange(from = 0) long getElapsedRealtimeNanos() {
return mElapsedRealtimeNs;
}
@@ -302,7 +299,7 @@ public class Location implements Parcelable {
* @return elapsed realtime of this location in milliseconds
* @see #getElapsedRealtimeNanos()
*/
- public @IntRange long getElapsedRealtimeMillis() {
+ public @IntRange(from = 0) long getElapsedRealtimeMillis() {
return NANOSECONDS.toMillis(mElapsedRealtimeNs);
}
@@ -312,7 +309,7 @@ public class Location implements Parcelable {
*
* @return age of this location in milliseconds
*/
- public @IntRange long getElapsedRealtimeAgeMillis() {
+ public @IntRange(from = 0) long getElapsedRealtimeAgeMillis() {
return getElapsedRealtimeAgeMillis(SystemClock.elapsedRealtime());
}
@@ -323,7 +320,8 @@ public class Location implements Parcelable {
* @param referenceRealtimeMs reference realtime in milliseconds
* @return age of this location in milliseconds
*/
- public @IntRange long getElapsedRealtimeAgeMillis(@IntRange long referenceRealtimeMs) {
+ public long getElapsedRealtimeAgeMillis(
+ @IntRange(from = 0) long referenceRealtimeMs) {
return referenceRealtimeMs - getElapsedRealtimeMillis();
}
@@ -332,7 +330,7 @@ public class Location implements Parcelable {
*
* @param elapsedRealtimeNs elapsed realtime in nanoseconds
*/
- public void setElapsedRealtimeNanos(@IntRange long elapsedRealtimeNs) {
+ public void setElapsedRealtimeNanos(@IntRange(from = 0) long elapsedRealtimeNs) {
mElapsedRealtimeNs = elapsedRealtimeNs;
}
@@ -346,7 +344,7 @@ public class Location implements Parcelable {
*
* @return uncertainty in nanoseconds of the elapsed realtime of this location
*/
- public @FloatRange double getElapsedRealtimeUncertaintyNanos() {
+ public @FloatRange(from = 0.0) double getElapsedRealtimeUncertaintyNanos() {
return mElapsedRealtimeUncertaintyNs;
}
@@ -358,20 +356,20 @@ public class Location implements Parcelable {
* this location
*/
public void setElapsedRealtimeUncertaintyNanos(
- @FloatRange double elapsedRealtimeUncertaintyNs) {
+ @FloatRange(from = 0.0) double elapsedRealtimeUncertaintyNs) {
mElapsedRealtimeUncertaintyNs = elapsedRealtimeUncertaintyNs;
mFieldsMask |= HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
}
/**
- * True if this location has a elapsed realtime uncertainty, false otherwise.
+ * True if this location has an elapsed realtime uncertainty, false otherwise.
*/
public boolean hasElapsedRealtimeUncertaintyNanos() {
return (mFieldsMask & HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK) != 0;
}
/**
- * Removes the elapsed realtime uncertainy from this location.
+ * Removes the elapsed realtime uncertainty from this location.
*/
public void removeElapsedRealtimeUncertaintyNanos() {
mFieldsMask &= ~HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
@@ -383,7 +381,7 @@ public class Location implements Parcelable {
*
* @return latitude of this location
*/
- public @FloatRange double getLatitude() {
+ public @FloatRange(from = -90.0, to = 90.0) double getLatitude() {
return mLatitudeDegrees;
}
@@ -392,7 +390,7 @@ public class Location implements Parcelable {
*
* @param latitudeDegrees latitude in degrees
*/
- public void setLatitude(@FloatRange double latitudeDegrees) {
+ public void setLatitude(@FloatRange(from = -90.0, to = 90.0) double latitudeDegrees) {
mLatitudeDegrees = latitudeDegrees;
}
@@ -402,7 +400,7 @@ public class Location implements Parcelable {
*
* @return longitude of this location
*/
- public @FloatRange double getLongitude() {
+ public @FloatRange(from = -180.0, to = 180.0) double getLongitude() {
return mLongitudeDegrees;
}
@@ -411,7 +409,7 @@ public class Location implements Parcelable {
*
* @param longitudeDegrees longitude in degrees
*/
- public void setLongitude(@FloatRange double longitudeDegrees) {
+ public void setLongitude(@FloatRange(from = -180.0, to = 180.0) double longitudeDegrees) {
mLongitudeDegrees = longitudeDegrees;
}
@@ -423,12 +421,12 @@ public class Location implements Parcelable {
* reported location, there is a 68% chance that the true location falls within this circle.
* This accuracy value is only valid for horizontal positioning, and not vertical positioning.
*
- * <p>This is only valid if {@link #hasSpeed()} is true. All locations generated by the
+ * <p>This is only valid if {@link #hasAccuracy()} is true. All locations generated by the
* {@link LocationManager} include horizontal accuracy.
*
* @return horizontal accuracy of this location
*/
- public @FloatRange float getAccuracy() {
+ public @FloatRange(from = 0.0) float getAccuracy() {
return mHorizontalAccuracyMeters;
}
@@ -437,7 +435,7 @@ public class Location implements Parcelable {
*
* @param horizontalAccuracyMeters horizontal altitude in meters
*/
- public void setAccuracy(@FloatRange float horizontalAccuracyMeters) {
+ public void setAccuracy(@FloatRange(from = 0.0) float horizontalAccuracyMeters) {
mHorizontalAccuracyMeters = horizontalAccuracyMeters;
mFieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK;
}
@@ -500,7 +498,7 @@ public class Location implements Parcelable {
*
* @return vertical accuracy of this location
*/
- public @FloatRange float getVerticalAccuracyMeters() {
+ public @FloatRange(from = 0.0) float getVerticalAccuracyMeters() {
return mAltitudeAccuracyMeters;
}
@@ -509,7 +507,7 @@ public class Location implements Parcelable {
*
* @param altitudeAccuracyMeters altitude accuracy in meters
*/
- public void setVerticalAccuracyMeters(@FloatRange float altitudeAccuracyMeters) {
+ public void setVerticalAccuracyMeters(@FloatRange(from = 0.0) float altitudeAccuracyMeters) {
mAltitudeAccuracyMeters = altitudeAccuracyMeters;
mFieldsMask |= HAS_ALTITUDE_ACCURACY_MASK;
}
@@ -538,17 +536,16 @@ public class Location implements Parcelable {
*
* @return speed at the time of this location
*/
- public @FloatRange float getSpeed() {
+ public @FloatRange(from = 0.0) float getSpeed() {
return mSpeedMetersPerSecond;
}
/**
- * Set the speed at the time of this location, in meters per second. Prefer not to set negative
- * speeds.
+ * Set the speed at the time of this location, in meters per second.
*
* @param speedMetersPerSecond speed in meters per second
*/
- public void setSpeed(@FloatRange float speedMetersPerSecond) {
+ public void setSpeed(@FloatRange(from = 0.0) float speedMetersPerSecond) {
mSpeedMetersPerSecond = speedMetersPerSecond;
mFieldsMask |= HAS_SPEED_MASK;
}
@@ -576,7 +573,7 @@ public class Location implements Parcelable {
*
* @return vertical accuracy of this location
*/
- public @FloatRange float getSpeedAccuracyMetersPerSecond() {
+ public @FloatRange(from = 0.0) float getSpeedAccuracyMetersPerSecond() {
return mSpeedAccuracyMetersPerSecond;
}
@@ -585,7 +582,8 @@ public class Location implements Parcelable {
*
* @param speedAccuracyMeterPerSecond speed accuracy in meters per second
*/
- public void setSpeedAccuracyMetersPerSecond(@FloatRange float speedAccuracyMeterPerSecond) {
+ public void setSpeedAccuracyMetersPerSecond(
+ @FloatRange(from = 0.0) float speedAccuracyMeterPerSecond) {
mSpeedAccuracyMetersPerSecond = speedAccuracyMeterPerSecond;
mFieldsMask |= HAS_SPEED_ACCURACY_MASK;
}
@@ -613,7 +611,7 @@ public class Location implements Parcelable {
*
* @return bearing at the time of this location
*/
- public @FloatRange(from = 0f, to = 360f, toInclusive = false) float getBearing() {
+ public @FloatRange(from = 0.0, to = 360.0, toInclusive = false) float getBearing() {
return mBearingDegrees;
}
@@ -663,7 +661,7 @@ public class Location implements Parcelable {
*
* @return bearing accuracy in degrees of this location
*/
- public @FloatRange float getBearingAccuracyDegrees() {
+ public @FloatRange(from = 0.0) float getBearingAccuracyDegrees() {
return mBearingAccuracyDegrees;
}
@@ -672,7 +670,7 @@ public class Location implements Parcelable {
*
* @param bearingAccuracyDegrees bearing accuracy in degrees
*/
- public void setBearingAccuracyDegrees(@FloatRange float bearingAccuracyDegrees) {
+ public void setBearingAccuracyDegrees(@FloatRange(from = 0.0) float bearingAccuracyDegrees) {
mBearingAccuracyDegrees = bearingAccuracyDegrees;
mFieldsMask |= HAS_BEARING_ACCURACY_MASK;
}
@@ -692,9 +690,11 @@ public class Location implements Parcelable {
}
/**
- * Returns true if the Location came from a mock provider.
+ * Returns true if this is a mock location. If this location comes from the Android framework,
+ * this indicates that the location was provided by a test location provider, and thus may not
+ * be related to the actual location of the device.
*
- * @return true if this Location came from a mock provider, false otherwise
+ * @return true if this location came from a mock provider, false otherwise
* @deprecated Prefer {@link #isMock()} instead.
*/
@Deprecated
@@ -703,9 +703,9 @@ public class Location implements Parcelable {
}
/**
- * Flag this Location as having come from a mock provider or not.
+ * Flag this location as having come from a mock provider or not.
*
- * @param isFromMockProvider true if this Location came from a mock provider, false otherwise
+ * @param isFromMockProvider true if this location came from a mock provider, false otherwise
* @deprecated Prefer {@link #setMock(boolean)} instead.
* @hide
*/
@@ -745,7 +745,7 @@ public class Location implements Parcelable {
* will be present for any location.
*
* <ul>
- * <li> satellites - the number of satellites used to derive the GNSS fix
+ * <li> satellites - the number of satellites used to derive a GNSS fix
* </ul>
*/
public @Nullable Bundle getExtras() {
@@ -899,7 +899,13 @@ public class Location implements Parcelable {
return s.toString();
}
- /** Dumps location. */
+ /**
+ * Dumps location information to the given Printer.
+ *
+ * @deprecated Prefer to use {@link #toString()} along with whatever custom formatting is
+ * required instead of this method. It is not this class's job to manage print representations.
+ */
+ @Deprecated
public void dump(@NonNull Printer pw, @Nullable String prefix) {
pw.println(prefix + this);
}
@@ -1209,10 +1215,10 @@ public class Location implements Parcelable {
* @throws IllegalArgumentException if results is null or has length < 1
*/
public static void distanceBetween(
- @FloatRange double startLatitude,
- @FloatRange double startLongitude,
- @FloatRange double endLatitude,
- @FloatRange double endLongitude,
+ @FloatRange(from = -90.0, to = 90.0) double startLatitude,
+ @FloatRange(from = -180.0, to = 180.0) double startLongitude,
+ @FloatRange(from = -90.0, to = 90.0) double endLatitude,
+ @FloatRange(from = -180.0, to = 180.0) double endLongitude,
float[] results) {
if (results == null || results.length < 1) {
throw new IllegalArgumentException("results is null or has length < 1");
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index bdbb740a849b..c186700a4326 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -39,6 +39,7 @@ import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.ISpatializerCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
import android.media.ISpatializerOutputCallback;
@@ -414,6 +415,11 @@ interface IAudioService {
boolean isHeadTrackerEnabled(in AudioDeviceAttributes device);
+ boolean isHeadTrackerAvailable();
+
+ void registerSpatializerHeadTrackerAvailableCallback(
+ in ISpatializerHeadTrackerAvailableCallback cb, boolean register);
+
void setSpatializerEnabled(boolean enabled);
boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);
diff --git a/core/java/com/android/internal/logging/UiEvent.java b/media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl
index 0407b0704e80..dc5ee1d4e985 100644
--- a/core/java/com/android/internal/logging/UiEvent.java
+++ b/media/java/android/media/ISpatializerHeadTrackerAvailableCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,17 +14,14 @@
* limitations under the License.
*/
-package com.android.internal.logging;
+package android.media;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
+/**
+ * AIDL for the AudioService to signal whether audio device used by Spatializer has head tracker.
+ *
+ * {@hide}
+ */
+oneway interface ISpatializerHeadTrackerAvailableCallback {
-@Retention(SOURCE)
-@Target(FIELD)
-public @interface UiEvent {
- /** An explanation, suitable for Android analysts, of the UI event that this log represents. */
- String doc();
+ void dispatchSpatializerHeadTrackerAvailable(boolean available);
}
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index ec56d614f2b5..ad1405aa2356 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -25,7 +25,8 @@ import android.util.Log;
/**
* <p>A class for producing sounds that match those produced by various actions
- * taken by the media and camera APIs. </p>
+ * taken by the media and camera APIs. It is recommended to call methods in this class
+ * in a background thread since it relies on binder calls.</p>
*
* <p>This class is recommended for use with the {@link android.hardware.camera2} API, since the
* camera2 API does not play any sounds on its own for any capture or video recording actions.</p>
@@ -109,7 +110,7 @@ public class MediaActionSound {
/**
* <p>Returns true if the application must play the shutter sound in accordance
- * to certain regional restrictions. </p>
+ * to certain regional restrictions.</p>
*
* <p>If this method returns true, applications are strongly recommended to use
* MediaActionSound.play(SHUTTER_CLICK) or START_VIDEO_RECORDING whenever it captures
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 4563259c31f2..e39914db4d0f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -223,19 +223,19 @@ import java.util.concurrent.locks.ReentrantLock;
</thead>
<tbody>
<tr>
- <td>{@code "crop-left"}</td>
+ <td>{@link MediaFormat#KEY_CROP_LEFT}</td>
<td>Integer</td>
<td>The left-coordinate (x) of the crop rectangle</td>
</tr><tr>
- <td>{@code "crop-top"}</td>
+ <td>{@link MediaFormat#KEY_CROP_TOP}</td>
<td>Integer</td>
<td>The top-coordinate (y) of the crop rectangle</td>
</tr><tr>
- <td>{@code "crop-right"}</td>
+ <td>{@link MediaFormat#KEY_CROP_RIGHT}</td>
<td>Integer</td>
<td>The right-coordinate (x) <strong>MINUS 1</strong> of the crop rectangle</td>
</tr><tr>
- <td>{@code "crop-bottom"}</td>
+ <td>{@link MediaFormat#KEY_CROP_BOTTOM}</td>
<td>Integer</td>
<td>The bottom-coordinate (y) <strong>MINUS 1</strong> of the crop rectangle</td>
</tr><tr>
@@ -251,12 +251,16 @@ import java.util.concurrent.locks.ReentrantLock;
<pre class=prettyprint>
MediaFormat format = decoder.getOutputFormat(&hellip;);
int width = format.getInteger(MediaFormat.KEY_WIDTH);
- if (format.containsKey("crop-left") && format.containsKey("crop-right")) {
- width = format.getInteger("crop-right") + 1 - format.getInteger("crop-left");
+ if (format.containsKey(MediaFormat.KEY_CROP_LEFT)
+ && format.containsKey(MediaFormat.KEY_CROP_RIGHT)) {
+ width = format.getInteger(MediaFormat.KEY_CROP_RIGHT) + 1
+ - format.getInteger(MediaFormat.KEY_CROP_LEFT);
}
int height = format.getInteger(MediaFormat.KEY_HEIGHT);
- if (format.containsKey("crop-top") && format.containsKey("crop-bottom")) {
- height = format.getInteger("crop-bottom") + 1 - format.getInteger("crop-top");
+ if (format.containsKey(MediaFormat.KEY_CROP_TOP)
+ && format.containsKey(MediaFormat.KEY_CROP_BOTTOM)) {
+ height = format.getInteger(MediaFormat.KEY_CROP_BOTTOM) + 1
+ - format.getInteger(MediaFormat.KEY_CROP_TOP);
}
</pre>
<p class=note>
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 4956dbefa240..9dea5b9152b7 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -359,6 +359,42 @@ public final class MediaFormat {
public static final String KEY_HEIGHT = "height";
/**
+ * A key describing the bottom-coordinate (y) of the crop rectangle.
+ * This is the bottom-most row included in the crop frame,
+ * where row indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_BOTTOM = "crop-bottom";
+
+ /**
+ * A key describing the left-coordinate (x) of the crop rectangle.
+ * This is the left-most column included in the crop frame,
+ * where column indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_LEFT = "crop-left";
+
+ /**
+ * A key describing the right-coordinate (x) of the crop rectangle.
+ * This is the right-most column included in the crop frame,
+ * where column indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_RIGHT = "crop-right";
+
+ /**
+ * A key describing the top-coordinate (y) of the crop rectangle.
+ * This is the top-most row included in the crop frame,
+ * where row indices start at 0.
+ * Additional information on the crop rectangle semantics can be found at
+ * {@link android.media.MediaCodec}.
+ */
+ public static final String KEY_CROP_TOP = "crop-top";
+
+ /**
* A key describing the maximum expected width of the content in a video
* decoder format, in case there are resolution changes in the video content.
* The associated value is an integer
@@ -793,8 +829,11 @@ public final class MediaFormat {
* By default, the decoder will output the same number of channels as present in the encoded
* stream, if supported. Set this value to limit the number of output channels, and use
* the downmix information in the stream, if available.
- * <p>Values larger than the number of channels in the content to decode are ignored.
+ * <p>Values larger than the number of channels in the content to decode behave just
+ * like the actual channel count of the content (e.g. passing 99 for the decoding of 5.1 content
+ * will behave like using 6).
* <p>This key is only used during decoding.
+ * @deprecated Use the non-AAC-specific key {@link #KEY_MAX_OUTPUT_CHANNEL_COUNT} instead
*/
public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index ee0293d629b1..283a41a81057 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -539,6 +539,7 @@ public final class MediaRoute2Info implements Parcelable {
/**
* Gets the Deduplication ID of the route if available.
* @see RouteDiscoveryPreference#shouldRemoveDuplicates()
+ * @hide
*/
@NonNull
public Set<String> getDeduplicationIds() {
@@ -968,6 +969,7 @@ public final class MediaRoute2Info implements Parcelable {
* <p>
* If it's {@code null}, the route will not be removed.
* @see RouteDiscoveryPreference#shouldRemoveDuplicates()
+ * @hide
*/
@NonNull
public Builder setDeduplicationIds(@NonNull Set<String> id) {
diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java
index 0ba36feb4ce9..207460af140c 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -119,6 +119,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* first in the provided list will remain.
*
* @see #shouldRemoveDuplicates()
+ * @hide
*/
@NonNull
public List<String> getDeduplicationPackageOrder() {
@@ -130,6 +131,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* <p>
* If it's not empty, it will only discover routes from the provider whose package name
* belongs to the list.
+ * @hide
*/
@NonNull
public List<String> getAllowedPackages() {
@@ -151,6 +153,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* Gets whether duplicate routes removal is enabled.
*
* @see #getDeduplicationPackageOrder()
+ * @hide
*/
public boolean shouldRemoveDuplicates() {
return !mPackageOrder.isEmpty();
@@ -293,6 +296,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
* <p>
* If it's non-empty, media router only discovers route from the provider in the list.
* The default value is empty, which discovers routes from all providers.
+ * @hide
*/
@NonNull
public Builder setAllowedPackages(@NonNull List<String> allowedPackages) {
@@ -324,6 +328,7 @@ public final class RouteDiscoveryPreference implements Parcelable {
*
* @param packageOrder ordered list of package names used to remove duplicate routes, or an
* empty list if deduplication should not be enabled.
+ * @hide
*/
@NonNull
public Builder setDeduplicationPackageOrder(@NonNull List<String> packageOrder) {
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index be0ef37345ed..74ca4b858ff6 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -185,6 +185,45 @@ public class Spatializer {
return false;
}
+ /**
+ * Returns whether a head tracker is currently available for the audio device used by the
+ * spatializer effect.
+ * @return true if a head tracker is available and the effect is enabled, false otherwise.
+ * @see OnHeadTrackerAvailableListener
+ * @see #addOnHeadTrackerAvailableListener(Executor, OnHeadTrackerAvailableListener)
+ */
+ public boolean isHeadTrackerAvailable() {
+ try {
+ return mAm.getService().isHeadTrackerAvailable();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
+ * Adds a listener to be notified of changes to the availability of a head tracker.
+ * @param executor the {@code Executor} handling the callback
+ * @param listener the listener to receive availability updates
+ * @see #removeOnHeadTrackerAvailableListener(OnHeadTrackerAvailableListener)
+ */
+ public void addOnHeadTrackerAvailableListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OnHeadTrackerAvailableListener listener) {
+ mHeadTrackerListenerMgr.addListener(executor, listener,
+ "addOnHeadTrackerAvailableListener",
+ () -> new SpatializerHeadTrackerAvailableDispatcherStub());
+ }
+
+ /**
+ * Removes a previously registered listener for the availability of a head tracker.
+ * @param listener the listener previously registered with
+ * {@link #addOnHeadTrackerAvailableListener(Executor, OnHeadTrackerAvailableListener)}
+ */
+ public void removeOnHeadTrackerAvailableListener(
+ @NonNull OnHeadTrackerAvailableListener listener) {
+ mHeadTrackerListenerMgr.removeListener(listener, "removeOnHeadTrackerAvailableListener");
+ }
+
/** @hide */
@IntDef(flag = false, value = {
SPATIALIZER_IMMERSIVE_LEVEL_OTHER,
@@ -401,6 +440,22 @@ public class Spatializer {
@HeadTrackingModeSet int mode);
}
+ /**
+ * Interface to be notified of changes to the availability of a head tracker on the audio
+ * device to be used by the spatializer effect.
+ */
+ public interface OnHeadTrackerAvailableListener {
+ /**
+ * Called when the availability of the head tracker changed.
+ * @param spatializer the {@code Spatializer} instance for which the head tracker
+ * availability was updated
+ * @param available true if the audio device that would output audio processed by
+ * the {@code Spatializer} has a head tracker associated with it, false
+ * otherwise.
+ */
+ void onHeadTrackerAvailableChanged(@NonNull Spatializer spatializer,
+ boolean available);
+ }
/**
* @hide
@@ -827,8 +882,12 @@ public class Spatializer {
/**
* @hide
- * Returns the id of the output stream used for the spatializer effect playback
+ * Returns the id of the output stream used for the spatializer effect playback.
+ * This getter or associated listener {@link OnSpatializerOutputChangedListener} can be used for
+ * handling spatializer output-specific configurations (e.g. disabling speaker post-processing
+ * to avoid double-processing of the spatialized path).
* @return id of the output stream, or 0 if no spatializer playback is active
+ * @see #setOnSpatializerOutputChangedListener(Executor, OnSpatializerOutputChangedListener)
*/
@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
@RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
@@ -865,6 +924,8 @@ public class Spatializer {
mOutputDispatcher = new SpatializerOutputDispatcherStub();
try {
mAm.getService().registerSpatializerOutputCallback(mOutputDispatcher);
+ // immediately report the current output
+ mOutputDispatcher.dispatchSpatializerOutputChanged(getOutput());
} catch (RemoteException e) {
mOutputListener = null;
mOutputDispatcher = null;
@@ -935,6 +996,36 @@ public class Spatializer {
}
//-----------------------------------------------------------------------------
+ // head tracker availability callback management and stub
+ /**
+ * manages the OnHeadTrackerAvailableListener listeners and the
+ * SpatializerHeadTrackerAvailableDispatcherStub
+ */
+ private final CallbackUtil.LazyListenerManager<OnHeadTrackerAvailableListener>
+ mHeadTrackerListenerMgr = new CallbackUtil.LazyListenerManager();
+
+ private final class SpatializerHeadTrackerAvailableDispatcherStub
+ extends ISpatializerHeadTrackerAvailableCallback.Stub
+ implements CallbackUtil.DispatcherStub {
+ @Override
+ public void register(boolean register) {
+ try {
+ mAm.getService().registerSpatializerHeadTrackerAvailableCallback(this, register);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ @SuppressLint("GuardedBy") // lock applied inside callListeners method
+ public void dispatchSpatializerHeadTrackerAvailable(boolean available) {
+ mHeadTrackerListenerMgr.callListeners(
+ (listener) -> listener.onHeadTrackerAvailableChanged(
+ Spatializer.this, available));
+ }
+ }
+
+ //-----------------------------------------------------------------------------
// head pose callback management and stub
private final Object mPoseListenerLock = new Object();
/**
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 19fc0521d7aa..b136d5bc4db3 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -17,6 +17,7 @@
package android.media.projection;
import android.media.projection.IMediaProjectionCallback;
+import android.window.WindowContainerToken;
/** {@hide} */
interface IMediaProjection {
@@ -28,4 +29,16 @@ interface IMediaProjection {
int applyVirtualDisplayFlags(int flags);
void registerCallback(IMediaProjectionCallback callback);
void unregisterCallback(IMediaProjectionCallback callback);
+
+ /**
+ * Returns the {@link android.window.WindowContainerToken} identifying the task to record, or
+ * {@code null} if there is none.
+ */
+ WindowContainerToken getTaskRecordingWindowContainerToken();
+
+ /**
+ * Updates the {@link android.window.WindowContainerToken} identifying the task to record, or
+ * {@code null} if there is none.
+ */
+ void setTaskRecordingWindowContainerToken(in WindowContainerToken token);
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 4dde5e8d39a2..b5f95938f845 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -25,13 +25,14 @@ import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import android.view.ContentRecordingSession;
+import android.view.IWindowManager;
import android.view.Surface;
import android.view.WindowManagerGlobal;
+import android.window.WindowContainerToken;
import java.util.Map;
@@ -171,16 +172,34 @@ public final class MediaProjection {
@NonNull VirtualDisplayConfig.Builder virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
try {
- final Context windowContext = mContext.createWindowContext(
- mContext.getDisplayNoVerify(),
- TYPE_APPLICATION, null /* options */);
- final IBinder windowContextToken = windowContext.getWindowContextToken();
+ final IWindowManager wmService = WindowManagerGlobal.getWindowManagerService();
+ final WindowContainerToken taskWindowContainerToken =
+ mImpl.getTaskRecordingWindowContainerToken();
+ Context windowContext = null;
+ ContentRecordingSession session;
+ if (taskWindowContainerToken == null) {
+ windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+ TYPE_APPLICATION, null /* options */);
+ session = ContentRecordingSession.createDisplaySession(
+ windowContext.getWindowContextToken());
+ } else {
+ session = ContentRecordingSession.createTaskSession(
+ taskWindowContainerToken.asBinder());
+ }
virtualDisplayConfig.setWindowManagerMirroring(true);
final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this,
- virtualDisplayConfig.build(),
- callback, handler, windowContext);
- setSession(windowContextToken, virtualDisplay);
+ virtualDisplayConfig.build(), callback, handler, windowContext);
+ if (virtualDisplay == null) {
+ // Since WM handling a new display and DM creating a new VirtualDisplay is async,
+ // WM may have tried to start task recording and encountered an error that required
+ // stopping recording entirely. The VirtualDisplay would then be null when the
+ // MediaProjection is no longer active.
+ return null;
+ }
+ session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
+ // Successfully set up, so save the current session details.
+ wmService.setContentRecordingSession(session);
return virtualDisplay;
} catch (RemoteException e) {
// Can not capture if WMS is not accessible, so bail out.
@@ -189,28 +208,6 @@ public final class MediaProjection {
}
/**
- * Updates the {@link ContentRecordingSession} describing the recording taking place on this
- * {@link VirtualDisplay}.
- *
- * @throws RemoteException if updating the session on the server failed.
- */
- private void setSession(@NonNull IBinder windowContextToken,
- @Nullable VirtualDisplay virtualDisplay)
- throws RemoteException {
- if (virtualDisplay == null) {
- // Not able to set up a new VirtualDisplay.
- return;
- }
- // Identify the VirtualDisplay that will be hosting the recording.
- ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
- windowContextToken);
- session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
- // TODO(b/216625226) handle task recording.
- // Successfully set up, so save the current session details.
- WindowManagerGlobal.getWindowManagerService().setContentRecordingSession(session);
- }
-
- /**
* Stops projection.
*/
public void stop() {
diff --git a/media/java/android/media/tv/AdRequest.java b/media/java/android/media/tv/AdRequest.java
index 0542c5598c01..f2fb93d803a8 100644
--- a/media/java/android/media/tv/AdRequest.java
+++ b/media/java/android/media/tv/AdRequest.java
@@ -163,7 +163,11 @@ public final class AdRequest implements Parcelable {
/**
* Gets the metadata of the media file.
- * <p>This includes additional information the TV input needs to play the AD media.
+ *
+ * <p>This includes additional information the TV input needs to play the AD media. This may
+ * include fields in {@link android.media.MediaFormat} like
+ * {@link android.media.MediaFormat#KEY_SAMPLE_RATE}, or integrity information like SHA. What
+ * data is included depends on the format of the media file.
*
* @return The metadata of the media file. Can be an empty bundle for
* {@link #REQUEST_TYPE_STOP}.
diff --git a/media/java/android/media/tv/AitInfo.java b/media/java/android/media/tv/AitInfo.java
index 8e80a62be3de..c88a2b5048df 100644
--- a/media/java/android/media/tv/AitInfo.java
+++ b/media/java/android/media/tv/AitInfo.java
@@ -17,7 +17,7 @@
package android.media.tv;
import android.annotation.NonNull;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
import android.os.Parcel;
import android.os.Parcelable;
@@ -50,7 +50,7 @@ public final class AitInfo implements Parcelable {
/**
* Constructs AIT info.
*/
- public AitInfo(@TvInteractiveAppInfo.InteractiveAppType int type, int version) {
+ public AitInfo(@TvInteractiveAppServiceInfo.InteractiveAppType int type, int version) {
mType = type;
mVersion = version;
}
@@ -58,7 +58,7 @@ public final class AitInfo implements Parcelable {
/**
* Gets interactive app type.
*/
- @TvInteractiveAppInfo.InteractiveAppType
+ @TvInteractiveAppServiceInfo.InteractiveAppType
public int getType() {
return mType;
}
diff --git a/media/java/android/media/tv/CommandRequest.java b/media/java/android/media/tv/CommandRequest.java
index ffb6e07bc485..3245fb504f85 100644
--- a/media/java/android/media/tv/CommandRequest.java
+++ b/media/java/android/media/tv/CommandRequest.java
@@ -24,6 +24,8 @@ import android.os.Parcelable;
* A request for command from broadcast signal.
*/
public final class CommandRequest extends BroadcastInfoRequest implements Parcelable {
+ public static final String ARGUMENT_TYPE_XML = "xml";
+ public static final String ARGUMENT_TYPE_JSON = "json";
private static final @TvInputManager.BroadcastInfoType int REQUEST_TYPE =
TvInputManager.BROADCAST_INFO_TYPE_COMMAND;
@@ -41,35 +43,38 @@ public final class CommandRequest extends BroadcastInfoRequest implements Parcel
}
};
- private final String mNameSpace;
+ private final String mNamespace;
private final String mName;
private final String mArguments;
+ private final String mArgumentType;
static CommandRequest createFromParcelBody(Parcel in) {
return new CommandRequest(in);
}
- public CommandRequest(int requestId, @RequestOption int option, @NonNull String nameSpace,
- @NonNull String name, @NonNull String arguments) {
+ public CommandRequest(int requestId, @RequestOption int option, @NonNull String namespace,
+ @NonNull String name, @NonNull String arguments, @NonNull String argumentType) {
super(REQUEST_TYPE, requestId, option);
- mNameSpace = nameSpace;
+ mNamespace = namespace;
mName = name;
mArguments = arguments;
+ mArgumentType = argumentType;
}
CommandRequest(Parcel source) {
super(REQUEST_TYPE, source);
- mNameSpace = source.readString();
+ mNamespace = source.readString();
mName = source.readString();
mArguments = source.readString();
+ mArgumentType = source.readString();
}
/**
* Gets the namespace of the command.
*/
@NonNull
- public String getNameSpace() {
- return mNameSpace;
+ public String getNamespace() {
+ return mNamespace;
}
/**
@@ -89,6 +94,15 @@ public final class CommandRequest extends BroadcastInfoRequest implements Parcel
return mArguments;
}
+ /**
+ * Gets the argument type of the command.
+ * It could be either JSON or XML.
+ */
+ @NonNull
+ public String getArgumentType() {
+ return mArgumentType;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -97,8 +111,9 @@ public final class CommandRequest extends BroadcastInfoRequest implements Parcel
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
- dest.writeString(mNameSpace);
+ dest.writeString(mNamespace);
dest.writeString(mName);
dest.writeString(mArguments);
+ dest.writeString(mArgumentType);
}
}
diff --git a/media/java/android/media/tv/CommandResponse.java b/media/java/android/media/tv/CommandResponse.java
index c8853f1d8373..8e448cdbd707 100644
--- a/media/java/android/media/tv/CommandResponse.java
+++ b/media/java/android/media/tv/CommandResponse.java
@@ -25,6 +25,8 @@ import android.os.Parcelable;
* A response for command from broadcast signal.
*/
public final class CommandResponse extends BroadcastInfoResponse implements Parcelable {
+ public static final String RESPONSE_TYPE_XML = "xml";
+ public static final String RESPONSE_TYPE_JSON = "json";
private static final @TvInputManager.BroadcastInfoType int RESPONSE_TYPE =
TvInputManager.BROADCAST_INFO_TYPE_COMMAND;
@@ -43,20 +45,23 @@ public final class CommandResponse extends BroadcastInfoResponse implements Parc
};
private final String mResponse;
+ private final String mResponseType;
static CommandResponse createFromParcelBody(Parcel in) {
return new CommandResponse(in);
}
- public CommandResponse(int requestId, int sequence,
- @ResponseResult int responseResult, @Nullable String response) {
+ public CommandResponse(int requestId, int sequence, @ResponseResult int responseResult,
+ @Nullable String response, @NonNull String responseType) {
super(RESPONSE_TYPE, requestId, sequence, responseResult);
mResponse = response;
+ mResponseType = responseType;
}
CommandResponse(Parcel source) {
super(RESPONSE_TYPE, source);
mResponse = source.readString();
+ mResponseType = source.readString();
}
/**
@@ -68,6 +73,15 @@ public final class CommandResponse extends BroadcastInfoResponse implements Parc
return mResponse;
}
+ /**
+ * Gets the type of the command response.
+ * It could be either JSON or XML.
+ */
+ @NonNull
+ public String getResponseType() {
+ return mResponseType;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -77,5 +91,6 @@ public final class CommandResponse extends BroadcastInfoResponse implements Parc
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(mResponse);
+ dest.writeString(mResponseType);
}
}
diff --git a/media/java/android/media/tv/SectionRequest.java b/media/java/android/media/tv/SectionRequest.java
index 5957528554dc..078e83222e4e 100644
--- a/media/java/android/media/tv/SectionRequest.java
+++ b/media/java/android/media/tv/SectionRequest.java
@@ -80,6 +80,11 @@ public final class SectionRequest extends BroadcastInfoRequest implements Parcel
/**
* Gets the version number of requested session. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/SectionResponse.java b/media/java/android/media/tv/SectionResponse.java
index 35836bed385f..f38ea9dfac99 100644
--- a/media/java/android/media/tv/SectionResponse.java
+++ b/media/java/android/media/tv/SectionResponse.java
@@ -74,14 +74,20 @@ public final class SectionResponse extends BroadcastInfoResponse implements Parc
}
/**
- * Gets the Version number of requested session.
+ * Gets the Version number of requested session. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
}
/**
- * Gets the raw data of session.
+ * Gets the raw data of session. The sessionData field represents payload data of the session
+ * after session header, which includes version and sessionId.
*/
@NonNull
public Bundle getSessionData() {
diff --git a/media/java/android/media/tv/StreamEventResponse.java b/media/java/android/media/tv/StreamEventResponse.java
index f952ce929842..28dff374d539 100644
--- a/media/java/android/media/tv/StreamEventResponse.java
+++ b/media/java/android/media/tv/StreamEventResponse.java
@@ -43,7 +43,7 @@ public final class StreamEventResponse extends BroadcastInfoResponse implements
};
private final int mEventId;
- private final long mNpt;
+ private final long mNptMillis;
private final byte[] mData;
static StreamEventResponse createFromParcelBody(Parcel in) {
@@ -51,17 +51,17 @@ public final class StreamEventResponse extends BroadcastInfoResponse implements
}
public StreamEventResponse(int requestId, int sequence, @ResponseResult int responseResult,
- int eventId, long npt, @Nullable byte[] data) {
+ int eventId, long nptMillis, @Nullable byte[] data) {
super(RESPONSE_TYPE, requestId, sequence, responseResult);
mEventId = eventId;
- mNpt = npt;
+ mNptMillis = nptMillis;
mData = data;
}
private StreamEventResponse(@NonNull Parcel source) {
super(RESPONSE_TYPE, source);
mEventId = source.readInt();
- mNpt = source.readLong();
+ mNptMillis = source.readLong();
int dataLength = source.readInt();
mData = new byte[dataLength];
source.readByteArray(mData);
@@ -76,9 +76,10 @@ public final class StreamEventResponse extends BroadcastInfoResponse implements
/**
* Returns the NPT(Normal Play Time) value when the event occurred or will occur.
+ * <p>The time unit of NPT is millisecond.
*/
- public long getNpt() {
- return mNpt;
+ public long getNptMillis() {
+ return mNptMillis;
}
/**
@@ -98,7 +99,7 @@ public final class StreamEventResponse extends BroadcastInfoResponse implements
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(mEventId);
- dest.writeLong(mNpt);
+ dest.writeLong(mNptMillis);
dest.writeInt(mData.length);
dest.writeByteArray(mData);
}
diff --git a/media/java/android/media/tv/TableRequest.java b/media/java/android/media/tv/TableRequest.java
index 37df4eaf1ed0..a1a6b516859c 100644
--- a/media/java/android/media/tv/TableRequest.java
+++ b/media/java/android/media/tv/TableRequest.java
@@ -91,7 +91,12 @@ public final class TableRequest extends BroadcastInfoRequest implements Parcelab
}
/**
- * Gets the version number of requested table.
+ * Gets the version number of requested table. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/TableResponse.java b/media/java/android/media/tv/TableResponse.java
index e9f1136875f5..afc9bee5fb85 100644
--- a/media/java/android/media/tv/TableResponse.java
+++ b/media/java/android/media/tv/TableResponse.java
@@ -76,7 +76,12 @@ public final class TableResponse extends BroadcastInfoResponse implements Parcel
}
/**
- * Gets the Version number of table.
+ * Gets the version number of requested table. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/TimelineResponse.java b/media/java/android/media/tv/TimelineResponse.java
index fbeb0c4bf268..7de30f579a35 100644
--- a/media/java/android/media/tv/TimelineResponse.java
+++ b/media/java/android/media/tv/TimelineResponse.java
@@ -18,6 +18,7 @@ package android.media.tv;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -79,8 +80,8 @@ public final class TimelineResponse extends BroadcastInfoResponse implements Par
* that conveys Time Values on it.
*/
@Nullable
- public String getSelector() {
- return mSelector;
+ public Uri getSelector() {
+ return Uri.parse(mSelector);
}
/**
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 69fe5ee49872..149c2f471a4c 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -680,7 +680,7 @@ public final class TvInputManager {
* @param session A {@link TvInputManager.Session} associated with this callback.
* @param strength The current signal strength.
*/
- public void onSignalStrength(Session session, @SignalStrength int strength) {
+ public void onSignalStrengthUpdated(Session session, @SignalStrength int strength) {
}
/**
@@ -898,7 +898,7 @@ public final class TvInputManager {
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCallback.onSignalStrength(mSession, strength);
+ mSessionCallback.onSignalStrengthUpdated(mSession, strength);
if (mSession.mIAppNotificationEnabled
&& mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifySignalStrength(strength);
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 4d63af7be474..ff3d06c5bd69 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -1083,7 +1083,7 @@ public class TvView extends ViewGroup {
* @param inputId The ID of the TV input bound to this view.
* @param strength The current signal strength.
*/
- public void onSignalStrength(
+ public void onSignalStrengthUpdated(
@NonNull String inputId, @TvInputManager.SignalStrength int strength) {
}
@@ -1406,16 +1406,16 @@ public class TvView extends ViewGroup {
}
@Override
- public void onSignalStrength(Session session, int strength) {
+ public void onSignalStrengthUpdated(Session session, int strength) {
if (DEBUG) {
- Log.d(TAG, "onSignalStrength(strength=" + strength + ")");
+ Log.d(TAG, "onSignalStrengthUpdated(strength=" + strength + ")");
}
if (this != mSessionCallback) {
- Log.w(TAG, "onSignalStrength - session not created");
+ Log.w(TAG, "onSignalStrengthUpdated - session not created");
return;
}
if (mCallback != null) {
- mCallback.onSignalStrength(mInputId, strength);
+ mCallback.onSignalStrengthUpdated(mInputId, strength);
}
}
diff --git a/media/java/android/media/tv/interactive/AppLinkInfo.aidl b/media/java/android/media/tv/interactive/AppLinkInfo.aidl
index 6759fc499e1c..f551c9fcf6c7 100644
--- a/media/java/android/media/tv/interactive/AppLinkInfo.aidl
+++ b/media/java/android/media/tv/interactive/AppLinkInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/AppLinkInfo.java b/media/java/android/media/tv/interactive/AppLinkInfo.java
index 0eb6fa8996d6..d5e995cbcfab 100644
--- a/media/java/android/media/tv/interactive/AppLinkInfo.java
+++ b/media/java/android/media/tv/interactive/AppLinkInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -17,8 +17,8 @@
package android.media.tv.interactive;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.ComponentName;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,68 +27,41 @@ import android.os.Parcelable;
*/
public final class AppLinkInfo implements Parcelable {
private @NonNull ComponentName mComponentName;
- private @Nullable String mUriScheme;
- private @Nullable String mUriHost;
- private @Nullable String mUriPrefix;
-
+ private @NonNull Uri mUri;
/**
* Creates a new AppLinkInfo.
+ *
+ * @param packageName Package Name of AppLinkInfo.
+ * @param className Class Name of AppLinkInfo.
+ * @param uriString Uri of AppLinkInfo.
*/
- private AppLinkInfo(
+ public AppLinkInfo(
@NonNull String packageName,
@NonNull String className,
- @Nullable String uriScheme,
- @Nullable String uriHost,
- @Nullable String uriPrefix) {
+ @NonNull String uriString) {
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, packageName);
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, className);
this.mComponentName = new ComponentName(packageName, className);
- this.mUriScheme = uriScheme;
- this.mUriHost = uriHost;
- this.mUriPrefix = uriPrefix;
+ this.mUri = Uri.parse(uriString);
}
/**
- * Gets package name of the App link.
+ * Gets component name of the App link, which contains package name and class name.
*/
@NonNull
- public String getPackageName() {
- return mComponentName.getPackageName();
+ public ComponentName getComponentName() {
+ return mComponentName;
}
/**
- * Gets package class of the App link.
+ * Gets URI of the App link.
*/
@NonNull
- public String getClassName() {
- return mComponentName.getClassName();
- }
-
- /**
- * Gets URI scheme of the App link.
- */
- @Nullable
- public String getUriScheme() {
- return mUriScheme;
- }
-
- /**
- * Gets URI host of the App link.
- */
- @Nullable
- public String getUriHost() {
- return mUriHost;
- }
-
- /**
- * Gets URI prefix of the App link.
- */
- @Nullable
- public String getUriPrefix() {
- return mUriPrefix;
+ public Uri getUri() {
+ return mUri;
}
@Override
@@ -96,19 +69,15 @@ public final class AppLinkInfo implements Parcelable {
return "AppLinkInfo { "
+ "packageName = " + mComponentName.getPackageName() + ", "
+ "className = " + mComponentName.getClassName() + ", "
- + "uriScheme = " + mUriScheme + ", "
- + "uriHost = " + mUriHost + ", "
- + "uriPrefix = " + mUriPrefix
+ + "uri = " + mUri.toString()
+ " }";
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeString(mComponentName.getPackageName());
- dest.writeString(mComponentName.getClassName());
- dest.writeString(mUriScheme);
- dest.writeString(mUriHost);
- dest.writeString(mUriPrefix);
+ mComponentName.writeToParcel(dest, flags);
+ String uriString = mUri == null ? null : mUri.toString();
+ dest.writeString(uriString);
}
@Override
@@ -117,20 +86,13 @@ public final class AppLinkInfo implements Parcelable {
}
/* package-private */ AppLinkInfo(@NonNull Parcel in) {
- String packageName = in.readString();
- String className = in.readString();
- String uriScheme = in.readString();
- String uriHost = in.readString();
- String uriPrefix = in.readString();
-
+ mComponentName = ComponentName.readFromParcel(in);
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, packageName);
+ NonNull.class, null, mComponentName.getPackageName());
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, className);
- this.mComponentName = new ComponentName(packageName, className);
- this.mUriScheme = uriScheme;
- this.mUriHost = uriHost;
- this.mUriPrefix = uriPrefix;
+ NonNull.class, null, mComponentName.getClassName());
+ String uriString = in.readString();
+ mUri = uriString == null ? null : Uri.parse(uriString);
}
@NonNull
@@ -146,68 +108,4 @@ public final class AppLinkInfo implements Parcelable {
return new AppLinkInfo(in);
}
};
-
- /**
- * A builder for {@link AppLinkInfo}
- */
- public static final class Builder {
- private @NonNull String mPackageName;
- private @NonNull String mClassName;
- private @Nullable String mUriScheme;
- private @Nullable String mUriHost;
- private @Nullable String mUriPrefix;
-
- /**
- * Creates a new Builder.
- */
- public Builder(
- @NonNull String packageName,
- @NonNull String className) {
- mPackageName = packageName;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPackageName);
- mClassName = className;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mClassName);
- }
-
- /**
- * Sets URI scheme of the App link.
- */
- @NonNull
- public Builder setUriScheme(@NonNull String value) {
- mUriScheme = value;
- return this;
- }
-
- /**
- * Sets URI host of the App link.
- */
- @NonNull
- public Builder setUriHost(@NonNull String value) {
- mUriHost = value;
- return this;
- }
-
- /**
- * Sets URI prefix of the App link.
- */
- @NonNull
- public Builder setUriPrefix(@NonNull String value) {
- mUriPrefix = value;
- return this;
- }
-
- /** Builds the instance. This builder should not be touched after calling this! */
- @NonNull
- public AppLinkInfo build() {
- AppLinkInfo o = new AppLinkInfo(
- mPackageName,
- mClassName,
- mUriScheme,
- mUriHost,
- mUriPrefix);
- return o;
- }
- }
}
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index a3e58d16f655..50aa6febacf7 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -44,5 +44,7 @@ oneway interface ITvInteractiveAppClient {
void onRequestStreamVolume(int seq);
void onRequestTrackInfoList(int seq);
void onRequestCurrentTvInputId(int seq);
+ void onRequestSigning(
+ in String id, in String algorithm, in String alias, in byte[] data, int seq);
void onAdRequest(in AdRequest request, int Seq);
}
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index aaabe342d9f1..9ff564ea3737 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -23,7 +23,7 @@ import android.media.tv.TvTrackInfo;
import android.media.tv.interactive.AppLinkInfo;
import android.media.tv.interactive.ITvInteractiveAppClient;
import android.media.tv.interactive.ITvInteractiveAppManagerCallback;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
import android.net.Uri;
import android.os.Bundle;
import android.view.Surface;
@@ -33,8 +33,7 @@ import android.view.Surface;
* @hide
*/
interface ITvInteractiveAppManager {
- List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId);
- void prepare(String tiasId, int type, int userId);
+ List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList(int userId);
void registerAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
void unregisterAppLinkInfo(String tiasId, in AppLinkInfo info, int userId);
void sendAppLinkCommand(String tiasId, in Bundle command, int userId);
@@ -50,6 +49,8 @@ interface ITvInteractiveAppManager {
void sendStreamVolume(in IBinder sessionToken, float volume, int userId);
void sendTrackInfoList(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId);
void sendCurrentTvInputId(in IBinder sessionToken, in String inputId, int userId);
+ void sendSigningResult(in IBinder sessionToken, in String signingId, in byte[] result,
+ int userId);
void createSession(in ITvInteractiveAppClient client, in String iAppServiceId, int type,
int seq, int userId);
void releaseSession(in IBinder sessionToken, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
index 23be4c64fcc4..fed86dc9e0a8 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManagerCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -16,7 +16,7 @@
package android.media.tv.interactive;
-import android.media.tv.interactive.TvInteractiveAppInfo;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
/**
* Interface to receive callbacks from ITvInteractiveAppManager regardless of sessions.
@@ -26,6 +26,6 @@ interface ITvInteractiveAppManagerCallback {
void onInteractiveAppServiceAdded(in String iAppServiceId);
void onInteractiveAppServiceRemoved(in String iAppServiceId);
void onInteractiveAppServiceUpdated(in String iAppServiceId);
- void onTvInteractiveAppInfoUpdated(in TvInteractiveAppInfo tvIAppInfo);
+ void onTvInteractiveAppServiceInfoUpdated(in TvInteractiveAppServiceInfo tvIAppInfo);
void onStateChanged(in String iAppServiceId, int type, int state, int err);
} \ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
index b6d518ff7242..fb58ca7843ef 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppService.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -32,7 +32,6 @@ oneway interface ITvInteractiveAppService {
void unregisterCallback(in ITvInteractiveAppServiceCallback callback);
void createSession(in InputChannel channel, in ITvInteractiveAppSessionCallback callback,
in String iAppServiceId, int type);
- void prepare(int type);
void registerAppLinkInfo(in AppLinkInfo info);
void unregisterAppLinkInfo(in AppLinkInfo info);
void sendAppLinkCommand(in Bundle command);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
index 970b94327572..87b3c1df6197 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppServiceCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index c449d2475428..e14b2bb18ea6 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -42,6 +42,7 @@ oneway interface ITvInteractiveAppSession {
void sendStreamVolume(float volume);
void sendTrackInfoList(in List<TvTrackInfo> tracks);
void sendCurrentTvInputId(in String inputId);
+ void sendSigningResult(in String signingId, in byte[] result);
void release();
void notifyTuned(in Uri channelUri);
void notifyTrackSelected(int type, in String trackId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index 385f0d4f766a..32b08b7042fe 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -43,5 +43,6 @@ oneway interface ITvInteractiveAppSessionCallback {
void onRequestStreamVolume();
void onRequestTrackInfoList();
void onRequestCurrentTvInputId();
+ void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data);
void onAdRequest(in AdRequest request);
}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 9eb4a6c393ab..d3cbcdc9a255 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -28,7 +28,6 @@ import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvContentRating;
-import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.media.tv.TvTrackInfo;
import android.net.Uri;
@@ -249,7 +248,7 @@ public final class TvInteractiveAppManager {
*
* @see #sendAppLinkCommand(String, Bundle)
* @see #ACTION_APP_LINK_COMMAND
- * @see android.media.tv.interactive.TvInteractiveAppInfo#getId()
+ * @see TvInteractiveAppServiceInfo#getId()
*/
public static final String INTENT_KEY_INTERACTIVE_APP_SERVICE_ID = "interactive_app_id";
@@ -269,7 +268,7 @@ public final class TvInteractiveAppManager {
*
* @see #sendAppLinkCommand(String, Bundle)
* @see #ACTION_APP_LINK_COMMAND
- * @see android.media.tv.interactive.TvInteractiveAppInfo#getSupportedTypes()
+ * @see android.media.tv.interactive.TvInteractiveAppServiceInfo#getSupportedTypes()
* @see android.media.tv.interactive.TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
*/
public static final String INTENT_KEY_BI_INTERACTIVE_APP_TYPE = "bi_interactive_app_type";
@@ -285,6 +284,16 @@ public final class TvInteractiveAppManager {
*/
public static final String INTENT_KEY_BI_INTERACTIVE_APP_URI = "bi_interactive_app_uri";
+ /**
+ * Intent key for command type. It's used to send app command to TV app. The value of this key
+ * could vary according to TV apps.
+ * <p>Type: String
+ *
+ * @see #sendAppLinkCommand(String, Bundle)
+ * @see #ACTION_APP_LINK_COMMAND
+ */
+ public static final String INTENT_KEY_COMMAND_TYPE = "command_type";
+
private final ITvInteractiveAppManager mService;
private final int mUserId;
@@ -478,6 +487,19 @@ public final class TvInteractiveAppManager {
}
@Override
+ public void onRequestSigning(
+ String id, String algorithm, String alias, byte[] data, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRequestSigning(id, algorithm, alias, data);
+ }
+ }
+
+ @Override
public void onSessionStateChanged(int state, int err, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -543,11 +565,11 @@ public final class TvInteractiveAppManager {
}
@Override
- public void onTvInteractiveAppInfoUpdated(TvInteractiveAppInfo iAppInfo) {
+ public void onTvInteractiveAppServiceInfoUpdated(TvInteractiveAppServiceInfo iAppInfo) {
// TODO: add public API updateInteractiveAppInfo()
synchronized (mLock) {
for (TvInteractiveAppCallbackRecord record : mCallbackRecords) {
- record.postTvInteractiveAppInfoUpdated(iAppInfo);
+ record.postTvInteractiveAppServiceInfoUpdated(iAppInfo);
}
}
}
@@ -611,16 +633,17 @@ public final class TvInteractiveAppManager {
* This is called when the information about an existing TV Interactive App service has been
* updated.
*
- * <p>Because the system automatically creates a <code>TvInteractiveAppInfo</code> object
- * for each TV Interactive App service based on the information collected from the
+ * <p>Because the system automatically creates a <code>TvInteractiveAppServiceInfo</code>
+ * object for each TV Interactive App service based on the information collected from the
* <code>AndroidManifest.xml</code>, this method is only called back when such information
* has changed dynamically.
*
- * @param iAppInfo The <code>TvInteractiveAppInfo</code> object that contains new
+ * @param iAppInfo The <code>TvInteractiveAppServiceInfo</code> object that contains new
* information.
* @hide
*/
- public void onTvInteractiveAppInfoUpdated(@NonNull TvInteractiveAppInfo iAppInfo) {
+ public void onTvInteractiveAppServiceInfoUpdated(
+ @NonNull TvInteractiveAppServiceInfo iAppInfo) {
}
/**
@@ -634,7 +657,7 @@ public final class TvInteractiveAppManager {
*/
public void onTvInteractiveAppServiceStateChanged(
@NonNull String iAppServiceId,
- @TvInteractiveAppInfo.InteractiveAppType int type,
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type,
@ServiceState int state,
@ErrorCode int err) {
}
@@ -680,11 +703,12 @@ public final class TvInteractiveAppManager {
});
}
- public void postTvInteractiveAppInfoUpdated(final TvInteractiveAppInfo iAppInfo) {
+ public void postTvInteractiveAppServiceInfoUpdated(
+ final TvInteractiveAppServiceInfo iAppInfo) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
- mCallback.onTvInteractiveAppInfoUpdated(iAppInfo);
+ mCallback.onTvInteractiveAppServiceInfoUpdated(iAppInfo);
}
});
}
@@ -737,11 +761,11 @@ public final class TvInteractiveAppManager {
/**
* Returns the complete list of TV Interactive App service on the system.
*
- * @return List of {@link TvInteractiveAppInfo} for each TV Interactive App service that
+ * @return List of {@link TvInteractiveAppServiceInfo} for each TV Interactive App service that
* describes its meta information.
*/
@NonNull
- public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList() {
+ public List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList() {
try {
return mService.getTvInteractiveAppServiceList(mUserId);
} catch (RemoteException e) {
@@ -750,22 +774,11 @@ public final class TvInteractiveAppManager {
}
/**
- * Prepares TV Interactive App service environment for the given type.
- */
- public void prepare(@NonNull String tvIAppServiceId, int type) {
- try {
- mService.prepare(tvIAppServiceId, type, mUserId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Registers an Android application link info record which can be used to launch the specific
* Android application by TV interactive App RTE.
*
* @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
- * ID can be found in {@link TvInputInfo#getId()}.
+ * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
* @param appLinkInfo The Android application link info record to be registered.
*/
public void registerAppLinkInfo(
@@ -782,7 +795,7 @@ public final class TvInteractiveAppManager {
* Android application by TV interactive App RTE.
*
* @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
- * ID can be found in {@link TvInputInfo#getId()}.
+ * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
* @param appLinkInfo The Android application link info record to be unregistered.
*/
public void unregisterAppLinkInfo(
@@ -798,7 +811,7 @@ public final class TvInteractiveAppManager {
* Sends app link command.
*
* @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
- * ID can be found in {@link TvInputInfo#getId()}.
+ * ID can be found in {@link TvInteractiveAppServiceInfo#getId()}.
* @param command The command to be sent.
*/
public void sendAppLinkCommand(@NonNull String tvIAppServiceId, @NonNull Bundle command) {
@@ -1022,6 +1035,18 @@ public final class TvInteractiveAppManager {
}
}
+ void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.sendSigningResult(mToken, signingId, result, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Sets the {@link android.view.Surface} for this session.
*
@@ -1655,6 +1680,15 @@ public final class TvInteractiveAppManager {
});
}
+ void postRequestSigning(String id, String algorithm, String alias, byte[] data) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onRequestSigning(mSession, id, algorithm, alias, data);
+ }
+ });
+ }
+
void postAdRequest(final AdRequest request) {
mHandler.post(new Runnable() {
@Override
@@ -1792,12 +1826,27 @@ public final class TvInteractiveAppManager {
* called.
*
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
- * @hide
*/
public void onRequestCurrentTvInputId(Session session) {
}
/**
+ * This is called when
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is
+ * called.
+ *
+ * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
+ * @param signingId the ID to identify the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc.
+ * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+ * @param data the original bytes to be signed.
+ */
+ public void onRequestSigning(
+ Session session, String signingId, String algorithm, String alias, byte[] data) {
+ }
+
+ /**
* This is called when {@link TvInteractiveAppService.Session#notifySessionStateChanged} is
* called.
*
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index d22fd83872e1..b103b1036303 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -20,6 +20,7 @@ import android.annotation.CallSuper;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Px;
import android.annotation.SdkConstant;
import android.annotation.StringDef;
import android.annotation.SuppressLint;
@@ -217,11 +218,6 @@ public abstract class TvInteractiveAppService extends Service {
}
@Override
- public void prepare(int type) {
- onPrepare(type);
- }
-
- @Override
public void registerAppLinkInfo(AppLinkInfo appLinkInfo) {
onRegisterAppLinkInfo(appLinkInfo);
}
@@ -240,11 +236,6 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
- * Prepares TV Interactive App service for the given type.
- */
- public abstract void onPrepare(@TvInteractiveAppInfo.InteractiveAppType int type);
-
- /**
* Called when a request to register an Android application link info record is received.
*/
public void onRegisterAppLinkInfo(@NonNull AppLinkInfo appLinkInfo) {
@@ -277,7 +268,7 @@ public abstract class TvInteractiveAppService extends Service {
@Nullable
public abstract Session onCreateSession(
@NonNull String iAppServiceId,
- @TvInteractiveAppInfo.InteractiveAppType int type);
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type);
/**
* Notifies the system when the state of the interactive app RTE has been changed.
@@ -289,7 +280,7 @@ public abstract class TvInteractiveAppService extends Service {
* {@link TvInteractiveAppManager#SERVICE_STATE_ERROR}.
*/
public final void notifyStateChanged(
- @TvInteractiveAppInfo.InteractiveAppType int type,
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type,
@TvInteractiveAppManager.ServiceState int state,
@TvInteractiveAppManager.ErrorCode int error) {
SomeArgs args = SomeArgs.obtain();
@@ -373,6 +364,15 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
+ * Returns {@code true} if media view is enabled, {@code false} otherwise.
+ *
+ * @see #setMediaViewEnabled(boolean)
+ */
+ public boolean isMediaViewEnabled() {
+ return mMediaViewEnabled;
+ }
+
+ /**
* Starts TvInteractiveAppService session.
*/
public void onStartInteractiveApp() {
@@ -397,9 +397,10 @@ public abstract class TvInteractiveAppService extends Service {
* no matter if it's created successfully or not.
*
* @see #notifyBiInteractiveAppCreated(Uri, String)
- * @see #onDestroyBiInteractiveApp(String)
+ * @see #onDestroyBiInteractiveAppRequest(String)
*/
- public void onCreateBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
+ public void onCreateBiInteractiveAppRequest(
+ @NonNull Uri biIAppUri, @Nullable Bundle params) {
}
@@ -407,11 +408,11 @@ public abstract class TvInteractiveAppService extends Service {
* Destroys broadcast-independent(BI) interactive application.
*
* @param biIAppId the BI interactive app ID from
- * {@link #onCreateBiInteractiveApp(Uri, Bundle)}}
+ * {@link #onCreateBiInteractiveAppRequest(Uri, Bundle)}
*
- * @see #onCreateBiInteractiveApp(Uri, Bundle)
+ * @see #onCreateBiInteractiveAppRequest(Uri, Bundle)
*/
- public void onDestroyBiInteractiveApp(@NonNull String biIAppId) {
+ public void onDestroyBiInteractiveAppRequest(@NonNull String biIAppId) {
}
/**
@@ -435,6 +436,8 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Receives current stream volume.
+ *
+ * @param volume a volume value between {@code 0.0f} and {@code 1.0f}, inclusive.
*/
public void onStreamVolume(float volume) {
}
@@ -452,6 +455,17 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
+ * Receives signing result.
+ * @param signingId the ID to identify the request. It's the same as the corresponding ID in
+ * {@link Session#requestSigning(String, String, String, byte[])}
+ * @param result the signed result.
+ *
+ * @see #requestSigning(String, String, String, byte[])
+ */
+ public void onSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ }
+
+ /**
* Called when the application sets the surface.
*
* <p>The TV Interactive App service should render interactive app UI onto the given
@@ -484,10 +498,10 @@ public abstract class TvInteractiveAppService extends Service {
* containing {@link TvInteractiveAppView}. Note that the size of the underlying surface can
* be different if the surface was changed by calling {@link #layoutSurface}.
*
- * @param width The width of the media view.
- * @param height The height of the media view.
+ * @param width The width of the media view, in pixels.
+ * @param height The height of the media view, in pixels.
*/
- public void onMediaViewSizeChanged(int width, int height) {
+ public void onMediaViewSizeChanged(@Px int width, @Px int height) {
}
/**
@@ -877,6 +891,47 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
+ * Requests signing of the given data.
+ *
+ * <p>This is used when the corresponding server of the broadcast-independent interactive
+ * app requires signing during handshaking, and the interactive app service doesn't have
+ * the built-in private key. The private key is provided by the content providers and
+ * pre-built in the related app, such as TV app.
+ *
+ * @param signingId the ID to identify the request. When a result is received, this ID can
+ * be used to correlate the result with the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc. The name is from standards like
+ * FIPS PUB 186-4 and PKCS #1.
+ * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+ * @param data the original bytes to be signed.
+ *
+ * @see #onSigningResult(String, byte[])
+ * @see TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
+ * @see TvInteractiveAppView#BI_INTERACTIVE_APP_KEY_ALIAS
+ */
+ @CallSuper
+ public void requestSigning(@NonNull String signingId, @NonNull String algorithm,
+ @NonNull String alias, @NonNull byte[] data) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestSigning");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onRequestSigning(signingId, algorithm, alias, data);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestSigning", e);
+ }
+ }
+ });
+ }
+
+ /**
* Sends an advertisement request to be processed by the related TV input.
*
* @param request The advertisement request
@@ -914,11 +969,11 @@ public abstract class TvInteractiveAppService extends Service {
}
void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
- onCreateBiInteractiveApp(biIAppUri, params);
+ onCreateBiInteractiveAppRequest(biIAppUri, params);
}
void destroyBiInteractiveApp(@NonNull String biIAppId) {
- onDestroyBiInteractiveApp(biIAppId);
+ onDestroyBiInteractiveAppRequest(biIAppId);
}
void setTeletextAppEnabled(boolean enable) {
@@ -945,6 +1000,10 @@ public abstract class TvInteractiveAppService extends Service {
onCurrentTvInputId(inputId);
}
+ void sendSigningResult(String signingId, byte[] result) {
+ onSigningResult(signingId, result);
+ }
+
void release() {
onRelease();
if (mSurface != null) {
@@ -1074,7 +1133,7 @@ public abstract class TvInteractiveAppService extends Service {
* @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
* app. {@code null} if it's not created successfully.
*
- * @see #onCreateBiInteractiveApp(Uri, Bundle)
+ * @see #onCreateBiInteractiveAppRequest(Uri, Bundle)
*/
@CallSuper
public final void notifyBiInteractiveAppCreated(
@@ -1413,6 +1472,11 @@ public abstract class TvInteractiveAppService extends Service {
}
@Override
+ public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ mSessionImpl.sendSigningResult(signingId, result);
+ }
+
+ @Override
public void release() {
mSessionImpl.scheduleMediaViewCleanup();
mSessionImpl.release();
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
index 5e1501677b3b..4b6127c01d1e 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.aidl
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -16,4 +16,4 @@
package android.media.tv.interactive;
-parcelable TvInteractiveAppInfo; \ No newline at end of file
+parcelable TvInteractiveAppServiceInfo; \ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
index 6103db001b19..3e0885214dcd 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -45,9 +45,9 @@ import java.util.List;
/**
* This class is used to specify meta information of a TV interactive app.
*/
-public final class TvInteractiveAppInfo implements Parcelable {
+public final class TvInteractiveAppServiceInfo implements Parcelable {
private static final boolean DEBUG = false;
- private static final String TAG = "TvInteractiveAppInfo";
+ private static final String TAG = "TvInteractiveAppServiceInfo";
private static final String XML_START_TAG_NAME = "tv-interactive-app";
@@ -71,7 +71,13 @@ public final class TvInteractiveAppInfo implements Parcelable {
private final String mId;
private int mTypes;
- public TvInteractiveAppInfo(@NonNull Context context, @NonNull ComponentName component) {
+ /**
+ * Constructs a TvInteractiveAppServiceInfo object.
+ *
+ * @param context the application context
+ * @param component the component name of the TvInteractiveAppService
+ */
+ public TvInteractiveAppServiceInfo(@NonNull Context context, @NonNull ComponentName component) {
if (context == null) {
throw new IllegalArgumentException("context cannot be null.");
}
@@ -94,28 +100,28 @@ public final class TvInteractiveAppInfo implements Parcelable {
mId = id;
mTypes = toTypesFlag(types);
}
- private TvInteractiveAppInfo(ResolveInfo service, String id, int types) {
+ private TvInteractiveAppServiceInfo(ResolveInfo service, String id, int types) {
mService = service;
mId = id;
mTypes = types;
}
- private TvInteractiveAppInfo(@NonNull Parcel in) {
+ private TvInteractiveAppServiceInfo(@NonNull Parcel in) {
mService = ResolveInfo.CREATOR.createFromParcel(in);
mId = in.readString();
mTypes = in.readInt();
}
- public static final @NonNull Creator<TvInteractiveAppInfo> CREATOR =
- new Creator<TvInteractiveAppInfo>() {
+ public static final @NonNull Creator<TvInteractiveAppServiceInfo> CREATOR =
+ new Creator<TvInteractiveAppServiceInfo>() {
@Override
- public TvInteractiveAppInfo createFromParcel(Parcel in) {
- return new TvInteractiveAppInfo(in);
+ public TvInteractiveAppServiceInfo createFromParcel(Parcel in) {
+ return new TvInteractiveAppServiceInfo(in);
}
@Override
- public TvInteractiveAppInfo[] newArray(int size) {
- return new TvInteractiveAppInfo[size];
+ public TvInteractiveAppServiceInfo[] newArray(int size) {
+ return new TvInteractiveAppServiceInfo[size];
}
};
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 773e54f30744..1df757b2d9d7 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 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.
@@ -46,6 +46,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
+import java.security.KeyStore;
import java.util.List;
import java.util.concurrent.Executor;
@@ -61,6 +62,41 @@ public class TvInteractiveAppView extends ViewGroup {
private static final int UNSET_TVVIEW_SUCCESS = 3;
private static final int UNSET_TVVIEW_FAIL = 4;
+ /**
+ * Used to share client {@link java.security.cert.Certificate} with
+ * {@link TvInteractiveAppService}.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ * @see java.security.cert.Certificate
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_CERTIFICATE = "certificate";
+ /**
+ * Used to share the {@link KeyStore} alias with {@link TvInteractiveAppService}.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ * @see KeyStore#aliases()
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias";
+ /**
+ * Used to share the {@link java.security.PrivateKey} with {@link TvInteractiveAppService}.
+ * <p>The private key is optional. It is used to encrypt data when necessary.
+ *
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ * @see java.security.PrivateKey
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_PRIVATE_KEY = "private_key";
+ /**
+ * Additional HTTP headers to be used by {@link TvInteractiveAppService} to load the
+ * broadcast-independent interactive application.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS =
+ "http_additional_headers";
+ /**
+ * HTTP user agent to be used by {@link TvInteractiveAppService} for broadcast-independent
+ * interactive application.
+ * @see #createBiInteractiveApp(Uri, Bundle)
+ */
+ public static final String BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT = "http_user_agent";
+
private final TvInteractiveAppManager mTvInteractiveAppManager;
private final Handler mHandler = new Handler();
private final Object mCallbackLock = new Object();
@@ -148,12 +184,14 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* Sets the callback to be invoked when an event is dispatched to this TvInteractiveAppView.
*
- * @param callback The callback to receive events. A value of {@code null} removes the existing
- * callback.
+ * @param callback the callback to receive events. MUST NOT be {@code null}.
+ *
+ * @see #clearCallback()
*/
public void setCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull TvInteractiveAppCallback callback) {
+ com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, callback);
synchronized (mCallbackLock) {
mCallbackExecutor = executor;
mCallback = callback;
@@ -162,6 +200,8 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* Clears the callback.
+ *
+ * @see #setCallback(Executor, TvInteractiveAppCallback)
*/
public void clearCallback() {
synchronized (mCallbackLock) {
@@ -238,7 +278,9 @@ public class TvInteractiveAppView extends ViewGroup {
}
/**
- * Resets this TvInteractiveAppView.
+ * Resets this TvInteractiveAppView to release its resources.
+ *
+ * <p>It can be reused by call {@link #prepareInteractiveApp(String, int)}.
*/
public void reset() {
if (DEBUG) Log.d(TAG, "reset()");
@@ -364,6 +406,19 @@ public class TvInteractiveAppView extends ViewGroup {
mOnUnhandledInputEventListener = listener;
// TODO: handle CallbackExecutor
}
+
+ /**
+ * Gets the {@link OnUnhandledInputEventListener}.
+ * <p>Returns {@code null} if the listener is not set or is cleared.
+ *
+ * @see #setOnUnhandledInputEventListener(Executor, OnUnhandledInputEventListener)
+ * @see #clearOnUnhandledInputEventListener()
+ */
+ @Nullable
+ public OnUnhandledInputEventListener getOnUnhandledInputEventListener() {
+ return mOnUnhandledInputEventListener;
+ }
+
/**
* Clears the {@link OnUnhandledInputEventListener}.
*/
@@ -386,16 +441,17 @@ public class TvInteractiveAppView extends ViewGroup {
}
/**
- * Prepares the interactive application.
+ * Prepares the interactive application runtime environment of corresponding
+ * {@link TvInteractiveAppService}.
*
* @param iAppServiceId the interactive app service ID, which can be found in
- * {@link TvInteractiveAppInfo#getId()}.
+ * {@link TvInteractiveAppServiceInfo#getId()}.
*
* @see android.media.tv.interactive.TvInteractiveAppManager#getTvInteractiveAppServiceList()
*/
public void prepareInteractiveApp(
@NonNull String iAppServiceId,
- @TvInteractiveAppInfo.InteractiveAppType int type) {
+ @TvInteractiveAppServiceInfo.InteractiveAppType int type) {
// TODO: document and handle the cases that this method is called multiple times.
if (DEBUG) {
Log.d(TAG, "prepareInteractiveApp");
@@ -432,6 +488,8 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* Resets the interactive application.
+ *
+ * <p>This releases the resources of the corresponding {@link TvInteractiveAppService.Session}.
*/
public void resetInteractiveApp() {
if (DEBUG) {
@@ -471,6 +529,8 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* Sends stream volume to related TV interactive app.
+ *
+ * @param volume a volume value between {@code 0.0f} and {@code 1.0f}, inclusive.
*/
public void sendStreamVolume(float volume) {
if (DEBUG) {
@@ -509,6 +569,27 @@ public class TvInteractiveAppView extends ViewGroup {
}
}
+ /**
+ * Sends signing result to related TV interactive app.
+ *
+ * <p>This is used when the corresponding server of the broadcast-independent interactive
+ * app requires signing during handshaking, and the interactive app service doesn't have
+ * the built-in private key. The private key is provided by the content providers and
+ * pre-built in the related app, such as TV app.
+ *
+ * @param signingId the ID to identify the request. It's the same as the corresponding ID in
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])}
+ * @param result the signed result.
+ */
+ public void sendSigningResult(@NonNull String signingId, @NonNull byte[] result) {
+ if (DEBUG) {
+ Log.d(TAG, "sendSigningResult");
+ }
+ if (mSession != null) {
+ mSession.sendSigningResult(signingId, result);
+ }
+ }
+
private void resetInternal() {
mSessionCallback = null;
if (mSession != null) {
@@ -527,7 +608,14 @@ public class TvInteractiveAppView extends ViewGroup {
* <p>{@link TvInteractiveAppCallback#onBiInteractiveAppCreated(String, Uri, String)} will be
* called for the result.
*
+ * @param biIAppUri URI associated this BI interactive app.
+ * @param params optional parameters for broadcast-independent interactive application, such as
+ * {@link #BI_INTERACTIVE_APP_KEY_CERTIFICATE}.
+ *
* @see TvInteractiveAppCallback#onBiInteractiveAppCreated(String, Uri, String)
+ * @see #BI_INTERACTIVE_APP_KEY_CERTIFICATE
+ * @see #BI_INTERACTIVE_APP_KEY_HTTP_ADDITIONAL_HEADERS
+ * @see #BI_INTERACTIVE_APP_KEY_HTTP_USER_AGENT
*/
public void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
if (DEBUG) {
@@ -721,6 +809,22 @@ public class TvInteractiveAppView extends ViewGroup {
public void onRequestCurrentTvInputId(@NonNull String iAppServiceId) {
}
+ /**
+ * This is called when
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, byte[])} is
+ * called.
+ *
+ * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param signingId the ID to identify the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc.
+ * @param alias the alias of the corresponding {@link java.security.KeyStore}.
+ * @param data the original bytes to be signed.
+ */
+ public void onRequestSigning(@NonNull String iAppServiceId, @NonNull String signingId,
+ @NonNull String algorithm, @NonNull String alias, @NonNull byte[] data) {
+ }
+
}
/**
@@ -1027,5 +1131,20 @@ public class TvInteractiveAppView extends ViewGroup {
mCallback.onRequestCurrentTvInputId(mIAppServiceId);
}
}
+
+ @Override
+ public void onRequestSigning(
+ Session session, String id, String algorithm, String alias, byte[] data) {
+ if (DEBUG) {
+ Log.d(TAG, "onRequestSigning");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onRequestSigning - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onRequestSigning(mIAppServiceId, id, algorithm, alias, data);
+ }
+ }
}
}
diff --git a/packages/CompanionDeviceManager/res/color/selector.xml b/packages/CompanionDeviceManager/res/color/selector.xml
index 56e5dca0f72f..aebc5d5adf6e 100644
--- a/packages/CompanionDeviceManager/res/color/selector.xml
+++ b/packages/CompanionDeviceManager/res/color/selector.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml b/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml
index ece7bbafc654..ebe16a7a14e5 100644
--- a/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml
+++ b/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml b/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml
index 7df92bb145cb..3cd7929bdd83 100644
--- a/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml
+++ b/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -17,6 +18,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/system_accent1_100"/>
- <corners android:topLeftRadius="12dp" android:topRightRadius="12dp"
- android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
+ <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
+ android:bottomLeftRadius="12dp" android:bottomRightRadius="12dp"/>
</shape>
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml b/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml
index 55e96f6d7512..2cff4737cabf 100644
--- a/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml
+++ b/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -17,6 +18,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/system_accent1_100"/>
- <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
- android:bottomLeftRadius="12dp" android:bottomRightRadius="12dp"/>
+ <corners android:topLeftRadius="12dp" android:topRightRadius="12dp"
+ android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
</shape>
diff --git a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml b/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
index f9ec5d0dce55..8e92051faf6c 100644
--- a/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
+++ b/packages/CompanionDeviceManager/res/drawable/helper_ok_button.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_apps.xml b/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
index 93a0cba769c6..d1ec8637775c 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_device_other.xml b/packages/CompanionDeviceManager/res/drawable/ic_device_other.xml
index f8515c33d57f..2a8eb24bcf1f 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_device_other.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_device_other.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml b/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml
index 4ac4d04b184e..e5825bcbf70c 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_notifications.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_storage.xml b/packages/CompanionDeviceManager/res/drawable/ic_storage.xml
index d8b7f59185c8..406a3b5dada5 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_storage.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_storage.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_watch.xml b/packages/CompanionDeviceManager/res/drawable/ic_watch.xml
index 44a40b9fede3..d7a28d949997 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_watch.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_watch.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index 8eec33aeb4ee..c37054e9e98d 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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
@@ -20,35 +19,26 @@
<!-- A header for selfManaged devices only. -->
<include layout="@layout/vendor_header" />
+ <!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
+
<ImageView
android:id="@+id/profile_icon"
android:layout_width="match_parent"
android:layout_height="32dp"
android:gravity="center"
- android:layout_marginBottom="12dp"
- android:layout_marginTop="1dp"
+ android:layout_marginTop="18dp"
android:tint="@android:color/system_accent1_600"/>
- <!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
+ <LinearLayout style="@style/Description">
+ <TextView
+ android:id="@+id/title"
+ style="@style/DescriptionTitle" />
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingHorizontal="12dp"
- android:layout_marginBottom="12dp"
- style="@*android:style/TextAppearance.Widget.Toolbar.Title" />
+ <TextView
+ android:id="@+id/summary"
+ style="@style/DescriptionSummary" />
- <TextView
- android:id="@+id/summary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
- android:gravity="center"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp" />
+ </LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
@@ -59,18 +49,20 @@
android:id="@+id/multiple_device_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"
android:orientation="vertical"
android:visibility="gone">
<View
android:id="@+id/border_top"
- android:layout_marginTop="12dp"
style="@style/DeviceListBorder" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/device_list"
android:layout_width="match_parent"
android:scrollbars="vertical"
+ android:layout_marginBottom="12dp"
android:layout_height="200dp" />
<View
@@ -84,35 +76,56 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
+ <ProgressBar
+ android:id="@+id/spinner"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:layout_centerInParent="true"
+ android:indeterminate="true"
+ android:tint="@android:color/system_accent1_600"
+ android:visibility="gone"
+ style="?android:attr/progressBarStyleLarge" />
+
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:gravity="center"
android:orientation="vertical"
- android:layout_marginTop="24dp">
+ android:layout_marginTop="16dp">
<!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
<Button
+ android:id="@+id/btn_positive"
+ style="@style/PositiveButton"
+ android:text="@string/consent_yes" />
+
+ <Button
android:id="@+id/btn_negative"
+ android:layout_marginBottom="12dp"
style="@style/NegativeButton"
android:text="@string/consent_no" />
- <Button
- android:id="@+id/btn_positive"
- style="@style/PositiveButton"
- android:text="@string/consent_yes" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="bottom|right"
+ android:orientation="vertical"
+ android:layout_marginRight="16dp"
+ android:layout_marginBottom="16dp">
+
+ <!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
<Button
android:id="@+id/btn_negative_multiple_devices"
- android:layout_marginLeft="170dp"
- android:layout_marginBottom="10dp"
style="@style/NegativeButtonMultipleDevices"
- android:textColor = "?android:textColorPrimary"
+ android:textColor="?android:textColorPrimary"
android:visibility="gone"
android:text="@string/consent_no" />
-
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml b/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
index 7c508147e0ac..3d0849356281 100644
--- a/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
@@ -15,54 +15,42 @@
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/activity_confirmation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/dialog_background"
- android:elevation="16dp"
- android:maxHeight="400dp"
- android:orientation="vertical"
- android:padding="18dp"
- android:layout_gravity="center">
+ android:id="@+id/data_transfer_confirmation"
+ style="@style/ContainerLayout">
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingHorizontal="12dp"
- style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
+ <LinearLayout style="@style/Description">
+ <TextView
+ android:id="@+id/title"
+ style="@style/DescriptionTitle" />
- <TextView
- android:id="@+id/summary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
- android:gravity="center"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp" />
+ <TextView
+ android:id="@+id/summary"
+ style="@style/DescriptionSummary" />
+
+ </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:gravity="center"
android:orientation="vertical"
- android:layout_marginTop="24dp">
+ android:layout_marginTop="16dp">
<!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
<Button
- android:id="@+id/btn_negative"
- style="@style/NegativeButton"
- android:text="@string/consent_no" />
-
- <Button
android:id="@+id/btn_positive"
style="@style/PositiveButton"
android:text="@string/consent_yes" />
+ <Button
+ android:id="@+id/btn_negative"
+ android:layout_marginBottom="12dp"
+ style="@style/NegativeButton"
+ android:text="@string/consent_no" />
+
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
index c177039891d2..a22ca941c5eb 100644
--- a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -17,6 +18,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/helper_confirmation"
android:theme="@style/ChooserActivity"
+ android:padding="12dp"
style="@style/ContainerLayout">
<ImageView
@@ -24,8 +26,8 @@
android:layout_width="match_parent"
android:layout_height="32dp"
android:gravity="center"
- android:layout_marginBottom="12dp"
- android:layout_marginTop="1dp"/>
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"/>
<TextView
android:id="@+id/helper_title"
@@ -33,17 +35,18 @@
android:layout_height="wrap_content"
android:gravity="center"
android:paddingHorizontal="12dp"
- style="@*android:style/TextAppearance.Widget.Toolbar.Title"
- android:textSize="20sp" />
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="22sp" />
<TextView
android:id="@+id/helper_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="24dp"
+ android:layout_marginRight="24dp"
android:layout_marginTop="12dp"
- android:layout_marginLeft="20dp"
android:layout_marginBottom="24dp"
- android:gravity="start"
+ android:gravity="center"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp" />
@@ -51,6 +54,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
+ android:layout_marginRight="12dp"
+ android:layout_marginBottom="12dp"
android:gravity="end">
<Button
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_device.xml b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
index 3c8a81f4fe83..eeb988f364b2 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_device.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
@@ -28,6 +28,7 @@
android:id="@android:id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
+ android:layout_marginLeft="24dp"
android:layout_marginRight="12dp"
android:tint="@android:color/system_accent1_600"/>
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_permission.xml b/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
index 79aa4e7e8927..3dce38d0dc20 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -19,13 +20,15 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:padding="5dp">
+ android:paddingLeft="32dp"
+ android:paddingRight="32dp"
+ android:paddingBottom="14dp">
<ImageView
android:id="@+id/permission_icon"
android:layout_width="24dp"
android:layout_height="24dp"
- android:layout_marginTop="7dp"
+ android:layout_marginTop="8dp"
android:layout_marginEnd="12dp"
android:tint="@android:color/system_accent1_600"
android:contentDescription="Permission Icon"/>
@@ -48,6 +51,7 @@
android:id="@+id/permission_summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:paddingRight="24dp"
android:textSize="14sp"
android:textColor="?android:attr/textColorSecondary"/>
diff --git a/packages/CompanionDeviceManager/res/layout/vendor_header.xml b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
index d04eadfb62f4..5f6aa9419c6e 100644
--- a/packages/CompanionDeviceManager/res/layout/vendor_header.xml
+++ b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -21,7 +22,10 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center"
- android:layout_marginBottom="16dp"
+ android:paddingTop="24dp"
+ android:paddingBottom="4dp"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
android:visibility="gone" >
<ImageView
@@ -42,7 +46,6 @@
style="?android:attr/actionOverflowButtonStyle"
android:layout_width="31dp"
android:layout_height="32dp"
- android:layout_marginLeft="100dp"
android:layout_alignParentRight="true" />
</RelativeLayout> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index 6eaffd4c3cfe..a55f30c9be6a 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -16,51 +17,86 @@
<resources>
<style name="ContainerLayout">
- <item name="android:padding">18dp</item>
- <item name="android:elevation">16dp</item>
- <item name="android:maxHeight">400dp</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
<item name="android:orientation">vertical</item>
<item name="android:layout_gravity">center</item>
+ <item name="android:minWidth">340dp</item>
+ <item name="android:background">@drawable/dialog_background</item>
+ </style>
+
+ <style name="Description">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
- <item name="android:background">@drawable/dialog_background</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_marginTop">18dp</item>
+ <item name="android:layout_marginBottom">18dp</item>
+ <item name="android:layout_marginLeft">24dp</item>
+ <item name="android:layout_marginRight">24dp</item>
+ </style>
+
+ <style name="DescriptionTitle"
+ parent="@*android:style/TextAppearance.Widget.Toolbar.Title">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center</item>
+ <item name="android:layout_marginLeft">14dp</item>
+ <item name="android:layout_marginRight">14dp</item>
+ <item name="android:textSize">20sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="DescriptionSummary">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center</item>
+ <item name="android:layout_marginTop">18dp</item>
+ <item name="android:layout_marginLeft">18dp</item>
+ <item name="android:layout_marginRight">18dp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
<style name="VendorHelperOkButton"
parent="@android:style/Widget.Material.Button.Borderless.Colored">
<item name="android:layout_width">50dp</item>
- <item name="android:layout_height">35dp</item>
+ <item name="android:layout_height">36dp</item>
<item name="android:layout_marginTop">20dp</item>
<item name="android:textColor">@android:color/system_neutral1_900</item>
<item name="android:background">@drawable/helper_ok_button</item>
</style>
- <style name="NegativeButton"
+ <style name="PositiveButton"
parent="@android:style/Widget.Material.Button.Borderless.Colored">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_width">300dp</item>
+ <item name="android:layout_height">56dp</item>
+ <item name="android:layout_marginLeft">24dp</item>
+ <item name="android:layout_marginRight">24dp</item>
+ <item name="android:layout_marginBottom">2dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">@android:color/system_neutral1_900</item>
- <item name="android:background">@drawable/btn_negative_top</item>
+ <item name="android:background">@drawable/btn_positive_bottom</item>
</style>
- <style name="PositiveButton"
+ <style name="NegativeButton"
parent="@android:style/Widget.Material.Button.Borderless.Colored">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_width">300dp</item>
+ <item name="android:layout_height">56dp</item>
+ <item name="android:layout_marginLeft">24dp</item>
+ <item name="android:layout_marginRight">24dp</item>
+ <item name="android:layout_marginTop">2dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">@android:color/system_neutral1_900</item>
<item name="android:layout_marginTop">4dp</item>
- <item name="android:background">@drawable/btn_positive_bottom</item>
+ <item name="android:background">@drawable/btn_negative_top</item>
</style>
<style name="NegativeButtonMultipleDevices"
parent="@android:style/Widget.Material.Button.Colored">
<item name="android:layout_width">100dp</item>
- <item name="android:layout_height">35dp</item>
- <item name="android:layout_marginTop">20dp</item>
+ <item name="android:layout_height">36dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:background">@drawable/btn_negative_multiple_devices</item>
</style>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index f752b697c4a5..0bdf65d8ef55 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -57,6 +57,7 @@ import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -116,14 +117,14 @@ public class CompanionDeviceActivity extends FragmentActivity implements
private ImageButton mVendorHeaderButton;
// Progress indicator is only shown while we are looking for the first suitable device for a
- // "regular" (ie. not self-managed) association.
- private View mProgressIndicator;
+ // multiple device association.
+ private ProgressBar mProgressIndicator;
// Present for self-managed association requests and "single-device" regular association
// regular.
private Button mButtonAllow;
private Button mButtonNotAllow;
- // Present for multiple device association requests only.
+ // Present for multiple devices' association requests only.
private Button mButtonNotAllowMultipleDevices;
private LinearLayout mAssociationConfirmationDialog;
@@ -263,6 +264,8 @@ public class CompanionDeviceActivity extends FragmentActivity implements
mVendorHeaderButton = findViewById(R.id.vendor_header_button);
mDeviceListRecyclerView = findViewById(R.id.device_list);
+
+ mProgressIndicator = findViewById(R.id.spinner);
mDeviceAdapter = new DeviceListAdapter(this, this::onListItemClick);
mPermissionListRecyclerView = findViewById(R.id.permission_list);
@@ -502,21 +505,25 @@ public class CompanionDeviceActivity extends FragmentActivity implements
mSummary.setText(summary);
mProfileIcon.setImageDrawable(profileIcon);
- mDeviceAdapter = new DeviceListAdapter(this, this::onListItemClick);
-
- // TODO: hide the list and show a spinner until a first device matching device is found.
mDeviceListRecyclerView.setAdapter(mDeviceAdapter);
mDeviceListRecyclerView.setLayoutManager(new LinearLayoutManager(this));
- CompanionDeviceDiscoveryService.getScanResult().observe(
- /* lifecycleOwner */ this,
- /* observer */ mDeviceAdapter);
+ CompanionDeviceDiscoveryService.getScanResult().observe(this,
+ deviceFilterPairs -> {
+ // Dismiss the progress bar once there's one device found for multiple devices.
+ if (deviceFilterPairs.size() >= 1) {
+ mProgressIndicator.setVisibility(View.GONE);
+ }
+
+ mDeviceAdapter.setDevices(deviceFilterPairs);
+ });
// "Remove" consent button: users would need to click on the list item.
mButtonAllow.setVisibility(View.GONE);
mButtonNotAllow.setVisibility(View.GONE);
mButtonNotAllowMultipleDevices.setVisibility(View.VISIBLE);
mMultipleDeviceList.setVisibility(View.VISIBLE);
+ mProgressIndicator.setVisibility(View.VISIBLE);
}
private void onListItemClick(int position) {
@@ -564,7 +571,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
CompanionVendorHelperDialogFragment.newInstance(mRequest.getPackageName(),
mRequest.getUserId(), mRequest.getDeviceProfile());
- mAssociationConfirmationDialog.setVisibility(View.GONE);
+ mAssociationConfirmationDialog.setVisibility(View.INVISIBLE);
fragmentDialog.show(fragmentManager, /* Tag */ FRAGMENT_DIALOG_TAG);
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index 5f07fcfd8565..e8a1a5cc1916 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -150,6 +150,8 @@ public class CompanionDeviceDiscoveryService extends Service {
mBtAdapter = mBtManager.getAdapter();
mBleScanner = mBtAdapter.getBluetoothLeScanner();
mWifiManager = getSystemService(WifiManager.class);
+
+ sScanResultsLiveData.setValue(Collections.emptyList());
}
@Override
@@ -186,7 +188,6 @@ public class CompanionDeviceDiscoveryService extends Service {
mStopAfterFirstMatch = request.isSingleDevice();
mDiscoveryStarted = true;
sStateLiveData.setValue(DiscoveryState.DISCOVERY_IN_PROGRESS);
- sScanResultsLiveData.setValue(Collections.emptyList());
final List<DeviceFilter<?>> allFilters = request.getDeviceFilters();
final List<BluetoothDeviceFilter> btFilters =
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
index 8babd3ade1eb..328c67ebb216 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
@@ -25,15 +25,13 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
-import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
/**
* Adapter for the list of "found" devices.
*/
-class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolder> implements
- Observer<List<DeviceFilterPair<?>>> {
+class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolder> {
public int mSelectedPosition = RecyclerView.NO_POSITION;
private final Context mContext;
@@ -96,9 +94,8 @@ class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolde
mSelectedPosition = position;
}
- @Override
- public void onChanged(List<DeviceFilterPair<?>> deviceFilterPairs) {
- mDevices = deviceFilterPairs;
+ void setDevices(List<DeviceFilterPair<?>> devices) {
+ mDevices = devices;
notifyDataSetChanged();
}
diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp
index 217a1f67c336..bc278528570f 100644
--- a/packages/ConnectivityT/framework-t/Android.bp
+++ b/packages/ConnectivityT/framework-t/Android.bp
@@ -131,8 +131,8 @@ filegroup {
"src/android/net/EthernetNetworkUpdateRequest.java",
"src/android/net/EthernetNetworkUpdateRequest.aidl",
"src/android/net/IEthernetManager.aidl",
- "src/android/net/IEthernetNetworkManagementListener.aidl",
"src/android/net/IEthernetServiceListener.aidl",
+ "src/android/net/INetworkInterfaceOutcomeReceiver.aidl",
"src/android/net/ITetheredInterfaceCallback.aidl",
],
path: "src",
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
index 2b6570a6ecb0..74fe4bd46cde 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
@@ -17,6 +17,7 @@
package android.app.usage;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
@@ -474,10 +475,11 @@ public final class NetworkStats implements AutoCloseable {
/**
* Fills the recycled bucket with data of the next bin in the enumeration.
- * @param bucketOut Bucket to be filled with data.
+ * @param bucketOut Bucket to be filled with data. If null, the method does
+ * nothing and returning false.
* @return true if successfully filled the bucket, false otherwise.
*/
- public boolean getNextBucket(Bucket bucketOut) {
+ public boolean getNextBucket(@Nullable Bucket bucketOut) {
if (mSummary != null) {
return getNextSummaryBucket(bucketOut);
} else {
@@ -651,7 +653,7 @@ public final class NetworkStats implements AutoCloseable {
* @param bucketOut Next item will be set here.
* @return true if a next item could be set.
*/
- private boolean getNextSummaryBucket(Bucket bucketOut) {
+ private boolean getNextSummaryBucket(@Nullable Bucket bucketOut) {
if (bucketOut != null && mEnumerationIndex < mSummary.size()) {
mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry);
fillBucketFromSummaryEntry(bucketOut);
@@ -678,7 +680,7 @@ public final class NetworkStats implements AutoCloseable {
* @param bucketOut Next item will be set here.
* @return true if a next item could be set.
*/
- private boolean getNextHistoryBucket(Bucket bucketOut) {
+ private boolean getNextHistoryBucket(@Nullable Bucket bucketOut) {
if (bucketOut != null && mHistory != null) {
if (mEnumerationIndex < mHistory.size()) {
mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++,
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index bf518b2d5a29..f41475bea190 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -290,7 +290,7 @@ public class NetworkStatsManager {
* statistics collection.
*/
@WorkerThread
- public Bucket querySummaryForDevice(int networkType, String subscriberId,
+ public Bucket querySummaryForDevice(int networkType, @Nullable String subscriberId,
long startTime, long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -335,8 +335,8 @@ public class NetworkStatsManager {
* statistics collection.
*/
@WorkerThread
- public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
- long endTime) throws SecurityException, RemoteException {
+ public Bucket querySummaryForUser(int networkType, @Nullable String subscriberId,
+ long startTime, long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
template = createTemplate(networkType, subscriberId);
@@ -384,7 +384,7 @@ public class NetworkStatsManager {
* statistics collection.
*/
@WorkerThread
- public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
+ public NetworkStats querySummary(int networkType, @Nullable String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -508,15 +508,17 @@ public class NetworkStatsManager {
*
* @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUid(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid) throws SecurityException {
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
}
/** @hide */
- public NetworkStats queryDetailsForUid(NetworkTemplate template,
+ @NonNull
+ public NetworkStats queryDetailsForUid(@NonNull NetworkTemplate template,
long startTime, long endTime, int uid) throws SecurityException {
return queryDetailsForUidTagState(template, startTime, endTime, uid,
NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
@@ -524,23 +526,59 @@ public class NetworkStatsManager {
/**
* Query network usage statistics details for a given uid and tag.
+ *
+ * This may take a long time, and apps should avoid calling this on their main thread.
+ * Only usable for uids belonging to calling user. Result is not aggregated over time.
+ * This means buckets' start and end timestamps are going to be between 'startTime' and
+ * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag
+ * the same as the 'tag' parameter, and the state the same as the 'state' parameter.
+ * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
+ * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
+ * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
+ * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
+ * interpolate across partial buckets. Since bucket length is in the order of hours, this
+ * method cannot be used to measure data usage on a fine grained time scale.
* This may take a long time, and apps should avoid calling this on their main thread.
*
- * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * <p>Starting with API level 29, the {@code subscriberId} is guarded by
+ * additional restrictions. Calling apps that do not meet the new
+ * requirements to access the {@code subscriberId} can provide a {@code
+ * null} value when querying for the mobile network type to receive usage
+ * for all mobile networks. For additional details see {@link
+ * TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param uid UID of app
+ * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data
+ * across all the tags.
+ * @return Statistics which is described above.
+ * @throws SecurityException if permissions are insufficient to read network statistics.
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUidTag(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid, int tag) throws SecurityException {
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
tag, NetworkStats.Bucket.STATE_ALL);
}
/**
- * Query network usage statistics details for a given uid, tag, and state. Only usable for uids
- * belonging to calling user. Result is not aggregated over time. This means buckets' start and
- * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going
- * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state
- * the same as the 'state' parameter.
+ * Query network usage statistics details for a given uid, tag, and state.
+ *
+ * Only usable for uids belonging to calling user. Result is not aggregated over time.
+ * This means buckets' start and end timestamps are going to be between 'startTime' and
+ * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag
+ * the same as the 'tag' parameter, and the state the same as the 'state' parameter.
* defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
* metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
* roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
@@ -572,11 +610,12 @@ public class NetworkStatsManager {
* across all the tags.
* @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate
* traffic from all states.
- * @return Statistics object or null if an error happened during statistics collection.
+ * @return Statistics which is described above.
* @throws SecurityException if permissions are insufficient to read network statistics.
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUidTagState(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
NetworkTemplate template;
template = createTemplate(networkType, subscriberId);
@@ -669,7 +708,7 @@ public class NetworkStatsManager {
* statistics collection.
*/
@WorkerThread
- public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
+ public NetworkStats queryDetails(int networkType, @Nullable String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -698,7 +737,7 @@ public class NetworkStatsManager {
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@@ -724,7 +763,7 @@ public class NetworkStatsManager {
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@@ -785,10 +824,28 @@ public class NetworkStatsManager {
/**
* Registers to receive notifications about data usage on specified networks.
*
- * @see #registerUsageCallback(int, String, long, UsageCallback, Handler)
+ * <p>The callbacks will continue to be called as long as the process is live or
+ * {@link #unregisterUsageCallback} is called.
+ *
+ * @param networkType Type of network to monitor. Either
+ {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * <p>Starting with API level 29, the {@code subscriberId} is guarded by
+ * additional restrictions. Calling apps that do not meet the new
+ * requirements to access the {@code subscriberId} can provide a {@code
+ * null} value when registering for the mobile network type to receive
+ * notifications for all mobile networks. For additional details see {@link
+ * TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
+ * @param thresholdBytes Threshold in bytes to be notified on.
+ * @param callback The {@link UsageCallback} that the system will call when data usage
+ * has exceeded the specified threshold.
*/
- public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
- UsageCallback callback) {
+ public void registerUsageCallback(int networkType, @Nullable String subscriberId,
+ long thresholdBytes, @NonNull UsageCallback callback) {
registerUsageCallback(networkType, subscriberId, thresholdBytes, callback,
null /* handler */);
}
@@ -818,8 +875,8 @@ public class NetworkStatsManager {
* @param handler to dispatch callback events through, otherwise if {@code null} it uses
* the calling thread.
*/
- public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
- UsageCallback callback, @Nullable Handler handler) {
+ public void registerUsageCallback(int networkType, @Nullable String subscriberId,
+ long thresholdBytes, @NonNull UsageCallback callback, @Nullable Handler handler) {
NetworkTemplate template = createTemplate(networkType, subscriberId);
if (DBG) {
Log.d(TAG, "registerUsageCallback called with: {"
@@ -839,7 +896,7 @@ public class NetworkStatsManager {
*
* @param callback The {@link UsageCallback} used when registering.
*/
- public void unregisterUsageCallback(UsageCallback callback) {
+ public void unregisterUsageCallback(@NonNull UsageCallback callback) {
if (callback == null || callback.request == null
|| callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
throw new IllegalArgumentException("Invalid UsageCallback");
@@ -880,7 +937,7 @@ public class NetworkStatsManager {
/**
* Called when data usage has reached the given threshold.
*/
- public abstract void onThresholdReached(int networkType, String subscriberId);
+ public abstract void onThresholdReached(int networkType, @Nullable String subscriberId);
/**
* @hide used for internal bookkeeping
@@ -924,7 +981,7 @@ public class NetworkStatsManager {
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- @NonNull public void registerNetworkStatsProvider(
+ public void registerNetworkStatsProvider(
@NonNull String tag,
@NonNull NetworkStatsProvider provider) {
try {
@@ -950,7 +1007,7 @@ public class NetworkStatsManager {
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- @NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
+ public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
try {
provider.getProviderCallbackBinderOrThrow().unregister();
} catch (RemoteException e) {
@@ -958,7 +1015,7 @@ public class NetworkStatsManager {
}
}
- private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
+ private static NetworkTemplate createTemplate(int networkType, @Nullable String subscriberId) {
final NetworkTemplate template;
switch (networkType) {
case ConnectivityManager.TYPE_MOBILE:
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index 793f28d5aa59..e02ea897dbe6 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -30,6 +30,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
+import android.os.OutcomeReceiver;
import android.os.RemoteException;
import com.android.internal.annotations.GuardedBy;
@@ -38,9 +39,10 @@ import com.android.modules.utils.BackgroundThread;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
+import java.util.function.IntConsumer;
/**
* A class that manages and configures Ethernet interfaces.
@@ -53,15 +55,31 @@ public class EthernetManager {
private static final String TAG = "EthernetManager";
private final IEthernetManager mService;
- @GuardedBy("mListeners")
- private final ArrayList<ListenerInfo> mListeners = new ArrayList<>();
+ @GuardedBy("mListenerLock")
+ private final ArrayList<ListenerInfo<InterfaceStateListener>> mIfaceListeners =
+ new ArrayList<>();
+ @GuardedBy("mListenerLock")
+ private final ArrayList<ListenerInfo<IntConsumer>> mEthernetStateListeners =
+ new ArrayList<>();
+ final Object mListenerLock = new Object();
private final IEthernetServiceListener.Stub mServiceListener =
new IEthernetServiceListener.Stub() {
@Override
+ public void onEthernetStateChanged(int state) {
+ synchronized (mListenerLock) {
+ for (ListenerInfo<IntConsumer> li : mEthernetStateListeners) {
+ li.executor.execute(() -> {
+ li.listener.accept(state);
+ });
+ }
+ }
+ }
+
+ @Override
public void onInterfaceStateChanged(String iface, int state, int role,
IpConfiguration configuration) {
- synchronized (mListeners) {
- for (ListenerInfo li : mListeners) {
+ synchronized (mListenerLock) {
+ for (ListenerInfo<InterfaceStateListener> li : mIfaceListeners) {
li.executor.execute(() ->
li.listener.onInterfaceStateChanged(iface, state, role,
configuration));
@@ -70,13 +88,29 @@ public class EthernetManager {
}
};
- private static class ListenerInfo {
+ /**
+ * Indicates that Ethernet is disabled.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int ETHERNET_STATE_DISABLED = 0;
+
+ /**
+ * Indicates that Ethernet is enabled.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int ETHERNET_STATE_ENABLED = 1;
+
+ private static class ListenerInfo<T> {
@NonNull
public final Executor executor;
@NonNull
- public final InterfaceStateListener listener;
+ public final T listener;
- private ListenerInfo(@NonNull Executor executor, @NonNull InterfaceStateListener listener) {
+ private ListenerInfo(@NonNull Executor executor, @NonNull T listener) {
this.executor = executor;
this.listener = listener;
}
@@ -289,16 +323,22 @@ public class EthernetManager {
if (listener == null || executor == null) {
throw new NullPointerException("listener and executor must not be null");
}
- synchronized (mListeners) {
- mListeners.add(new ListenerInfo(executor, listener));
- if (mListeners.size() == 1) {
- try {
- mService.addListener(mServiceListener);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ synchronized (mListenerLock) {
+ maybeAddServiceListener();
+ mIfaceListeners.add(new ListenerInfo<InterfaceStateListener>(executor, listener));
+ }
+ }
+
+ @GuardedBy("mListenerLock")
+ private void maybeAddServiceListener() {
+ if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return;
+
+ try {
+ mService.addListener(mServiceListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
+
}
/**
@@ -323,15 +363,20 @@ public class EthernetManager {
@SystemApi(client = MODULE_LIBRARIES)
public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) {
Objects.requireNonNull(listener);
- synchronized (mListeners) {
- mListeners.removeIf(l -> l.listener == listener);
- if (mListeners.isEmpty()) {
- try {
- mService.removeListener(mServiceListener);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ synchronized (mListenerLock) {
+ mIfaceListeners.removeIf(l -> l.listener == listener);
+ maybeRemoveServiceListener();
+ }
+ }
+
+ @GuardedBy("mListenerLock")
+ private void maybeRemoveServiceListener() {
+ if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return;
+
+ try {
+ mService.removeListener(mServiceListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -443,41 +488,45 @@ public class EthernetManager {
return new TetheredInterfaceRequest(mService, cbInternal);
}
- private static final class InternalNetworkManagementListener
- extends IEthernetNetworkManagementListener.Stub {
+ private static final class NetworkInterfaceOutcomeReceiver
+ extends INetworkInterfaceOutcomeReceiver.Stub {
@NonNull
private final Executor mExecutor;
@NonNull
- private final BiConsumer<Network, EthernetNetworkManagementException> mListener;
+ private final OutcomeReceiver<String, EthernetNetworkManagementException> mCallback;
- InternalNetworkManagementListener(
+ NetworkInterfaceOutcomeReceiver(
@NonNull final Executor executor,
- @NonNull final BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @NonNull final OutcomeReceiver<String, EthernetNetworkManagementException>
+ callback) {
Objects.requireNonNull(executor, "Pass a non-null executor");
- Objects.requireNonNull(listener, "Pass a non-null listener");
+ Objects.requireNonNull(callback, "Pass a non-null callback");
mExecutor = executor;
- mListener = listener;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onResult(@NonNull String iface) {
+ mExecutor.execute(() -> mCallback.onResult(iface));
}
@Override
- public void onComplete(
- @Nullable final Network network,
- @Nullable final EthernetNetworkManagementException e) {
- mExecutor.execute(() -> mListener.accept(network, e));
+ public void onError(@NonNull EthernetNetworkManagementException e) {
+ mExecutor.execute(() -> mCallback.onError(e));
}
}
- private InternalNetworkManagementListener getInternalNetworkManagementListener(
+ private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver(
@Nullable final Executor executor,
- @Nullable final BiConsumer<Network, EthernetNetworkManagementException> listener) {
- if (null != listener) {
- Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
+ @Nullable final OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
+ if (null != callback) {
+ Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback");
}
- final InternalNetworkManagementListener proxy;
- if (null == listener) {
+ final NetworkInterfaceOutcomeReceiver proxy;
+ if (null == callback) {
proxy = null;
} else {
- proxy = new InternalNetworkManagementListener(executor, listener);
+ proxy = new NetworkInterfaceOutcomeReceiver(executor, callback);
}
return proxy;
}
@@ -492,14 +541,17 @@ public class EthernetManager {
* Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities}
* object for this network to put inside the {@code request}.
*
- * If non-null, the listener will be called exactly once after this is called, unless
- * a synchronous exception was thrown.
+ * This function accepts an {@link OutcomeReceiver} that is called once the operation has
+ * finished execution.
*
* @param iface the name of the interface to act upon.
* @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's
* {@link StaticIpConfiguration} and {@link NetworkCapabilities} values.
- * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
- * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+ * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+ * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+ * operation. On success, {@link OutcomeReceiver#onResult} is called with the
+ * interface name. On error, {@link OutcomeReceiver#onError} is called with more
+ * information about the error.
* @throws SecurityException if the process doesn't hold
* {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
* @throws UnsupportedOperationException if called on a non-automotive device or on an
@@ -515,11 +567,11 @@ public class EthernetManager {
@NonNull String iface,
@NonNull EthernetNetworkUpdateRequest request,
@Nullable @CallbackExecutor Executor executor,
- @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
Objects.requireNonNull(iface, "iface must be non-null");
Objects.requireNonNull(request, "request must be non-null");
- final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
- executor, listener);
+ final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+ executor, callback);
try {
mService.updateConfiguration(iface, request, proxy);
} catch (RemoteException e) {
@@ -528,20 +580,20 @@ public class EthernetManager {
}
/**
- * Set an ethernet network's link state up.
+ * Enable a network interface.
*
- * When the link is successfully turned up, the listener will be called with the resulting
- * network. If any error or unexpected condition happens while the system tries to turn the
- * interface up, the listener will be called with an appropriate exception.
- * The listener is guaranteed to be called exactly once for each call to this method, but this
- * may take an unbounded amount of time depending on the actual network conditions.
+ * Enables a previously disabled network interface.
+ * This function accepts an {@link OutcomeReceiver} that is called once the operation has
+ * finished execution.
*
- * @param iface the name of the interface to act upon.
- * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
- * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+ * @param iface the name of the interface to enable.
+ * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+ * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+ * operation. On success, {@link OutcomeReceiver#onResult} is called with the
+ * interface name. On error, {@link OutcomeReceiver#onError} is called with more
+ * information about the error.
* @throws SecurityException if the process doesn't hold
* {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
- * @throws UnsupportedOperationException if called on a non-automotive device.
* @hide
*/
@SystemApi
@@ -550,13 +602,13 @@ public class EthernetManager {
android.Manifest.permission.NETWORK_STACK,
android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
- public void connectNetwork(
+ public void enableInterface(
@NonNull String iface,
@Nullable @CallbackExecutor Executor executor,
- @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
Objects.requireNonNull(iface, "iface must be non-null");
- final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
- executor, listener);
+ final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+ executor, callback);
try {
mService.connectNetwork(iface, proxy);
} catch (RemoteException e) {
@@ -565,19 +617,21 @@ public class EthernetManager {
}
/**
- * Set an ethernet network's link state down.
+ * Disable a network interface.
*
- * When the link is successfully turned down, the listener will be called with the network that
- * was torn down, if any. If any error or unexpected condition happens while the system tries to
- * turn the interface down, the listener will be called with an appropriate exception.
- * The listener is guaranteed to be called exactly once for each call to this method.
+ * Disables the use of a network interface to fulfill network requests. If the interface
+ * currently serves a request, the network will be torn down.
+ * This function accepts an {@link OutcomeReceiver} that is called once the operation has
+ * finished execution.
*
- * @param iface the name of the interface to act upon.
- * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
- * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+ * @param iface the name of the interface to disable.
+ * @param executor an {@link Executor} to execute the callback on. Optional if callback is null.
+ * @param callback an optional {@link OutcomeReceiver} to listen for completion of the
+ * operation. On success, {@link OutcomeReceiver#onResult} is called with the
+ * interface name. On error, {@link OutcomeReceiver#onError} is called with more
+ * information about the error.
* @throws SecurityException if the process doesn't hold
* {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
- * @throws UnsupportedOperationException if called on a non-automotive device.
* @hide
*/
@SystemApi
@@ -586,17 +640,90 @@ public class EthernetManager {
android.Manifest.permission.NETWORK_STACK,
android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
- public void disconnectNetwork(
+ public void disableInterface(
@NonNull String iface,
@Nullable @CallbackExecutor Executor executor,
- @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+ @Nullable OutcomeReceiver<String, EthernetNetworkManagementException> callback) {
Objects.requireNonNull(iface, "iface must be non-null");
- final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
- executor, listener);
+ final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver(
+ executor, callback);
try {
mService.disconnectNetwork(iface, proxy);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Change ethernet setting.
+ *
+ * @param enabled enable or disable ethernet settings.
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void setEthernetEnabled(boolean enabled) {
+ try {
+ mService.setEthernetEnabled(enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Listen to changes in the state of ethernet.
+ *
+ * @param executor to run callbacks on.
+ * @param listener to listen ethernet state changed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void addEthernetStateListener(@NonNull Executor executor,
+ @NonNull IntConsumer listener) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
+ synchronized (mListenerLock) {
+ maybeAddServiceListener();
+ mEthernetStateListeners.add(new ListenerInfo<IntConsumer>(executor, listener));
+ }
+ }
+
+ /**
+ * Removes a listener.
+ *
+ * @param listener to listen ethernet state changed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void removeEthernetStateListener(@NonNull IntConsumer listener) {
+ Objects.requireNonNull(listener);
+ synchronized (mListenerLock) {
+ mEthernetStateListeners.removeIf(l -> l.listener == listener);
+ maybeRemoveServiceListener();
+ }
+ }
+
+ /**
+ * Returns an array of existing Ethernet interface names regardless whether the interface
+ * is available or not currently.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ @SystemApi(client = MODULE_LIBRARIES)
+ @NonNull
+ public List<String> getInterfaceList() {
+ try {
+ return mService.getInterfaceList();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
index 43f4c40f2d27..1691942c3675 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
@@ -33,17 +33,20 @@ import java.util.Objects;
*/
@SystemApi
public final class EthernetNetworkUpdateRequest implements Parcelable {
- @NonNull
+ @Nullable
private final IpConfiguration mIpConfig;
@Nullable
private final NetworkCapabilities mNetworkCapabilities;
/**
- * @return the new {@link IpConfiguration}.
+ * Setting the {@link IpConfiguration} is optional in {@link EthernetNetworkUpdateRequest}.
+ * When set to null, the existing IpConfiguration is not updated.
+ *
+ * @return the new {@link IpConfiguration} or null.
*/
- @NonNull
+ @Nullable
public IpConfiguration getIpConfiguration() {
- return new IpConfiguration(mIpConfig);
+ return mIpConfig == null ? null : new IpConfiguration(mIpConfig);
}
/**
@@ -57,9 +60,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities);
}
- private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig,
+ private EthernetNetworkUpdateRequest(@Nullable final IpConfiguration ipConfig,
@Nullable final NetworkCapabilities networkCapabilities) {
- Objects.requireNonNull(ipConfig);
mIpConfig = ipConfig;
mNetworkCapabilities = networkCapabilities;
}
@@ -90,7 +92,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
*/
public Builder(@NonNull final EthernetNetworkUpdateRequest request) {
Objects.requireNonNull(request);
- mBuilderIpConfig = new IpConfiguration(request.mIpConfig);
+ mBuilderIpConfig = null == request.mIpConfig
+ ? null : new IpConfiguration(request.mIpConfig);
mBuilderNetworkCapabilities = null == request.mNetworkCapabilities
? null : new NetworkCapabilities(request.mNetworkCapabilities);
}
@@ -101,8 +104,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
* @return The builder to facilitate chaining.
*/
@NonNull
- public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) {
- mBuilderIpConfig = new IpConfiguration(ipConfig);
+ public Builder setIpConfiguration(@Nullable final IpConfiguration ipConfig) {
+ mBuilderIpConfig = ipConfig == null ? null : new IpConfiguration(ipConfig);
return this;
}
@@ -119,9 +122,16 @@ public final class EthernetNetworkUpdateRequest implements Parcelable {
/**
* Build {@link EthernetNetworkUpdateRequest} return the current update request.
+ *
+ * @throws IllegalStateException when both mBuilderNetworkCapabilities and mBuilderIpConfig
+ * are null.
*/
@NonNull
public EthernetNetworkUpdateRequest build() {
+ if (mBuilderIpConfig == null && mBuilderNetworkCapabilities == null) {
+ throw new IllegalStateException(
+ "Cannot construct an empty EthernetNetworkUpdateRequest");
+ }
return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities);
}
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
index 544d02ba76ff..42e4c1ac55aa 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl
@@ -18,10 +18,13 @@ package android.net;
import android.net.IpConfiguration;
import android.net.IEthernetServiceListener;
-import android.net.IEthernetNetworkManagementListener;
+import android.net.EthernetNetworkManagementException;
import android.net.EthernetNetworkUpdateRequest;
+import android.net.INetworkInterfaceOutcomeReceiver;
import android.net.ITetheredInterfaceCallback;
+import java.util.List;
+
/**
* Interface that answers queries about, and allows changing
* ethernet configuration.
@@ -39,7 +42,9 @@ interface IEthernetManager
void requestTetheredInterface(in ITetheredInterfaceCallback callback);
void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request,
- in IEthernetNetworkManagementListener listener);
- void connectNetwork(String iface, in IEthernetNetworkManagementListener listener);
- void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener);
+ in INetworkInterfaceOutcomeReceiver listener);
+ void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener);
+ void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener);
+ void setEthernetEnabled(boolean enabled);
+ List<String> getInterfaceList();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
index 6d2ba03f78d4..751605bb3849 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl
@@ -21,6 +21,7 @@ import android.net.IpConfiguration;
/** @hide */
oneway interface IEthernetServiceListener
{
+ void onEthernetStateChanged(int state);
void onInterfaceStateChanged(String iface, int state, int role,
in IpConfiguration configuration);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl
index 93edccfdafd9..85795ead7aea 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl
@@ -17,9 +17,9 @@
package android.net;
import android.net.EthernetNetworkManagementException;
-import android.net.Network;
/** @hide */
-oneway interface IEthernetNetworkManagementListener {
- void onComplete(in Network network, in EthernetNetworkManagementException exception);
+oneway interface INetworkInterfaceOutcomeReceiver {
+ void onResult(in String iface);
+ void onError(in EthernetNetworkManagementException e);
} \ No newline at end of file
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
index 06f2a621bcae..bcfeab96081a 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
import android.annotation.IntDef;
@@ -124,7 +126,6 @@ public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Ent
public @Nullable static final String[] INTERFACES_ALL = null;
/** {@link #tag} value for total data across all tags. */
- // TODO: Rename TAG_NONE to TAG_ALL.
public static final int TAG_NONE = 0;
/** {@link #metered} value to account for all metered states. */
@@ -390,77 +391,102 @@ public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Ent
/**
* @return the uid of this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public int getUid() {
return uid;
}
/**
* @return the set state of this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
@State public int getSet() {
return set;
}
/**
* @return the tag value of this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public int getTag() {
return tag;
}
/**
* @return the metered state.
+ * @hide
*/
- @Meteredness public int getMetered() {
+ @Meteredness
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getMetered() {
return metered;
}
/**
* @return the roaming state.
+ * @hide
*/
- @Roaming public int getRoaming() {
+ @Roaming
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getRoaming() {
return roaming;
}
/**
* @return the default network state.
+ * @hide
*/
- @DefaultNetwork public int getDefaultNetwork() {
+ @DefaultNetwork
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getDefaultNetwork() {
return defaultNetwork;
}
/**
* @return the number of received bytes.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getRxBytes() {
return rxBytes;
}
/**
* @return the number of received packets.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getRxPackets() {
return rxPackets;
}
/**
* @return the number of transmitted bytes.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getTxBytes() {
return txBytes;
}
/**
* @return the number of transmitted packets.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getTxPackets() {
return txPackets;
}
/**
* @return the count of network operations performed for this entry.
+ * @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public long getOperations() {
return operations;
}
@@ -682,7 +708,7 @@ public final class NetworkStats implements Parcelable, Iterable<NetworkStats.Ent
* The remove() method is not implemented and will throw UnsupportedOperationException.
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@NonNull public Iterator<Entry> iterator() {
return new Iterator<Entry>() {
int mIndex = 0;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
index bc836d857e3e..dc4ac552a4bb 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
@@ -205,7 +205,7 @@ public class TrafficStats {
* server context.
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SystemApi(client = MODULE_LIBRARIES)
@SuppressLint("VisiblySynchronized")
public static synchronized void init(@NonNull final Context context) {
if (sStatsService != null) {
@@ -376,7 +376,7 @@ public class TrafficStats {
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
public static void setThreadStatsTagDownload() {
setThreadStatsTag(TAG_SYSTEM_DOWNLOAD);
}
@@ -468,7 +468,7 @@ public class TrafficStats {
*
* @see #setThreadStatsTag(int)
*/
- public static void tagSocket(Socket socket) throws SocketException {
+ public static void tagSocket(@NonNull Socket socket) throws SocketException {
SocketTagger.get().tag(socket);
}
@@ -483,7 +483,7 @@ public class TrafficStats {
* calling {@code untagSocket()} before sending the socket to another
* process.
*/
- public static void untagSocket(Socket socket) throws SocketException {
+ public static void untagSocket(@NonNull Socket socket) throws SocketException {
SocketTagger.get().untag(socket);
}
@@ -496,14 +496,14 @@ public class TrafficStats {
*
* @see #setThreadStatsTag(int)
*/
- public static void tagDatagramSocket(DatagramSocket socket) throws SocketException {
+ public static void tagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException {
SocketTagger.get().tag(socket);
}
/**
* Remove any statistics parameters from the given {@link DatagramSocket}.
*/
- public static void untagDatagramSocket(DatagramSocket socket) throws SocketException {
+ public static void untagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException {
SocketTagger.get().untag(socket);
}
@@ -516,7 +516,7 @@ public class TrafficStats {
*
* @see #setThreadStatsTag(int)
*/
- public static void tagFileDescriptor(FileDescriptor fd) throws IOException {
+ public static void tagFileDescriptor(@NonNull FileDescriptor fd) throws IOException {
SocketTagger.get().tag(fd);
}
@@ -524,7 +524,7 @@ public class TrafficStats {
* Remove any statistics parameters from the given {@link FileDescriptor}
* socket.
*/
- public static void untagFileDescriptor(FileDescriptor fd) throws IOException {
+ public static void untagFileDescriptor(@NonNull FileDescriptor fd) throws IOException {
SocketTagger.get().untag(fd);
}
diff --git a/packages/SettingsLib/SearchWidget/res/values-or/strings.xml b/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
index cf824deecd79..322571adc89c 100644
--- a/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-or/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"ସେଟିଂସ୍ ସନ୍ଧାନ କରନ୍ତୁ"</string>
+ <string name="search_menu" msgid="1914043873178389845">"ସେଟିଂସ ସନ୍ଧାନ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
new file mode 100644
index 000000000000..221d2db00031
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_text_color_primary.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:alpha="?android:attr/disabledAlpha"
+ android:color="@color/settingslib_text_color_primary_device_default"/>
+ <item android:color="@color/settingslib_text_color_primary_device_default"/>
+</selector>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 9d3991119338..cba1a9cf0003 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -17,7 +17,7 @@
<resources>
<style name="TextAppearance.PreferenceTitle.SettingsLib"
parent="@android:style/TextAppearance.Material.Subhead">
- <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
+ <item name="android:textColor">@color/settingslib_text_color_primary</item>
<item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20sp</item>
</style>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 579e3d7a6d39..31036ec152d9 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1038,23 +1038,6 @@
<!-- Developer settings: text for the WebView provider selection toast shown if an invalid provider was chosen (i.e. the setting list was stale). [CHAR LIMIT=NONE] -->
<string name="select_webview_provider_toast_text">This choice is no longer valid. Try again.</string>
- <!-- Developer settings screen, convert userdata to file encryption option name -->
- <string name="convert_to_file_encryption">Convert to file encryption</string>
- <!-- Developer settings screen, convert userdata to file encryption summary when option is available -->
- <string name="convert_to_file_encryption_enabled">Convert\u2026</string>
- <!-- Developer settings screen, convert userdata to file encryption summary when option is already done -->
- <string name="convert_to_file_encryption_done">Already file encrypted</string>
- <!-- Title used on dialog with final prompt for converting to file encryption -->
- <string name="title_convert_fbe">Converting to file based encryption</string>
- <!-- Warning displayed on dialog with final prompt for converting to file encryption -->
- <string name="convert_to_fbe_warning">
- Convert data partition to file based encryption.\n
- !!Warning!! This will erase all your data.\n
- This feature is alpha, and may not work correctly.\n
- Press \'Wipe and convert\u2026\' to continue.</string>
- <!-- Button on dialog that triggers convertion to file encryption -->
- <string name="button_convert_fbe">Wipe and convert\u2026</string>
-
<!-- Name of feature to change color setting for the display [CHAR LIMIT=60] -->
<string name="picture_color_mode">Picture color mode</string>
@@ -1582,4 +1565,11 @@
<string name="keyboard_layout_dialog_title">Choose keyboard layout</string>
<!-- Label of the default keyboard layout. [CHAR LIMIT=35] -->
<string name="keyboard_layout_default_label">Default</string>
+
+ <!-- Special access > Title for managing turn screen on settings. [CHAR LIMIT=50] -->
+ <string name="turn_screen_on_title">Turn screen on</string>
+ <!-- Label for a setting which controls whether an app can turn the screen on [CHAR LIMIT=45] -->
+ <string name="allow_turn_screen_on">Allow turning the screen on</string>
+ <!-- Description for a setting which controls whether an app can turn the screen on [CHAR LIMIT=NONE] -->
+ <string name="allow_turn_screen_on_description">Allow an app to turn the screen on. If granted, the app may turn on the screen at any time without your explicit intent.</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index e4efae2f1a36..7e8ce2b5b29d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -23,12 +23,15 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Build;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
+import androidx.annotation.RequiresApi;
+import androidx.core.os.BuildCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@@ -102,11 +105,9 @@ public class RestrictedPreferenceHelper {
if (mDisabledSummary) {
final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
if (summaryView != null) {
- final CharSequence disabledText = mContext
- .getSystemService(DevicePolicyManager.class)
- .getString(CONTROLLED_BY_ADMIN_SUMMARY,
- () -> summaryView.getContext().getString(
- R.string.disabled_by_admin_summary_text));
+ final CharSequence disabledText = BuildCompat.isAtLeastT()
+ ? getDisabledByAdminUpdatableString()
+ : mContext.getString(R.string.disabled_by_admin_summary_text);
if (mDisabledByAdmin) {
summaryView.setText(disabledText);
} else if (mDisabledByAppOps) {
@@ -119,6 +120,13 @@ public class RestrictedPreferenceHelper {
}
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private String getDisabledByAdminUpdatableString() {
+ return mContext.getSystemService(DevicePolicyManager.class).getString(
+ CONTROLLED_BY_ADMIN_SUMMARY,
+ () -> mContext.getString(R.string.disabled_by_admin_summary_text));
+ }
+
public void useAdminDisabledSummary(boolean useSummary) {
mDisabledSummary = useSummary;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 19114cf147e4..38fad9d99aa4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -30,6 +30,7 @@ import android.net.TetheringManager;
import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
import android.os.BatteryManager;
+import android.os.Build;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -41,8 +42,10 @@ import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.core.os.BuildCompat;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
@@ -127,8 +130,9 @@ public class Utils {
String name = info != null ? info.name : null;
if (info.isManagedProfile()) {
// We use predefined values for managed profiles
- return context.getSystemService(DevicePolicyManager.class).getString(
- WORK_PROFILE_USER_LABEL, () -> context.getString(R.string.managed_user_title));
+ return BuildCompat.isAtLeastT()
+ ? getUpdatableManagedUserTitle(context)
+ : context.getString(R.string.managed_user_title);
} else if (info.isGuest()) {
name = context.getString(R.string.user_guest);
}
@@ -140,6 +144,13 @@ public class Utils {
return context.getResources().getString(R.string.running_process_item_user_label, name);
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ private static String getUpdatableManagedUserTitle(Context context) {
+ return context.getSystemService(DevicePolicyManager.class).getString(
+ WORK_PROFILE_USER_LABEL,
+ () -> context.getString(R.string.managed_user_title));
+ }
+
/**
* Returns a circular icon for a user.
*/
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 7f300cafaa08..2a28891e9158 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -753,7 +753,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
ParcelUuid[] uuids = mDevice.getUuids();
if (uuids == null) return false;
- ParcelUuid[] localUuids = mLocalAdapter.getUuids();
+ List<ParcelUuid> uuidsList = mLocalAdapter.getUuidsList();
+ ParcelUuid[] localUuids = new ParcelUuid[uuidsList.size()];
+ uuidsList.toArray(localUuids);
+
if (localUuids == null) return false;
/*
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
index e7a6b327bacd..31cc6a4ba412 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -126,7 +126,10 @@ public class LocalBluetoothAdapter {
}
public ParcelUuid[] getUuids() {
- return mAdapter.getUuids();
+ List<ParcelUuid> uuidsList = mAdapter.getUuidsList();
+ ParcelUuid[] uuidsArray = new ParcelUuid[uuidsList.size()];
+ uuidsList.toArray(uuidsArray);
+ return uuidsArray;
}
public boolean isDiscovering() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
index c61f8a9c3b53..be420ac8bd24 100644
--- a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
@@ -31,6 +31,8 @@ import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+
/**
* An interface class to manage connectivity subsystem recovery/restart operations.
*/
@@ -193,22 +195,30 @@ public class ConnectivitySubsystemsRecoveryManager {
mApmMonitorRegistered = false;
}
- private void startTrackingWifiRestart() {
+ @VisibleForTesting
+ void startTrackingWifiRestart() {
+ if (mWifiManager == null) return;
mWifiManager.registerSubsystemRestartTrackingCallback(new HandlerExecutor(mHandler),
mWifiSubsystemRestartTrackingCallback);
}
- private void stopTrackingWifiRestart() {
+ @VisibleForTesting
+ void stopTrackingWifiRestart() {
+ if (mWifiManager == null) return;
mWifiManager.unregisterSubsystemRestartTrackingCallback(
mWifiSubsystemRestartTrackingCallback);
}
- private void startTrackingTelephonyRestart() {
+ @VisibleForTesting
+ void startTrackingTelephonyRestart() {
+ if (mTelephonyManager == null) return;
mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(mHandler),
mTelephonyCallback);
}
- private void stopTrackingTelephonyRestart() {
+ @VisibleForTesting
+ void stopTrackingTelephonyRestart() {
+ if (mTelephonyManager == null) return;
mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
index 0cb2c0b22a4c..63a9f0c5c7f4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
@@ -78,6 +78,11 @@ class AvatarPhotoController {
static final int REQUEST_CODE_TAKE_PHOTO = 1002;
static final int REQUEST_CODE_CROP_PHOTO = 1003;
+ /**
+ * Delay to allow the photo picker exit animation to complete before the crop activity opens.
+ */
+ private static final long DELAY_BEFORE_CROP_MILLIS = 150;
+
private static final String IMAGES_DIR = "multi_user";
private static final String PRE_CROP_PICTURE_FILE_NAME = "PreCropEditUserPhoto.jpg";
private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
@@ -131,13 +136,15 @@ class AvatarPhotoController {
mAvatarUi.returnUriResult(pictureUri);
return true;
case REQUEST_CODE_TAKE_PHOTO:
- case REQUEST_CODE_CHOOSE_PHOTO:
if (mTakePictureUri.equals(pictureUri)) {
cropPhoto(pictureUri);
} else {
- copyAndCropPhoto(pictureUri);
+ copyAndCropPhoto(pictureUri, false);
}
return true;
+ case REQUEST_CODE_CHOOSE_PHOTO:
+ copyAndCropPhoto(pictureUri, true);
+ return true;
}
return false;
}
@@ -154,7 +161,7 @@ class AvatarPhotoController {
mAvatarUi.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO);
}
- private void copyAndCropPhoto(final Uri pictureUri) {
+ private void copyAndCropPhoto(final Uri pictureUri, boolean delayBeforeCrop) {
try {
ThreadUtils.postOnBackgroundThread(() -> {
final ContentResolver cr = mContextInjector.getContentResolver();
@@ -165,11 +172,17 @@ class AvatarPhotoController {
Log.w(TAG, "Failed to copy photo", e);
return;
}
- ThreadUtils.postOnMainThread(() -> {
+ Runnable cropRunnable = () -> {
if (!mAvatarUi.isFinishing()) {
cropPhoto(mPreCropPictureUri);
}
- });
+ };
+ if (delayBeforeCrop) {
+ ThreadUtils.postOnMainThreadDelayed(cropRunnable, DELAY_BEFORE_CROP_MILLIS);
+ } else {
+ ThreadUtils.postOnMainThread(cropRunnable);
+ }
+
}).get();
} catch (InterruptedException | ExecutionException e) {
Log.e(TAG, "Error performing copy-and-crop", e);
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
index 69f1c17f97b1..2c1d5da5e941 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
@@ -84,6 +84,13 @@ public class ThreadUtils {
getUiThreadHandler().post(runnable);
}
+ /**
+ * Posts the runnable on the main thread with a delay.
+ */
+ public static void postOnMainThreadDelayed(Runnable runnable, long delayMillis) {
+ getUiThreadHandler().postDelayed(runnable, delayMillis);
+ }
+
private static synchronized ExecutorService getThreadExecutor() {
if (sThreadExecutor == null) {
sThreadExecutor = Executors.newFixedThreadPool(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java
new file mode 100644
index 000000000000..ca53a187d6f8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManagerTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.settingslib.connectivity;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class ConnectivitySubsystemsRecoveryManagerTest {
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Spy
+ Context mContext = ApplicationProvider.getApplicationContext();
+ @Spy
+ Handler mMainHandler = ApplicationProvider.getApplicationContext().getMainThreadHandler();
+ @Mock
+ PackageManager mPackageManager;
+
+ ConnectivitySubsystemsRecoveryManager mConnectivitySubsystemsRecoveryManager;
+
+ @Before
+ public void setUp() {
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(true);
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
+ }
+
+ @Test
+ public void startTrackingWifiRestart_hasNoWifiFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.startTrackingWifiRestart();
+ }
+
+ @Test
+ public void stopTrackingWifiRestart_hasNoWifiFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.stopTrackingWifiRestart();
+ }
+
+ @Test
+ public void startTrackingTelephonyRestart_hasNoTelephonyFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.startTrackingTelephonyRestart();
+ }
+
+ @Test
+ public void stopTrackingTelephonyRestart_hasNoTelephonyFeature_shouldNotCrash() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(false);
+ mConnectivitySubsystemsRecoveryManager =
+ new ConnectivitySubsystemsRecoveryManager(mContext, mMainHandler);
+
+ mConnectivitySubsystemsRecoveryManager.stopTrackingTelephonyRestart();
+ }
+}
diff --git a/packages/SettingsProvider/res/values-or/strings.xml b/packages/SettingsProvider/res/values-or/strings.xml
index 486d8ffaa500..85add41b1ee1 100644
--- a/packages/SettingsProvider/res/values-or/strings.xml
+++ b/packages/SettingsProvider/res/values-or/strings.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4567566098528588863">"ସେଟିଙ୍ଗ ଷ୍ଟୋରେଜ୍‌"</string>
+ <string name="app_label" msgid="4567566098528588863">"ସେଟିଂସ ଷ୍ଟୋରେଜ୍‌"</string>
<string name="wifi_softap_config_change" msgid="5688373762357941645">"ହଟସ୍ପଟ୍ ସେଟିଂସ୍ ବଦଳାଯାଇଛି"</string>
<string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"ବିବରଣୀ ଦେଖିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e24b2d6c6aa9..4b45cc338a6a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -314,6 +314,11 @@
<!-- To change system captions state -->
<uses-permission android:name="android.permission.SET_SYSTEM_AUDIO_CAPTION" />
+ <!-- Compat framework -->
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 8d205c14144d..9a6f5edae5ec 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -129,4 +129,7 @@
<dimen name="user_switcher_icon_selected_width">8dp</dimen>
<dimen name="user_switcher_fullscreen_button_text_size">14sp</dimen>
<dimen name="user_switcher_fullscreen_button_padding">12dp</dimen>
+
+ <!-- Translation y for appear animation -->
+ <dimen name="keyguard_host_view_translation_y">80dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/drawable/media_ttt_undo_background.xml b/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
index ec74ee1fcbf1..3e2e4f055b14 100644
--- a/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
+++ b/packages/SystemUI/res/drawable/media_ttt_undo_background.xml
@@ -14,9 +14,14 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape
+<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <solid android:color="?androidprv:attr/colorAccentPrimary" />
- <corners android:radius="24dp" />
-</shape>
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:color="?android:textColorPrimary">
+ <item android:id="@android:id/background">
+ <shape>
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+ <corners android:radius="24dp" />
+ </shape>
+ </item>
+</ripple>
diff --git a/packages/SystemUI/res/drawable/user_switcher_icon_large.xml b/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
index 1ed75537059a..d81b518d2a9f 100644
--- a/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
+++ b/packages/SystemUI/res/drawable/user_switcher_icon_large.xml
@@ -27,7 +27,7 @@
</shape>
</item>
<!-- When an item is selected, this layer will show a ring around the icon -->
- <item>
+ <item android:id="@+id/ring">
<shape android:shape="oval">
<stroke
android:width="@dimen/user_switcher_icon_selected_width"
@@ -35,7 +35,7 @@
</shape>
</item>
<!-- Where the user drawable/bitmap will be placed -->
- <item
+ <item android:id="@+id/user_avatar"
android:drawable="@drawable/user_avatar_bg"
android:width="@dimen/bouncer_user_switcher_icon_size"
android:height="@dimen/bouncer_user_switcher_icon_size"
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index ad2bc79a5c96..5aa608084510 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -37,7 +37,5 @@
android:layout_gravity="center"
android:minWidth="@dimen/ongoing_appops_chip_min_width"
android:maxWidth="@dimen/ongoing_appops_chip_max_width"
- android:clipChildren="false"
- android:clipToPadding="false"
/>
</com.android.systemui.privacy.OngoingPrivacyChip> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 02a4070415dd..740697ba98af 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -54,6 +54,14 @@
the shade (in alpha) -->
<dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
+ <!-- The notifications scrim transition should start when the other scrims' transition is at
+ 95%. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_delay">76dp</dimen>
+
+ <!-- The notifications scrim transition duration is 66.6% of the duration of the other scrims'
+ transition. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_distance">53.28dp</dimen>
+
<!-- Distance that the full shade transition takes in order for the keyguard content on
NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
<dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">80dp</dimen>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a0a876825a6f..9ea361892b32 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -707,4 +707,18 @@
<integer name="complicationFadeInMs">500</integer>
<integer name="complicationRestoreMs">1000</integer>
+
+ <!-- Icons that don't show in a collapsed non-keyguard statusbar -->
+ <string-array name="config_collapsed_statusbar_icon_blocklist" translatable="false">
+ <item>@*android:string/status_bar_volume</item>
+ <item>@*android:string/status_bar_alarm_clock</item>
+ <item>@*android:string/status_bar_call_strength</item>
+ </string-array>
+
+ <!-- Icons that don't show in a collapsed statusbar on keyguard -->
+ <string-array name="config_keyguard_statusbar_icon_blocklist" translatable="false">
+ <item>@*android:string/status_bar_volume</item>
+ <item>@*android:string/status_bar_alarm_clock</item>
+ <item>@*android:string/status_bar_call_strength</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ffae6015c732..8f4e11527d95 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -941,6 +941,9 @@
<!-- Three privacy items. This value must not be exceeded -->
<dimen name="ongoing_appops_chip_max_width">76dp</dimen>
<dimen name="ongoing_appops_dot_diameter">6dp</dimen>
+ <dimen name="ongoing_appops_chip_min_animation_width">10dp</dimen>
+ <dimen name="ongoing_appops_chip_animation_in_status_bar_translation_x">15dp</dimen>
+ <dimen name="ongoing_appops_chip_animation_out_status_bar_translation_x">7dp</dimen>
<!-- Total minimum padding to enforce to ensure that the dot can always show -->
<dimen name="ongoing_appops_dot_min_padding">20dp</dimen>
@@ -1005,6 +1008,9 @@
<!-- Media tap-to-transfer chip for receiver device -->
<dimen name="media_ttt_chip_size_receiver">100dp</dimen>
<dimen name="media_ttt_icon_size_receiver">95dp</dimen>
+ <!-- Since the generic icon isn't circular, we need to scale it down so it still fits within
+ the circular chip. -->
+ <dimen name="media_ttt_generic_icon_size_receiver">70dp</dimen>
<!-- Window magnification -->
<dimen name="magnification_border_drag_size">35dp</dimen>
@@ -1138,6 +1144,12 @@
the shade (in alpha) -->
<dimen name="lockscreen_shade_scrim_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
+ <!-- Distance that it takes in order for the notifications scrim fade in to start. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_delay">0dp</dimen>
+
+ <!-- Distance that it takes for the notifications scrim to fully fade if after it started. -->
+ <dimen name="lockscreen_shade_notifications_scrim_transition_distance">@dimen/lockscreen_shade_scrim_transition_distance</dimen>
+
<!-- Distance that the full shade transition takes in order for the keyguard content on
NotificationPanelViewController to fully fade (e.g. Clock & Smartspace) -->
<dimen name="lockscreen_shade_npvc_keyguard_content_alpha_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d230f33f4939..6dc6214fec65 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2184,7 +2184,7 @@
<!-- Text informing the user that their media is now playing on this device. [CHAR LIMIT=50] -->
<string name="media_transfer_playing_this_device">Playing on this phone</string>
<!-- Text informing the user that the media transfer has failed because something went wrong. [CHAR LIMIT=50] -->
- <string name="media_transfer_failed">Something went wrong</string>
+ <string name="media_transfer_failed">Something went wrong. Try again.</string>
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
<string name="controls_error_timeout">Inactive, check app</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt b/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
new file mode 100644
index 000000000000..497d81f6bdc5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.keyguard
+
+import android.util.MathUtils
+
+object BouncerPanelExpansionCalculator {
+ /**
+ * Scale the alpha/position of the host view.
+ */
+ @JvmStatic
+ fun getHostViewScaledExpansion(fraction: Float): Float {
+ return when {
+ fraction >= 0.9f -> 1f
+ fraction < 0.6 -> 0f
+ else -> (fraction - 0.6f) / 0.3f
+ }
+ }
+
+ /**
+ * Scale the alpha/tint of the back scrim.
+ */
+ @JvmStatic
+ fun getBackScrimScaledExpansion(fraction: Float): Float {
+ return MathUtils.constrain((fraction - 0.9f) / 0.1f, 0f, 1f)
+ }
+
+ /**
+ * This will scale the alpha/position of the clock.
+ */
+ @JvmStatic
+ fun getKeyguardClockScaledExpansion(fraction: Float): Float {
+ return MathUtils.constrain((fraction - 0.7f) / 0.3f, 0f, 1f)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index b6910961bcb4..8c3e066849b9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -37,7 +37,6 @@ import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.util.ViewController;
import java.io.File;
@@ -64,6 +63,7 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
private ActivityStarter.OnDismissAction mDismissAction;
private Runnable mCancelAction;
+ private int mTranslationY;
private final KeyguardUpdateMonitorCallback mUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@@ -322,12 +322,14 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
/**
* Fades and translates in/out the security screen.
+ * Fades in as expansion approaches 0.
+ * Animation duration is between 0.33f and 0.67f of panel expansion fraction.
* @param fraction amount of the screen that should show.
*/
public void setExpansion(float fraction) {
- float alpha = MathUtils.map(KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
- mView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
- mView.setTranslationY(fraction * mView.getHeight());
+ float scaledFraction = BouncerPanelExpansionCalculator.getHostViewScaledExpansion(fraction);
+ mView.setAlpha(MathUtils.constrain(1 - scaledFraction, 0f, 1f));
+ mView.setTranslationY(scaledFraction * mTranslationY);
}
/**
@@ -490,6 +492,8 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
gravity = resources.getInteger(R.integer.keyguard_host_view_gravity);
}
+ mTranslationY = resources
+ .getDimensionPixelSize(R.dimen.keyguard_host_view_translation_y);
// Android SysUI uses a FrameLayout as the top-level, but Auto uses RelativeLayout.
// We're just changing the gravity here though (which can't be applied to RelativeLayout),
// so only attempt the update if mView is inside a FrameLayout.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 362fbed7055a..46a883194e25 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -152,6 +152,7 @@ public class KeyguardSecurityContainer extends FrameLayout {
private SwipeListener mSwipeListener;
private ViewMode mViewMode = new DefaultViewMode();
private @Mode int mCurrentMode = MODE_DEFAULT;
+ private int mWidth = -1;
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -649,9 +650,11 @@ public class KeyguardSecurityContainer extends FrameLayout {
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- // After a layout pass, we need to re-place the inner bouncer, as our bounds may have
- // changed.
- mViewMode.updateSecurityViewLocation();
+ int width = right - left;
+ if (changed && mWidth != width) {
+ mWidth = width;
+ mViewMode.updateSecurityViewLocation();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 74659f71eb1f..e36e984380e2 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -211,6 +211,23 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mDownDetected = false;
updateBurnInOffsets();
updateVisibility();
+
+ updateAccessibility();
+ }
+
+ private void updateAccessibility() {
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ mView.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onLongPress();
+ }
+ }
+ );
+ } else {
+ mView.setOnClickListener(null);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index a27b9cd357f4..b811c51c952b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -116,7 +116,7 @@ class AuthRippleController @Inject constructor(
}
fun showRipple(biometricSourceType: BiometricSourceType?) {
- if (!keyguardUpdateMonitor.isKeyguardVisible ||
+ if (!(keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.isDreaming) ||
keyguardUpdateMonitor.userNeedsStrongAuth()) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index bc7a3f6f4b13..975e0c5b32cd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -49,7 +49,6 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.VelocityTracker;
-import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -92,7 +91,7 @@ import kotlin.Unit;
* Note that the current architecture is designed so that a single {@link UdfpsController}
* controls/manages all UDFPS sensors. In other words, a single controller is registered with
* {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService}, and interfaces such
- * as {@link FingerprintManager#onPointerDown(int, int, int, float, float)} or
+ * as {@link FingerprintManager#onPointerDown(long, int, int, int, float, float)} or
* {@link IUdfpsOverlayController#showUdfpsOverlay} should all have
* {@code sensorId} parameters.
*/
@@ -193,7 +192,7 @@ public class UdfpsController implements DozeReceiver {
public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
@Override
- public void showUdfpsOverlay(int sensorId, int reason,
+ public void showUdfpsOverlay(long requestId, int sensorId, int reason,
@NonNull IUdfpsOverlayControllerCallback callback) {
mFgExecutor.execute(
() -> UdfpsController.this.showUdfpsOverlay(new UdfpsControllerOverlay(
@@ -203,8 +202,10 @@ public class UdfpsController implements DozeReceiver {
mKeyguardUpdateMonitor, mDialogManager, mDumpManager,
mLockscreenShadeTransitionController, mConfigurationController,
mSystemClock, mKeyguardStateController,
- mUnlockedScreenOffAnimationController, mSensorProps, mHbmProvider,
- reason, callback, UdfpsController.this::onTouch,
+ mUnlockedScreenOffAnimationController, mSensorProps,
+ mHbmProvider, requestId, reason, callback,
+ (view, event, fromUdfpsView) ->
+ onTouch(requestId, event, fromUdfpsView),
mActivityLaunchAnimator)));
}
@@ -318,7 +319,8 @@ public class UdfpsController implements DozeReceiver {
if (mOverlay == null || mOverlay.isHiding()) {
return false;
}
- return onTouch(mOverlay.getOverlayView(), event, false);
+ // TODO(b/225068271): may not be correct but no way to get the id yet
+ return onTouch(mOverlay.getRequestId(), event, false);
}
/**
@@ -342,8 +344,18 @@ public class UdfpsController implements DozeReceiver {
&& getSensorLocation().contains(x, y);
}
- private boolean onTouch(@NonNull View view, @NonNull MotionEvent event, boolean fromUdfpsView) {
- UdfpsView udfpsView = (UdfpsView) view;
+ private boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
+ if (mOverlay == null) {
+ Log.w(TAG, "ignoring onTouch with null overlay");
+ return false;
+ }
+ if (!mOverlay.matchesRequestId(requestId)) {
+ Log.w(TAG, "ignoring stale touch event: " + requestId + " current: "
+ + mOverlay.getRequestId());
+ return false;
+ }
+
+ final UdfpsView udfpsView = mOverlay.getOverlayView();
final boolean isIlluminationRequested = udfpsView.isIlluminationRequested();
boolean handled = false;
switch (event.getActionMasked()) {
@@ -453,7 +465,7 @@ public class UdfpsController implements DozeReceiver {
// Do nothing to stay in portrait mode.
}
- onFingerDown(x, y, minor, major);
+ onFingerDown(requestId, x, y, minor, major);
Log.v(TAG, "onTouch | finger down: " + touchInfo);
mTouchLogTime = mSystemClock.elapsedRealtime();
mPowerManager.userActivity(mSystemClock.uptimeMillis(),
@@ -465,7 +477,7 @@ public class UdfpsController implements DozeReceiver {
}
} else {
Log.v(TAG, "onTouch | finger outside");
- onFingerUp(udfpsView);
+ onFingerUp(requestId, udfpsView);
}
}
Trace.endSection();
@@ -482,7 +494,7 @@ public class UdfpsController implements DozeReceiver {
}
Log.v(TAG, "onTouch | finger up");
mAttemptedToDismissKeyguard = false;
- onFingerUp(udfpsView);
+ onFingerUp(requestId, udfpsView);
mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
Trace.endSection();
break;
@@ -679,7 +691,7 @@ public class UdfpsController implements DozeReceiver {
// Reset the controller back to its starting state.
final UdfpsView oldView = mOverlay.getOverlayView();
if (oldView != null) {
- onFingerUp(oldView);
+ onFingerUp(mOverlay.getRequestId(), oldView);
}
final boolean removed = mOverlay.hide();
if (mKeyguardViewManager.isShowingAlternateAuth()) {
@@ -710,6 +722,8 @@ public class UdfpsController implements DozeReceiver {
return;
}
+ // TODO(b/225068271): this may not be correct but there isn't a way to track it
+ final long requestId = mOverlay != null ? mOverlay.getRequestId() : -1;
mAodInterruptRunnable = () -> {
mIsAodInterruptActive = true;
// Since the sensor that triggers the AOD interrupt doesn't provide
@@ -719,10 +733,10 @@ public class UdfpsController implements DozeReceiver {
mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelUdfps,
AOD_INTERRUPT_TIMEOUT_MILLIS);
// using a hard-coded value for major and minor until it is available from the sensor
- onFingerDown(screenX, screenY, minor, major);
+ onFingerDown(requestId, screenX, screenY, minor, major);
};
- if (mScreenOn && mAodInterruptRunnable != null) {
+ if (mScreenOn) {
mAodInterruptRunnable.run();
mAodInterruptRunnable = null;
}
@@ -755,7 +769,7 @@ public class UdfpsController implements DozeReceiver {
*/
void onCancelUdfps() {
if (mOverlay != null && mOverlay.getOverlayView() != null) {
- onFingerUp(mOverlay.getOverlayView());
+ onFingerUp(mOverlay.getRequestId(), mOverlay.getOverlayView());
}
if (!mIsAodInterruptActive) {
return;
@@ -771,12 +785,17 @@ public class UdfpsController implements DozeReceiver {
return mOnFingerDown;
}
- private void onFingerDown(int x, int y, float minor, float major) {
+ private void onFingerDown(long requestId, int x, int y, float minor, float major) {
mExecution.assertIsMainThread();
if (mOverlay == null) {
Log.w(TAG, "Null request in onFingerDown");
return;
}
+ if (!mOverlay.matchesRequestId(requestId)) {
+ Log.w(TAG, "Mismatched fingerDown: " + requestId
+ + " current: " + mOverlay.getRequestId());
+ return;
+ }
if (mOverlay.getAnimationViewController() instanceof UdfpsKeyguardViewController
&& !mStatusBarStateController.isDozing()) {
@@ -791,14 +810,14 @@ public class UdfpsController implements DozeReceiver {
}
}
mOnFingerDown = true;
- mFingerprintManager.onPointerDown(mSensorProps.sensorId, x, y, minor, major);
+ mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, x, y, minor, major);
Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
final UdfpsView view = mOverlay.getOverlayView();
if (view != null) {
Trace.beginAsyncSection("UdfpsController.e2e.startIllumination", 0);
view.startIllumination(() -> {
- mFingerprintManager.onUiReady(mSensorProps.sensorId);
+ mFingerprintManager.onUiReady(requestId, mSensorProps.sensorId);
mLatencyTracker.onActionEnd(LatencyTracker.ACTION_UDFPS_ILLUMINATE);
Trace.endAsyncSection("UdfpsController.e2e.startIllumination", 0);
});
@@ -809,12 +828,12 @@ public class UdfpsController implements DozeReceiver {
}
}
- private void onFingerUp(@NonNull UdfpsView view) {
+ private void onFingerUp(long requestId, @NonNull UdfpsView view) {
mExecution.assertIsMainThread();
mActivePointerId = -1;
mAcquiredReceived = false;
if (mOnFingerDown) {
- mFingerprintManager.onPointerUp(mSensorProps.sensorId);
+ mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId);
for (Callback cb : mCallbacks) {
cb.onFingerUp();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 086894d2e670..ee43e932b344 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -80,6 +80,7 @@ class UdfpsControllerOverlay(
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
private val sensorProps: FingerprintSensorPropertiesInternal,
private var hbmProvider: UdfpsHbmProvider,
+ val requestId: Long,
@ShowReason val requestReason: Int,
private val controllerCallback: IUdfpsOverlayControllerCallback,
private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
@@ -276,6 +277,9 @@ class UdfpsControllerOverlay(
}
}
+ /** Checks if the id is relevant for this overlay. */
+ fun matchesRequestId(id: Long): Boolean = requestId == -1L || requestId == id
+
private fun WindowManager.LayoutParams.updateForLocation(
location: SensorLocationInternal,
animation: UdfpsAnimationViewController<*>?
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index f78929f75b04..a9f340854689 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -35,6 +35,7 @@ import com.android.systemui.power.PowerUI
import com.android.systemui.recents.Recents
import com.android.systemui.shortcut.ShortcutKeyDispatcher
import com.android.systemui.statusbar.notification.InstantAppNotifier
+import com.android.systemui.statusbar.phone.KeyguardLiftController
import com.android.systemui.theme.ThemeOverlayController
import com.android.systemui.toast.ToastUI
import com.android.systemui.usb.StorageNotification
@@ -198,4 +199,10 @@ abstract class SystemUICoreStartableModule {
@IntoMap
@ClassKey(WMShell::class)
abstract fun bindWMShell(sysui: WMShell): CoreStartable
+
+ /** Inject into KeyguardLiftController. */
+ @Binds
+ @IntoMap
+ @ClassKey(KeyguardLiftController::class)
+ abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index d2ab61149d26..59a17bad5069 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -88,10 +88,6 @@ public class DreamOverlayStatusBarView extends ConstraintLayout {
fetchStatusIconForResId(R.id.dream_overlay_priority_mode));
}
- void showIcon(@StatusIconType int iconType, boolean show) {
- showIcon(iconType, show, null);
- }
-
void showIcon(@StatusIconType int iconType, boolean show, @Nullable String contentDescription) {
View icon = mStatusIcons.get(iconType);
if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index a25a7423770e..761f28c5ac3b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -16,6 +16,7 @@
package com.android.systemui.dreams;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.res.Resources;
import android.hardware.SensorPrivacyManager;
@@ -45,6 +46,7 @@ import com.android.systemui.util.time.DateFormatUtil;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -62,6 +64,9 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
private final IndividualSensorPrivacyController mSensorPrivacyController;
private final NotificationListener mNotificationListener;
private final ZenModeController mZenModeController;
+ private final Executor mMainExecutor;
+
+ private boolean mIsAttached;
private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
.clearCapabilities()
@@ -131,6 +136,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
public DreamOverlayStatusBarViewController(
DreamOverlayStatusBarView view,
@Main Resources resources,
+ @Main Executor mainExecutor,
ConnectivityManager connectivityManager,
TouchInsetManager.TouchInsetSession touchInsetSession,
AlarmManager alarmManager,
@@ -141,6 +147,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
ZenModeController zenModeController) {
super(view);
mResources = resources;
+ mMainExecutor = mainExecutor;
mConnectivityManager = connectivityManager;
mTouchInsetSession = touchInsetSession;
mAlarmManager = alarmManager;
@@ -157,6 +164,8 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
@Override
protected void onViewAttached() {
+ mIsAttached = true;
+
updateNotificationsStatusIcon();
mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
@@ -181,6 +190,8 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
mNextAlarmController.removeCallback(mNextAlarmCallback);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
mTouchInsetSession.clear();
+
+ mIsAttached = false;
}
private void updateWifiUnavailableStatusIcon() {
@@ -189,14 +200,14 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
mConnectivityManager.getActiveNetwork());
final boolean available = capabilities != null
&& capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
- mView.showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
+ showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
}
private void updateAlarmStatusIcon() {
final AlarmManager.AlarmClockInfo alarm =
mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET,
hasAlarm,
hasAlarm ? buildAlarmContentDescription(alarm) : null);
@@ -215,7 +226,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE);
final boolean cameraBlocked = mSensorPrivacyController
.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA);
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED,
micBlocked && cameraBlocked);
}
@@ -230,7 +241,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
final StatusBarNotification[] notifications =
mNotificationListener.getActiveNotifications();
final int notificationCount = notifications != null ? notifications.length : 0;
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS,
notificationCount > 0,
notificationCount > 0
@@ -246,8 +257,23 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
}
private void updatePriorityModeStatusIcon() {
- mView.showIcon(
+ showIcon(
DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON,
mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF);
}
+
+ private void showIcon(@DreamOverlayStatusBarView.StatusIconType int iconType, boolean show) {
+ showIcon(iconType, show, null);
+ }
+
+ private void showIcon(
+ @DreamOverlayStatusBarView.StatusIconType int iconType,
+ boolean show,
+ @Nullable String contentDescription) {
+ mMainExecutor.execute(() -> {
+ if (mIsAttached) {
+ mView.showIcon(iconType, show, contentDescription);
+ }
+ });
+ }
}
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 6861c7479161..1ca06b25aa9f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
@@ -16,32 +16,32 @@
package com.android.systemui.dreams.complication;
-import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS;
-import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_VIEW;
+import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationModule.DREAM_CLOCK_DATE_COMPLICATION_VIEW;
import android.content.Context;
import android.view.View;
import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.dreams.complication.dagger.DreamClockDateComplicationComponent;
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Provider;
/**
* Clock Date Complication that produce Clock Date view holder.
*/
public class DreamClockDateComplication implements Complication {
- DreamClockDateComplicationComponent.Factory mComponentFactory;
+ private final Provider<DreamClockDateViewHolder> mDreamClockDateViewHolderProvider;
/**
* Default constructor for {@link DreamClockDateComplication}.
*/
@Inject
public DreamClockDateComplication(
- DreamClockDateComplicationComponent.Factory componentFactory) {
- mComponentFactory = componentFactory;
+ Provider<DreamClockDateViewHolder> dreamClockDateViewHolderProvider) {
+ mDreamClockDateViewHolderProvider = dreamClockDateViewHolderProvider;
}
@Override
@@ -54,11 +54,11 @@ public class DreamClockDateComplication implements Complication {
*/
@Override
public ViewHolder createView(ComplicationViewModel model) {
- return mComponentFactory.create().getViewHolder();
+ return mDreamClockDateViewHolderProvider.get();
}
/**
- * {@link CoreStartable} responsbile for registering {@link DreamClockDateComplication} with
+ * {@link CoreStartable} responsible for registering {@link DreamClockDateComplication} with
* SystemUI.
*/
public static class Registrant extends CoreStartable {
@@ -84,7 +84,7 @@ public class DreamClockDateComplication implements Complication {
}
/**
- * ViewHolder to contain value/logic associated with a Clock Date Complication View.
+ * {@link ViewHolder} to contain value/logic associated with {@link DreamClockDateComplication}.
*/
public static class DreamClockDateViewHolder implements ViewHolder {
private final View mView;
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 936767a60233..7f67ecd19175 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
@@ -16,32 +16,32 @@
package com.android.systemui.dreams.complication;
-import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS;
-import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW;
+import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS;
+import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW;
import android.content.Context;
import android.view.View;
import com.android.systemui.CoreStartable;
import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationComponent;
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Provider;
/**
* Clock Time Complication that produce Clock Time view holder.
*/
public class DreamClockTimeComplication implements Complication {
- DreamClockTimeComplicationComponent.Factory mComponentFactory;
+ private final Provider<DreamClockTimeViewHolder> mDreamClockTimeViewHolderProvider;
/**
* Default constructor for {@link DreamClockTimeComplication}.
*/
@Inject
public DreamClockTimeComplication(
- DreamClockTimeComplicationComponent.Factory componentFactory) {
- mComponentFactory = componentFactory;
+ Provider<DreamClockTimeViewHolder> dreamClockTimeViewHolderProvider) {
+ mDreamClockTimeViewHolderProvider = dreamClockTimeViewHolderProvider;
}
@Override
@@ -54,11 +54,11 @@ public class DreamClockTimeComplication implements Complication {
*/
@Override
public ViewHolder createView(ComplicationViewModel model) {
- return mComponentFactory.create().getViewHolder();
+ return mDreamClockTimeViewHolderProvider.get();
}
/**
- * {@link CoreStartable} responsbile for registering {@link DreamClockTimeComplication} with
+ * {@link CoreStartable} responsible for registering {@link DreamClockTimeComplication} with
* SystemUI.
*/
public static class Registrant extends CoreStartable {
@@ -84,7 +84,7 @@ public class DreamClockTimeComplication implements Complication {
}
/**
- * ViewHolder to contain value/logic associated with a Clock Time Complication View.
+ * {@link ViewHolder} to contain value/logic associated with {@link DreamClockTimeComplication}.
*/
public static class DreamClockTimeViewHolder implements ViewHolder {
private final View mView;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java
deleted file mode 100644
index dd7f10c204e1..000000000000
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationComponent.java
+++ /dev/null
@@ -1,110 +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.systemui.dreams.complication.dagger;
-
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.internal.util.Preconditions;
-import com.android.systemui.R;
-import com.android.systemui.dreams.complication.ComplicationLayoutParams;
-import com.android.systemui.dreams.complication.DreamClockDateComplication.DreamClockDateViewHolder;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Named;
-import javax.inject.Scope;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-
-/**
- * {@link DreamClockDateComplicationComponent} is responsible for generating dependencies
- * surrounding the
- * Clock Date {@link com.android.systemui.dreams.complication.Complication}, such as the layout
- * details.
- */
-@Subcomponent(modules = {
- DreamClockDateComplicationComponent.DreamClockDateComplicationModule.class,
-})
-@DreamClockDateComplicationComponent.DreamClockDateComplicationScope
-public interface DreamClockDateComplicationComponent {
- /**
- * Creates {@link DreamClockDateViewHolder}.
- */
- DreamClockDateViewHolder getViewHolder();
-
- @Documented
- @Retention(RUNTIME)
- @Scope
- @interface DreamClockDateComplicationScope {
- }
-
- /**
- * Generates {@link DreamClockDateComplicationComponent}.
- */
- @Subcomponent.Factory
- interface Factory {
- DreamClockDateComplicationComponent create();
- }
-
- /**
- * Scoped values for {@link DreamClockDateComplicationComponent}.
- */
- @Module
- interface DreamClockDateComplicationModule {
- String DREAM_CLOCK_DATE_COMPLICATION_VIEW = "clock_date_complication_view";
- String DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS =
- "clock_date_complication_layout_params";
- // Order weight of insert into parent container
- int INSERT_ORDER_WEIGHT = 2;
-
- /**
- * Provides the complication view.
- */
- @Provides
- @DreamClockDateComplicationScope
- @Named(DREAM_CLOCK_DATE_COMPLICATION_VIEW)
- static View provideComplicationView(LayoutInflater layoutInflater) {
- return Preconditions.checkNotNull(
- layoutInflater.inflate(R.layout.dream_overlay_complication_clock_date,
- null, false),
- "R.layout.dream_overlay_complication_clock_date did not properly inflated");
- }
-
- /**
- * Provides the layout parameters for the complication view.
- */
- @Provides
- @DreamClockDateComplicationScope
- @Named(DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS)
- static ComplicationLayoutParams provideLayoutParams() {
- return new ComplicationLayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ComplicationLayoutParams.POSITION_BOTTOM
- | ComplicationLayoutParams.POSITION_START,
- ComplicationLayoutParams.DIRECTION_END,
- INSERT_ORDER_WEIGHT);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java
new file mode 100644
index 000000000000..eb2fc5d1a93e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.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 com.android.systemui.dreams.complication.dagger;
+
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.util.Preconditions;
+import com.android.systemui.R;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.DreamClockDateComplication;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Module for providing {@link DreamClockDateComplication}.
+ */
+@Module
+public interface DreamClockDateComplicationModule {
+ String DREAM_CLOCK_DATE_COMPLICATION_VIEW = "clock_date_complication_view";
+ String DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS =
+ "clock_date_complication_layout_params";
+ // Order weight of insert into parent container
+ //TODO(b/217199227): move to a single location.
+ int INSERT_ORDER_WEIGHT = 2;
+
+ /**
+ * Provides the complication view.
+ */
+ @Provides
+ @Named(DREAM_CLOCK_DATE_COMPLICATION_VIEW)
+ static View provideComplicationView(LayoutInflater layoutInflater) {
+ return Preconditions.checkNotNull(
+ layoutInflater.inflate(R.layout.dream_overlay_complication_clock_date,
+ null, false),
+ "R.layout.dream_overlay_complication_clock_date did not properly inflated");
+ }
+
+ /**
+ * Provides the layout parameters for the complication view.
+ */
+ @Provides
+ @Named(DREAM_CLOCK_DATE_COMPLICATION_LAYOUT_PARAMS)
+ static ComplicationLayoutParams provideLayoutParams() {
+ return new ComplicationLayoutParams(0,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ComplicationLayoutParams.POSITION_BOTTOM
+ | ComplicationLayoutParams.POSITION_START,
+ ComplicationLayoutParams.DIRECTION_END,
+ INSERT_ORDER_WEIGHT);
+ }
+}
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
deleted file mode 100644
index de11b61f4759..000000000000
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
+++ /dev/null
@@ -1,115 +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.systemui.dreams.complication.dagger;
-
-
-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;
-import com.android.systemui.dreams.complication.ComplicationLayoutParams;
-import com.android.systemui.dreams.complication.DreamClockTimeComplication.DreamClockTimeViewHolder;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Named;
-import javax.inject.Scope;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.Subcomponent;
-
-/**
- * {@link DreamClockTimeComplicationComponent} is responsible for generating dependencies
- * surrounding the
- * Clock Time {@link com.android.systemui.dreams.complication.Complication}, such as the layout
- * details.
- */
-@Subcomponent(modules = {
- DreamClockTimeComplicationComponent.DreamClockTimeComplicationModule.class,
-})
-@DreamClockTimeComplicationComponent.DreamClockTimeComplicationScope
-public interface DreamClockTimeComplicationComponent {
- /**
- * Creates {@link DreamClockTimeViewHolder}.
- */
- DreamClockTimeViewHolder getViewHolder();
-
- @Documented
- @Retention(RUNTIME)
- @Scope
- @interface DreamClockTimeComplicationScope {
- }
-
- /**
- * Generates {@link DreamClockTimeComplicationComponent}.
- */
- @Subcomponent.Factory
- interface Factory {
- DreamClockTimeComplicationComponent create();
- }
-
- /**
- * Scoped values for {@link DreamClockTimeComplicationComponent}.
- */
- @Module
- interface DreamClockTimeComplicationModule {
- String DREAM_CLOCK_TIME_COMPLICATION_VIEW = "clock_time_complication_view";
- String DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS =
- "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.
- */
- @Provides
- @DreamClockTimeComplicationScope
- @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
- static View provideComplicationView(LayoutInflater layoutInflater) {
- 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;
- }
-
- /**
- * Provides the layout parameters for the complication view.
- */
- @Provides
- @DreamClockTimeComplicationScope
- @Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
- static ComplicationLayoutParams provideLayoutParams() {
- return new ComplicationLayoutParams(0,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ComplicationLayoutParams.POSITION_BOTTOM
- | ComplicationLayoutParams.POSITION_START,
- ComplicationLayoutParams.DIRECTION_UP,
- INSERT_ORDER_WEIGHT);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
new file mode 100644
index 000000000000..3ad7d3ded749
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
@@ -0,0 +1,76 @@
+/*
+ * 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.dreams.complication.dagger;
+
+
+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;
+import com.android.systemui.dreams.complication.ComplicationLayoutParams;
+import com.android.systemui.dreams.complication.DreamClockTimeComplication;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Module for providing {@link DreamClockTimeComplication}.
+ */
+@Module
+public interface DreamClockTimeComplicationModule {
+ String DREAM_CLOCK_TIME_COMPLICATION_VIEW = "clock_time_complication_view";
+ String DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS =
+ "clock_time_complication_layout_params";
+ // Order weight of insert into parent container
+ //TODO(b/217199227): move to a single location.
+ int INSERT_ORDER_WEIGHT = 0;
+ String TAG_WEIGHT = "'wght' ";
+ int WEIGHT = 200;
+
+ /**
+ * Provides the complication view.
+ */
+ @Provides
+ @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
+ static View provideComplicationView(LayoutInflater layoutInflater) {
+ 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;
+ }
+
+ /**
+ * Provides the layout parameters for the complication view.
+ */
+ @Provides
+ @Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
+ static ComplicationLayoutParams provideLayoutParams() {
+ return new ComplicationLayoutParams(0,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ComplicationLayoutParams.POSITION_BOTTOM
+ | ComplicationLayoutParams.POSITION_START,
+ ComplicationLayoutParams.DIRECTION_UP,
+ INSERT_ORDER_WEIGHT);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
index 8e4fb3783f4a..62a4140c6745 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
@@ -24,10 +24,12 @@ import dagger.Module;
* Module for all components with corresponding dream layer complications registered in
* {@link SystemUIBinder}.
*/
-@Module(subcomponents = {
- DreamClockTimeComplicationComponent.class,
- DreamClockDateComplicationComponent.class,
- DreamWeatherComplicationComponent.class,
-})
+@Module(includes = {
+ DreamClockDateComplicationModule.class,
+ DreamClockTimeComplicationModule.class,
+ },
+ subcomponents = {
+ DreamWeatherComplicationComponent.class,
+ })
public interface RegisteredComplicationsModule {
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 2db3de173257..61cfe925f640 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -145,7 +145,7 @@ public class Flags {
/***************************************/
// 900 - media
public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true);
- public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, true);
+ public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, false);
public static final BooleanFlag MEDIA_SESSION_LAYOUT = new BooleanFlag(902, true);
public static final BooleanFlag MEDIA_NEARBY_DEVICES = new BooleanFlag(903, true);
public static final BooleanFlag MEDIA_MUTE_AWAIT = new BooleanFlag(904, true);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index acad30b4276f..bf464ecdec98 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2347,7 +2347,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
// Hack level over 9000: To speed up wake-and-unlock sequence, force it to report
// the next draw from here, so we don't have to wait for window manager to signal
// this to our ViewRootImpl.
- mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw();
+ mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw(
+ false /* syncBuffer */);
mScreenOnCoordinator.setWakeAndUnlocking(false);
}
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 c69f947f5f3f..71dfa7433c32 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -16,10 +16,8 @@
package com.android.systemui.keyguard.dagger;
-import android.annotation.Nullable;
import android.app.trust.TrustManager;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.PowerManager;
import com.android.internal.jank.InteractionJankMonitor;
@@ -44,18 +42,14 @@ import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.sensors.AsyncSensorManager;
import java.util.concurrent.Executor;
@@ -133,20 +127,4 @@ public class KeyguardModule {
notificationShadeWindowController,
activityLaunchAnimator);
}
-
- @SysUISingleton
- @Provides
- @Nullable
- static KeyguardLiftController provideKeyguardLiftController(
- Context context,
- StatusBarStateController statusBarStateController,
- AsyncSensorManager asyncSensorManager,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- DumpManager dumpManager) {
- if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
- return null;
- }
- return new KeyguardLiftController(statusBarStateController, asyncSensorManager,
- keyguardUpdateMonitor, dumpManager);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 510d15bd7b73..ffdd5376b12e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -137,7 +137,6 @@ public class MediaControlPanel {
private MediaCarouselController mMediaCarouselController;
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
private final FalsingManager mFalsingManager;
- private final MediaFlags mMediaFlags;
// Used for swipe-to-dismiss logging.
protected boolean mIsImpressed = false;
@@ -156,7 +155,7 @@ public class MediaControlPanel {
Lazy<MediaDataManager> lazyMediaDataManager,
MediaOutputDialogFactory mediaOutputDialogFactory,
MediaCarouselController mediaCarouselController,
- FalsingManager falsingManager, MediaFlags mediaFlags, SystemClock systemClock) {
+ FalsingManager falsingManager, SystemClock systemClock) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
@@ -167,7 +166,6 @@ public class MediaControlPanel {
mMediaOutputDialogFactory = mediaOutputDialogFactory;
mMediaCarouselController = mediaCarouselController;
mFalsingManager = falsingManager;
- mMediaFlags = mediaFlags;
mSystemClock = systemClock;
loadDimens();
@@ -506,9 +504,8 @@ public class MediaControlPanel {
List<MediaAction> actionIcons = data.getActions();
List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
- // If the session actions flag is enabled, but we're still using the regular layout, use
- // the session actions anyways
- if (mMediaFlags.areMediaSessionActionsEnabled() && data.getSemanticActions() != null) {
+ // If we got session actions, use those instead
+ if (data.getSemanticActions() != null) {
MediaButton semanticActions = data.getSemanticActions();
actionIcons = new ArrayList<MediaAction>();
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 9e14fe91f21d..56d8c6486631 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -610,7 +610,8 @@ class MediaDataManager(
var actionIcons: List<MediaAction> = emptyList()
var actionsToShowCollapsed: List<Int> = emptyList()
var semanticActions: MediaButton? = null
- if (mediaFlags.areMediaSessionActionsEnabled() && mediaController.playbackState != null) {
+ if (mediaFlags.areMediaSessionActionsEnabled(sbn.packageName, sbn.user) &&
+ mediaController.playbackState != null) {
semanticActions = createActionsFromState(sbn.packageName, mediaController)
} else {
val actions = createActionsFromNotification(sbn)
@@ -726,7 +727,7 @@ class MediaDataManager(
}
}
- // Finally, assign the remaining button slots: C A play/pause B D
+ // Finally, assign the remaining button slots: play/pause A B C D
// A = previous, else custom action (if not reserved)
// B = next, else custom action (if not reserved)
// C and D are always custom actions
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
index dd35a9a81399..59237d936d72 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
@@ -16,6 +16,8 @@
package com.android.systemui.media
+import android.app.StatusBarManager
+import android.os.UserHandle
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -26,16 +28,17 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) {
/**
* Check whether media control actions should be based on PlaybackState instead of notification
*/
- fun areMediaSessionActionsEnabled(): Boolean {
- return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
+ fun areMediaSessionActionsEnabled(packageName: String, user: UserHandle): Boolean {
+ val enabled = StatusBarManager.useMediaSessionActionsForApp(packageName, user)
+ // Allow global override with flag
+ return enabled || featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
}
/**
* Check whether media controls should use the new session-based layout
*/
fun useMediaSessionLayout(): Boolean {
- return featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS) &&
- featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT)
+ return featureFlags.isEnabled(Flags.MEDIA_SESSION_LAYOUT)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 7a4dee294dd6..d472aeee1073 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -812,7 +812,7 @@ class MediaHierarchyManager @Inject constructor(
@TransformationType
fun calculateTransformationType(): Int {
if (isTransitioningToFullShade) {
- if (inSplitShade) {
+ if (inSplitShade && areGuidedTransitionHostsVisible()) {
return TRANSFORMATION_TYPE_TRANSITION
}
return TRANSFORMATION_TYPE_FADE
@@ -829,6 +829,11 @@ class MediaHierarchyManager @Inject constructor(
return TRANSFORMATION_TYPE_TRANSITION
}
+ private fun areGuidedTransitionHostsVisible(): Boolean {
+ return getHost(previousLocation)?.visible == true &&
+ getHost(desiredLocation)?.visible == true
+ }
+
/**
* @return the current transformation progress if we're in a guided transformation and -1
* otherwise
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 3961f079748b..e4b8874ff601 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -128,19 +128,21 @@ class MediaTttCommandLineHelper @Inject constructor(
as StatusBarManager
val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
.addFeature("feature")
- .setPackageName(TEST_PACKAGE_NAME)
- .build()
+ if (args.size >= 2 && args[1] == "useAppIcon=true") {
+ routeInfo.setPackageName(TEST_PACKAGE_NAME)
+ }
statusBarManager.updateMediaTapToTransferReceiverDisplay(
displayState,
- routeInfo,
+ routeInfo.build(),
null,
null
)
}
override fun help(pw: PrintWriter) {
- pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND <chipState>")
+ pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND " +
+ "<chipState> useAppIcon=[true|false]")
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index 3d5b3a3f70df..54b0c1345601 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -31,6 +31,7 @@ import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
+import android.widget.LinearLayout
import com.android.internal.widget.CachingIconView
import com.android.settingslib.Utils
import com.android.systemui.R
@@ -137,6 +138,11 @@ abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
abstract fun updateChipView(chipInfo: T, currentChipView: ViewGroup)
/**
+ * Returns the size that the icon should be, or null if no size override is needed.
+ */
+ open fun getIconSize(isAppIcon: Boolean): Int? = null
+
+ /**
* An internal method to set the icon on the view.
*
* This is in the common superclass since both the sender and the receiver show an icon.
@@ -151,35 +157,47 @@ abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
appNameOverride: CharSequence? = null,
) {
val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
- val appInfo = getAppInfo(appPackageName)
- appIconView.contentDescription = appNameOverride ?: appInfo.appName
- appIconView.setImageDrawable(appIconDrawableOverride ?: appInfo.appIcon)
+ val iconInfo = getIconInfo(appPackageName)
+
+ getIconSize(iconInfo.isAppIcon)?.let { size ->
+ val lp = appIconView.layoutParams
+ lp.width = size
+ lp.height = size
+ appIconView.layoutParams = lp
+ }
+
+ appIconView.contentDescription = appNameOverride ?: iconInfo.iconName
+ appIconView.setImageDrawable(appIconDrawableOverride ?: iconInfo.icon)
}
/**
- * Returns the app name and icon of the app playing media, or a default name and icon if we
- * can't find the app name/icon.
+ * Returns the information needed to display the icon.
+ *
+ * The information will either contain app name and icon of the app playing media, or a default
+ * name and icon if we can't find the app name/icon.
*/
- private fun getAppInfo(appPackageName: String?): AppInfo {
+ private fun getIconInfo(appPackageName: String?): IconInfo {
if (appPackageName != null) {
try {
- return AppInfo(
- appName = context.packageManager.getApplicationInfo(
+ return IconInfo(
+ iconName = context.packageManager.getApplicationInfo(
appPackageName, PackageManager.ApplicationInfoFlags.of(0)
).loadLabel(context.packageManager).toString(),
- appIcon = context.packageManager.getApplicationIcon(appPackageName)
+ icon = context.packageManager.getApplicationIcon(appPackageName),
+ isAppIcon = true
)
} catch (e: PackageManager.NameNotFoundException) {
Log.w(TAG, "Cannot find package $appPackageName", e)
}
}
- return AppInfo(
- appName = context.getString(R.string.media_output_dialog_unknown_launch_app_name),
- appIcon = context.resources.getDrawable(R.drawable.ic_cast).apply {
+ return IconInfo(
+ iconName = context.getString(R.string.media_output_dialog_unknown_launch_app_name),
+ icon = context.resources.getDrawable(R.drawable.ic_cast).apply {
this.setTint(
Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
)
- }
+ },
+ isAppIcon = false
)
}
@@ -203,7 +221,9 @@ object MediaTttRemovalReason {
const val REASON_SCREEN_TAP = "SCREEN_TAP"
}
-private data class AppInfo(
- val appName: String,
- val appIcon: Drawable
+private data class IconInfo(
+ val iconName: String,
+ val icon: Drawable,
+ /** True if [icon] is the app's icon, and false if [icon] is some generic default icon. */
+ val isAppIcon: Boolean
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 44965d705802..072263fcf38c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -127,6 +127,15 @@ class MediaTttChipControllerReceiver @Inject constructor(
chipInfo.appNameOverride
)
}
+
+ override fun getIconSize(isAppIcon: Boolean): Int? =
+ context.resources.getDimensionPixelSize(
+ if (isAppIcon) {
+ R.dimen.media_ttt_icon_size_receiver
+ } else {
+ R.dimen.media_ttt_generic_icon_size_receiver
+ }
+ )
}
data class ChipReceiverInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
index 61071235db0b..8147877a8a29 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
@@ -150,24 +150,27 @@ class PrivacyDialogController(
packageName: String,
userId: Int,
permGroupName: CharSequence,
- attributionTag: CharSequence?
+ attributionTag: CharSequence?,
+ isAttributionSupported: Boolean
): Intent
{
lateinit var intent: Intent
- if (attributionTag != null) {
+ if (attributionTag != null && isAttributionSupported) {
intent = Intent(Intent.ACTION_MANAGE_PERMISSION_USAGE)
intent.setPackage(packageName)
intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permGroupName.toString())
intent.putExtra(Intent.EXTRA_ATTRIBUTION_TAGS, arrayOf(attributionTag.toString()))
intent.putExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, true)
val resolveInfo = packageManager.resolveActivity(
- intent, PackageManager.ResolveInfoFlags.of(0))
- ?: return getDefaultManageAppPermissionsIntent(packageName, userId)
- intent.component = ComponentName(packageName, resolveInfo.activityInfo.name)
- return intent
- } else {
- return getDefaultManageAppPermissionsIntent(packageName, userId)
+ intent, PackageManager.ResolveInfoFlags.of(0))
+ if (resolveInfo != null && resolveInfo.activityInfo != null &&
+ resolveInfo.activityInfo.permission ==
+ android.Manifest.permission.START_VIEW_PERMISSION_USAGE) {
+ intent.component = ComponentName(packageName, resolveInfo.activityInfo.name)
+ return intent
+ }
}
+ return getDefaultManageAppPermissionsIntent(packageName, userId)
}
fun getDefaultManageAppPermissionsIntent(packageName: String, userId: Int): Intent {
@@ -226,9 +229,15 @@ class PrivacyDialogController(
userInfo?.isManagedProfile ?: false,
it.isPhoneCall,
it.permissionGroupName,
- getManagePermissionIntent(it.packageName, userId,
- it.permissionGroupName,
- it.attributionTag)
+ getManagePermissionIntent(
+ it.packageName,
+ userId,
+ it.permissionGroupName,
+ it.attributionTag,
+ // attributionLabel is set only when subattribution policies
+ // are supported and satisfied
+ it.attributionLabel != null
+ )
)
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
index 8bad2de189c5..2cc3986c6e82 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
@@ -21,6 +21,7 @@ import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.TextUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -158,22 +159,47 @@ public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.Intern
final int security = wifiEntry.getSecurity();
updateEndIcon(connectedState, security);
+ mWifiListLayout.setEnabled(shouldEnabled(wifiEntry));
if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
mWifiListLayout.setOnClickListener(
- v -> mInternetDialogController.launchWifiNetworkDetailsSetting(
+ v -> mInternetDialogController.launchWifiDetailsSetting(
wifiEntry.getKey(), v));
return;
}
- mWifiListLayout.setOnClickListener(v -> {
- if (wifiEntry.shouldEditBeforeConnect()) {
- final Intent intent = WifiUtils.getWifiDialogIntent(wifiEntry.getKey(),
- true /* connectForCaller */);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- mContext.startActivity(intent);
- }
+ mWifiListLayout.setOnClickListener(v -> onWifiClick(wifiEntry, v));
+ }
+
+ boolean shouldEnabled(@NonNull WifiEntry wifiEntry) {
+ if (wifiEntry.canConnect()) {
+ return true;
+ }
+ // If Wi-Fi is connected or saved network, leave it enabled to disconnect or configure.
+ if (wifiEntry.canDisconnect() || wifiEntry.isSaved()) {
+ return true;
+ }
+ return false;
+ }
+
+ void onWifiClick(@NonNull WifiEntry wifiEntry, @NonNull View view) {
+ if (wifiEntry.shouldEditBeforeConnect()) {
+ final Intent intent = WifiUtils.getWifiDialogIntent(wifiEntry.getKey(),
+ true /* connectForCaller */);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
+ mContext.startActivity(intent);
+ return;
+ }
+
+ if (wifiEntry.canConnect()) {
mInternetDialogController.connect(wifiEntry);
- });
+ return;
+ }
+
+ if (wifiEntry.isSaved()) {
+ Log.w(TAG, "The saved Wi-Fi network does not allow to connect. SSID:"
+ + wifiEntry.getSsid());
+ mInternetDialogController.launchWifiDetailsSetting(wifiEntry.getKey(), view);
+ }
}
void setWifiNetworkLayout(CharSequence title, CharSequence summary) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index d1c784457c9f..8921e95fcee9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -531,8 +531,7 @@ public class InternetDialog extends SystemUIDialog implements
if (mConnectedWifiEntry == null) {
return;
}
- mInternetDialogController.launchWifiNetworkDetailsSetting(mConnectedWifiEntry.getKey(),
- view);
+ mInternetDialogController.launchWifiDetailsSetting(mConnectedWifiEntry.getKey(), view);
}
void onClickSeeMoreButton(View view) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index b322cbf6c60e..d97ce7757d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -635,7 +635,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi
startActivity(getSettingsIntent(), view);
}
- void launchWifiNetworkDetailsSetting(String key, View view) {
+ void launchWifiDetailsSetting(String key, View view) {
Intent intent = getWifiDetailsSettingsIntent(key);
if (intent != null) {
startActivity(intent, view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index ab4d0dd355f3..de3e89d6dc8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -116,6 +116,16 @@ class LockscreenShadeTransitionController @Inject constructor(
private var scrimTransitionDistance = 0
/**
+ * Distance that it takes in order for the notifications scrim fade in to start.
+ */
+ private var notificationsScrimTransitionDelay = 0
+
+ /**
+ * Distance that it takes for the notifications scrim to fully fade if after it started.
+ */
+ private var notificationsScrimTransitionDistance = 0
+
+ /**
* Distance that the full shade transition takes in order for the notification shelf to fully
* expand.
*/
@@ -225,6 +235,10 @@ class LockscreenShadeTransitionController @Inject constructor(
R.dimen.lockscreen_shade_transition_by_tap_distance)
scrimTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_scrim_transition_distance)
+ notificationsScrimTransitionDelay = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay)
+ notificationsScrimTransitionDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance)
notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
R.dimen.lockscreen_shade_notif_shelf_transition_distance)
qsTransitionDistance = context.resources.getDimensionPixelSize(
@@ -405,6 +419,7 @@ class LockscreenShadeTransitionController @Inject constructor(
false /* animate */, 0 /* delay */)
mediaHierarchyManager.setTransitionToFullShadeAmount(field)
+ transitionToShadeAmountScrim(field)
transitionToShadeAmountCommon(field)
transitionToShadeAmountKeyguard(field)
}
@@ -417,10 +432,15 @@ class LockscreenShadeTransitionController @Inject constructor(
var qSDragProgress = 0f
private set
- private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
+ private fun transitionToShadeAmountScrim(dragDownAmount: Float) {
val scrimProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
- scrimController.setTransitionToFullShadeProgress(scrimProgress)
+ val notificationsScrimDragAmount = dragDownAmount - notificationsScrimTransitionDelay
+ val notificationsScrimProgress = MathUtils.saturate(
+ notificationsScrimDragAmount / notificationsScrimTransitionDistance)
+ scrimController.setTransitionToFullShadeProgress(scrimProgress, notificationsScrimProgress)
+ }
+ private fun transitionToShadeAmountCommon(dragDownAmount: Float) {
if (depthControllerTransitionDistance > 0) {
val depthProgress =
MathUtils.saturate(dragDownAmount / depthControllerTransitionDistance)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 3dd717d2f377..eaa66bbc15ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -226,10 +226,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
? MathUtils.lerp(shortestWidth, getWidth(), fractionToShade)
: getWidth();
ActivatableNotificationView anv = (ActivatableNotificationView) this;
- NotificationBackgroundView bg = anv.getBackgroundNormal();
- if (bg != null) {
- anv.getBackgroundNormal().setActualWidth((int) actualWidth);
- }
+ anv.setBackgroundWidth((int) actualWidth);
if (mShelfIcons != null) {
mShelfIcons.setActualLayoutWidth((int) actualWidth);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
index 9795dcf1fcd8..b74140da99d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -16,9 +16,12 @@
package com.android.systemui.statusbar.events
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.content.Context
-import android.graphics.Point
+import android.graphics.Rect
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@@ -30,6 +33,7 @@ import com.android.systemui.R
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
+import kotlin.math.roundToInt
/**
* Controls the view for system event animations.
@@ -38,7 +42,7 @@ class SystemEventChipAnimationController @Inject constructor(
private val context: Context,
private val statusBarWindowController: StatusBarWindowController,
private val contentInsetsProvider: StatusBarContentInsetsProvider
-) : SystemStatusChipAnimationCallback {
+) : SystemStatusAnimationCallback {
private lateinit var animationWindowView: FrameLayout
@@ -49,90 +53,169 @@ class SystemEventChipAnimationController @Inject constructor(
private var chipRight = 0
private var chipLeft = 0
private var chipWidth = 0
- private var dotCenter = Point(0, 0)
+ private var chipMinWidth = context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_min_animation_width)
private var dotSize = context.resources.getDimensionPixelSize(
R.dimen.ongoing_appops_dot_diameter)
- // If the chip animates away to a persistent dot, then we modify the CHIP_OUT animation
- private var isAnimatingToDot = false
+ // Use during animation so that multiple animators can update the drawing rect
+ private var animRect = Rect()
// TODO: move to dagger
private var initialized = false
- override fun onChipAnimationStart(
- viewCreator: ViewCreator,
- @SystemAnimationState state: Int
- ) {
- if (!initialized) init()
-
- if (state == ANIMATING_IN) {
- animationDirection = if (animationWindowView.isLayoutRtl) RIGHT else LEFT
-
- // Initialize the animated view
- val insets = contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation()
- currentAnimatedView = viewCreator(context).also {
- animationWindowView.addView(
- it.view,
- layoutParamsDefault(
- if (animationWindowView.isLayoutRtl) insets.first
- else insets.second))
- it.view.alpha = 0f
- // For some reason, the window view's measured width is always 0 here, so use the
- // parent (status bar)
- it.view.measure(
- View.MeasureSpec.makeMeasureSpec(
- (animationWindowView.parent as View).width, AT_MOST),
- View.MeasureSpec.makeMeasureSpec(animationWindowView.height, AT_MOST))
- chipWidth = it.chipWidth
- }
+ /**
+ * Give the chip controller a chance to inflate and configure the chip view before we start
+ * animating
+ */
+ fun prepareChipAnimation(viewCreator: ViewCreator) {
+ if (!initialized) {
+ init()
+ }
+ animationDirection = if (animationWindowView.isLayoutRtl) RIGHT else LEFT
- // decide which direction we're animating from, and then set some screen coordinates
- val contentRect = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation()
- when (animationDirection) {
- LEFT -> {
- chipRight = contentRect.right
- chipLeft = contentRect.right - chipWidth
- }
- else /* RIGHT */ -> {
- chipLeft = contentRect.left
- chipRight = contentRect.left + chipWidth
- }
- }
+ // Initialize the animated view
+ val insets = contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation()
+ currentAnimatedView = viewCreator(context).also {
+ animationWindowView.addView(
+ it.view,
+ layoutParamsDefault(
+ if (animationWindowView.isLayoutRtl) insets.first
+ else insets.second))
+ it.view.alpha = 0f
+ // For some reason, the window view's measured width is always 0 here, so use the
+ // parent (status bar)
+ it.view.measure(
+ View.MeasureSpec.makeMeasureSpec(
+ (animationWindowView.parent as View).width, AT_MOST),
+ View.MeasureSpec.makeMeasureSpec(animationWindowView.height, AT_MOST))
+ chipWidth = it.chipWidth
+ }
- currentAnimatedView?.apply {
- updateAnimatedViewBoundsForAmount(0.1f, this)
+ // decide which direction we're animating from, and then set some screen coordinates
+ val contentRect = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation()
+ when (animationDirection) {
+ LEFT -> {
+ chipRight = contentRect.right
+ chipLeft = contentRect.right - chipWidth
}
- } else {
- // We are animating away
- currentAnimatedView!!.view.apply {
- alpha = 1f
+ else /* RIGHT */ -> {
+ chipLeft = contentRect.left
+ chipRight = contentRect.left + chipWidth
}
}
}
- override fun onChipAnimationEnd(@SystemAnimationState state: Int) {
- if (state == ANIMATING_IN) {
- // Finished animating in
- currentAnimatedView?.apply {
- updateAnimatedViewBoundsForAmount(1f, this)
+ override fun onSystemEventAnimationBegin(): Animator {
+ initializeAnimRect()
+
+ val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply {
+ startDelay = 117
+ duration = 83
+ interpolator = null
+ addUpdateListener { currentAnimatedView?.view?.alpha = animatedValue as Float }
+ }
+ val moveIn = ValueAnimator.ofInt(chipMinWidth, chipWidth).apply {
+ startDelay = 117
+ duration = 383
+ interpolator = STATUS_BAR_X_MOVE_IN
+ addUpdateListener {
+ updateAnimatedViewBoundsWidth(animatedValue as Int)
}
+ }
+ val animSet = AnimatorSet()
+ animSet.playTogether(alphaIn, moveIn)
+ return animSet
+ }
+
+ override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
+ initializeAnimRect()
+ val finish = if (hasPersistentDot) {
+ createMoveOutAnimationForDot()
} else {
- // Finished animating away
- currentAnimatedView!!.view.apply {
- visibility = View.INVISIBLE
+ createMoveOutAnimationDefault()
+ }
+
+ finish.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ animationWindowView.removeView(currentAnimatedView!!.view)
+ }
+ })
+
+ return finish
+ }
+
+ private fun createMoveOutAnimationForDot(): Animator {
+ val width1 = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply {
+ duration = 150
+ interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1
+ addUpdateListener {
+ updateAnimatedViewBoundsWidth(it.animatedValue as Int)
+ }
+ }
+
+ val width2 = ValueAnimator.ofInt(chipMinWidth, dotSize).apply {
+ startDelay = 150
+ duration = 333
+ interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2
+ addUpdateListener {
+ updateAnimatedViewBoundsWidth(it.animatedValue as Int)
}
- animationWindowView.removeView(currentAnimatedView!!.view)
}
+
+ val keyFrame1Height = dotSize * 2
+ val v = currentAnimatedView!!.view
+ val chipVerticalCenter = v.top + v.measuredHeight / 2
+ val height1 = ValueAnimator.ofInt(
+ currentAnimatedView!!.view.measuredHeight, keyFrame1Height).apply {
+ startDelay = 133
+ duration = 100
+ interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1
+ addUpdateListener {
+ updateAnimatedViewBoundsHeight(it.animatedValue as Int, chipVerticalCenter)
+ }
+ }
+
+ val height2 = ValueAnimator.ofInt(keyFrame1Height, dotSize).apply {
+ startDelay = 233
+ duration = 250
+ interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2
+ addUpdateListener {
+ updateAnimatedViewBoundsHeight(it.animatedValue as Int, chipVerticalCenter)
+ }
+ }
+
+ // Move the chip view to overlap exactly with the privacy dot. The chip displays by default
+ // exactly adjacent to the dot, so we can just move over by the diameter of the dot itself
+ val moveOut = ValueAnimator.ofInt(0, dotSize).apply {
+ startDelay = 50
+ duration = 183
+ interpolator = STATUS_CHIP_MOVE_TO_DOT
+ addUpdateListener {
+ // If RTL, we can just invert the move
+ val amt = if (animationDirection == LEFT) {
+ animatedValue as Int
+ } else {
+ -(animatedValue as Int)
+ }
+ updateAnimatedBoundsX(amt)
+ }
+ }
+
+ val animSet = AnimatorSet()
+ animSet.playTogether(width1, width2, height1, height2, moveOut)
+ return animSet
}
- override fun onChipAnimationUpdate(
- animator: ValueAnimator,
- @SystemAnimationState state: Int
- ) {
- currentAnimatedView?.apply {
- val amt = (animator.animatedValue as Float).amt()
- view.alpha = (animator.animatedValue as Float)
- updateAnimatedViewBoundsForAmount(amt, this)
+ private fun createMoveOutAnimationDefault(): Animator {
+ val moveOut = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply {
+ duration = 383
+ addUpdateListener {
+ currentAnimatedView?.apply {
+ updateAnimatedViewBoundsWidth(it.animatedValue as Int)
+ }
+ }
}
+ return moveOut
}
private fun init() {
@@ -144,7 +227,6 @@ class SystemEventChipAnimationController @Inject constructor(
statusBarWindowController.addViewToWindow(animationWindowView, lp)
animationWindowView.clipToPadding = false
animationWindowView.clipChildren = false
- animationWindowView.measureAllChildren = true
}
private fun layoutParamsDefault(marginEnd: Int): FrameLayout.LayoutParams =
@@ -153,29 +235,55 @@ class SystemEventChipAnimationController @Inject constructor(
it.marginEnd = marginEnd
}
- private fun updateAnimatedViewBoundsForAmount(amt: Float, chip: BackgroundAnimatableView) {
+ private fun initializeAnimRect() = animRect.set(
+ chipLeft,
+ currentAnimatedView!!.view.top,
+ chipRight,
+ currentAnimatedView!!.view.bottom)
+
+ /**
+ * To be called during an animation, sets the width and updates the current animated chip view
+ */
+ private fun updateAnimatedViewBoundsWidth(width: Int) {
when (animationDirection) {
LEFT -> {
- chip.setBoundsForAnimation(
- (chipRight - (chipWidth * amt)).toInt(),
- chip.view.top,
- chipRight,
- chip.view.bottom)
- }
- else /* RIGHT */ -> {
- chip.setBoundsForAnimation(
- chipLeft,
- chip.view.top,
- (chipLeft + (chipWidth * amt)).toInt(),
- chip.view.bottom)
+ animRect.set((chipRight - width), animRect.top, chipRight, animRect.bottom)
+ } else /* RIGHT */ -> {
+ animRect.set(chipLeft, animRect.top, (chipLeft + width), animRect.bottom)
}
}
+
+ updateCurrentAnimatedView()
}
- private fun start() = if (animationWindowView.isLayoutRtl) right() else left()
- private fun right() = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation().right
- private fun left() = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation().left
- private fun Float.amt() = 0.01f.coerceAtLeast(this)
+ /**
+ * To be called during an animation, updates the animation rect and sends the update to the chip
+ */
+ private fun updateAnimatedViewBoundsHeight(height: Int, verticalCenter: Int) {
+ animRect.set(
+ animRect.left,
+ verticalCenter - (height.toFloat() / 2).roundToInt(),
+ animRect.right,
+ verticalCenter + (height.toFloat() / 2).roundToInt())
+
+ updateCurrentAnimatedView()
+ }
+
+ /**
+ * To be called during an animation, updates the animation rect offset and updates the chip
+ */
+ private fun updateAnimatedBoundsX(translation: Int) {
+ currentAnimatedView?.view?.translationX = translation.toFloat()
+ }
+
+ /**
+ * To be called during an animation. Sets the chip rect to animRect
+ */
+ private fun updateCurrentAnimatedView() {
+ currentAnimatedView?.setBoundsForAnimation(
+ animRect.left, animRect.top, animRect.right, animRect.bottom
+ )
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index 947f3eb2ee12..36233e4e3eab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -19,14 +19,12 @@ package com.android.systemui.statusbar.events
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
-import android.animation.ValueAnimator
import android.annotation.IntDef
import android.os.Process
import android.provider.DeviceConfig
import android.util.Log
+import android.view.animation.PathInterpolator
import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators.STANDARD_ACCELERATE
-import com.android.systemui.animation.Interpolators.STANDARD_DECELERATE
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
@@ -38,6 +36,7 @@ import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
import java.io.FileDescriptor
import java.io.PrintWriter
+import java.lang.IllegalStateException
import javax.inject.Inject
@@ -116,7 +115,10 @@ class SystemStatusAnimationScheduler @Inject constructor(
scheduledEvent?.updateFromEvent(event)
if (event.forceVisible) {
hasPersistentDot = true
- notifyTransitionToPersistentDot()
+ // If we missed the chance to show the persistent dot, do it now
+ if (animationState == IDLE) {
+ notifyTransitionToPersistentDot()
+ }
}
} else {
if (DEBUG) {
@@ -162,68 +164,90 @@ class SystemStatusAnimationScheduler @Inject constructor(
return
}
- // Schedule the animation to start after a debounce period
- cancelExecutionRunnable = executor.executeDelayed({
- cancelExecutionRunnable = null
- animationState = ANIMATING_IN
- statusBarWindowController.setForceStatusBarVisible(true)
-
- val entranceAnimator = ValueAnimator.ofFloat(1f, 0f)
- entranceAnimator.duration = ENTRANCE_ANIM_LENGTH
- entranceAnimator.addListener(systemAnimatorAdapter)
- entranceAnimator.addUpdateListener(systemUpdateListener)
- entranceAnimator.interpolator = STANDARD_ACCELERATE
-
- val chipAnimator = ValueAnimator.ofFloat(0f, 1f)
- chipAnimator.duration = CHIP_ANIM_LENGTH
- chipAnimator.addListener(
- ChipAnimatorAdapter(RUNNING_CHIP_ANIM, scheduledEvent!!.viewCreator))
- chipAnimator.addUpdateListener(chipUpdateListener)
- chipAnimator.interpolator = STANDARD_DECELERATE
-
- val aSet2 = AnimatorSet()
- aSet2.playSequentially(entranceAnimator, chipAnimator)
- aSet2.start()
-
- executor.executeDelayed({
- animationState = ANIMATING_OUT
-
- val systemAnimator = ValueAnimator.ofFloat(0f, 1f)
- systemAnimator.duration = ENTRANCE_ANIM_LENGTH
- systemAnimator.addListener(systemAnimatorAdapter)
- systemAnimator.addUpdateListener(systemUpdateListener)
- systemAnimator.interpolator = STANDARD_DECELERATE
- systemAnimator.addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- statusBarWindowController.setForceStatusBarVisible(false)
+ chipAnimationController.prepareChipAnimation(scheduledEvent!!.viewCreator)
+ animationState = ANIMATION_QUEUED
+ executor.executeDelayed({
+ runChipAnimation()
+ }, DEBOUNCE_DELAY)
+ }
+
+ /**
+ * 1. Define a total budget for the chip animation (1500ms)
+ * 2. Send out callbacks to listeners so that they can generate animations locally
+ * 3. Update the scheduler state so that clients know where we are
+ * 4. Maybe: provide scaffolding such as: dot location, margins, etc
+ * 5. Maybe: define a maximum animation length and enforce it. Probably only doable if we
+ * collect all of the animators and run them together.
+ */
+ private fun runChipAnimation() {
+ statusBarWindowController.setForceStatusBarVisible(true)
+ animationState = ANIMATING_IN
+
+ val animSet = collectStartAnimations()
+ if (animSet.totalDuration > 500) {
+ throw IllegalStateException("System animation total length exceeds budget. " +
+ "Expected: 500, actual: ${animSet.totalDuration}")
+ }
+ animSet.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ animationState = RUNNING_CHIP_ANIM
+ }
+ })
+ animSet.start()
+
+ executor.executeDelayed({
+ val animSet2 = collectFinishAnimations()
+ animationState = ANIMATING_OUT
+ animSet2.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ animationState = if (hasPersistentDot) {
+ SHOWING_PERSISTENT_DOT
+ } else {
+ IDLE
}
- })
-
- val chipAnimator = ValueAnimator.ofFloat(1f, 0f)
- chipAnimator.duration = CHIP_ANIM_LENGTH
- val endState = if (hasPersistentDot) {
- SHOWING_PERSISTENT_DOT
- } else {
- IDLE
+
+ statusBarWindowController.setForceStatusBarVisible(false)
}
- chipAnimator.addListener(
- ChipAnimatorAdapter(endState, scheduledEvent!!.viewCreator))
- chipAnimator.addUpdateListener(chipUpdateListener)
- chipAnimator.interpolator = STANDARD_ACCELERATE
+ })
+ animSet2.start()
+ scheduledEvent = null
+ }, DISPLAY_LENGTH)
+ }
- val aSet2 = AnimatorSet()
+ private fun collectStartAnimations(): AnimatorSet {
+ val animators = mutableListOf<Animator>()
+ listeners.forEach { listener ->
+ listener.onSystemEventAnimationBegin()?.let { anim ->
+ animators.add(anim)
+ }
+ }
+ animators.add(chipAnimationController.onSystemEventAnimationBegin())
+ val animSet = AnimatorSet().also {
+ it.playTogether(animators)
+ }
- aSet2.play(chipAnimator).before(systemAnimator)
- if (hasPersistentDot) {
- val dotAnim = notifyTransitionToPersistentDot()
- if (dotAnim != null) aSet2.playTogether(systemAnimator, dotAnim)
- }
+ return animSet
+ }
- aSet2.start()
+ private fun collectFinishAnimations(): AnimatorSet {
+ val animators = mutableListOf<Animator>()
+ listeners.forEach { listener ->
+ listener.onSystemEventAnimationFinish(hasPersistentDot)?.let { anim ->
+ animators.add(anim)
+ }
+ }
+ animators.add(chipAnimationController.onSystemEventAnimationFinish(hasPersistentDot))
+ if (hasPersistentDot) {
+ val dotAnim = notifyTransitionToPersistentDot()
+ if (dotAnim != null) {
+ animators.add(dotAnim)
+ }
+ }
+ val animSet = AnimatorSet().also {
+ it.playTogether(animators)
+ }
- scheduledEvent = null
- }, DISPLAY_LENGTH)
- }, DELAY)
+ return animSet
}
private fun notifyTransitionToPersistentDot(): Animator? {
@@ -257,18 +281,6 @@ class SystemStatusAnimationScheduler @Inject constructor(
return null
}
- private fun notifySystemStart() {
- listeners.forEach { it.onSystemChromeAnimationStart() }
- }
-
- private fun notifySystemFinish() {
- listeners.forEach { it.onSystemChromeAnimationEnd() }
- }
-
- private fun notifySystemAnimationUpdate(anim: ValueAnimator) {
- listeners.forEach { it.onSystemChromeAnimationUpdate(anim) }
- }
-
override fun addCallback(listener: SystemStatusAnimationCallback) {
Assert.isMainThread()
@@ -287,24 +299,6 @@ class SystemStatusAnimationScheduler @Inject constructor(
}
}
- private val systemUpdateListener = ValueAnimator.AnimatorUpdateListener {
- anim -> notifySystemAnimationUpdate(anim)
- }
-
- private val systemAnimatorAdapter = object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(p0: Animator?) {
- notifySystemFinish()
- }
-
- override fun onAnimationStart(p0: Animator?) {
- notifySystemStart()
- }
- }
-
- private val chipUpdateListener = ValueAnimator.AnimatorUpdateListener {
- anim -> chipAnimationController.onChipAnimationUpdate(anim, animationState)
- }
-
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
pw.println("Scheduled event: $scheduledEvent")
pw.println("Has persistent privacy dot: $hasPersistentDot")
@@ -318,24 +312,6 @@ class SystemStatusAnimationScheduler @Inject constructor(
}
}
}
-
- inner class ChipAnimatorAdapter(
- @SystemAnimationState val endState: Int,
- val viewCreator: ViewCreator
- ) : AnimatorListenerAdapter() {
- override fun onAnimationEnd(p0: Animator?) {
- chipAnimationController.onChipAnimationEnd(animationState)
- animationState = if (endState == SHOWING_PERSISTENT_DOT && !hasPersistentDot) {
- IDLE
- } else {
- endState
- }
- }
-
- override fun onAnimationStart(p0: Animator?) {
- chipAnimationController.onChipAnimationStart(viewCreator, animationState)
- }
- }
}
/**
@@ -344,16 +320,14 @@ class SystemStatusAnimationScheduler @Inject constructor(
* create space for the chip animation to display. This means hiding the system elements in the
* status bar and keyguard.
*
- * TODO: the chip animation really only has one client, we can probably remove it from this
- * interface
- *
* The value animators themselves are simple animators from 0.0 to 1.0. Listeners can apply any
* interpolation they choose but realistically these are most likely to be simple alpha transitions
*/
interface SystemStatusAnimationCallback {
- @JvmDefault fun onSystemChromeAnimationUpdate(animator: ValueAnimator) {}
- @JvmDefault fun onSystemChromeAnimationStart() {}
- @JvmDefault fun onSystemChromeAnimationEnd() {}
+ /** Implement this method to return an [Animator] or [AnimatorSet] that presents the chip */
+ fun onSystemEventAnimationBegin(): Animator? { return null }
+ /** Implement this method to return an [Animator] or [AnimatorSet] that hides the chip */
+ fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator? { return null }
// Best method name, change my mind
@JvmDefault
@@ -363,50 +337,61 @@ interface SystemStatusAnimationCallback {
@JvmDefault fun onHidePersistentDot(): Animator? { return null }
}
-interface SystemStatusChipAnimationCallback {
- fun onChipAnimationUpdate(animator: ValueAnimator, @SystemAnimationState state: Int) {}
-
- fun onChipAnimationStart(
- viewCreator: ViewCreator,
- @SystemAnimationState state: Int
- ) {}
-
- fun onChipAnimationEnd(@SystemAnimationState state: Int) {}
-}
-
/**
+ * Animation state IntDef
*/
@Retention(AnnotationRetention.SOURCE)
@IntDef(
value = [
- IDLE, ANIMATING_IN, RUNNING_CHIP_ANIM, ANIMATING_OUT, SHOWING_PERSISTENT_DOT
+ IDLE,
+ ANIMATION_QUEUED,
+ ANIMATING_IN,
+ RUNNING_CHIP_ANIM,
+ ANIMATING_OUT,
+ SHOWING_PERSISTENT_DOT
]
)
annotation class SystemAnimationState
/** No animation is in progress */
const val IDLE = 0
+/** An animation is queued, and awaiting the debounce period */
+const val ANIMATION_QUEUED = 1
/** System is animating out, and chip is animating in */
-const val ANIMATING_IN = 1
+const val ANIMATING_IN = 2
/** Chip has animated in and is awaiting exit animation, and optionally playing its own animation */
-const val RUNNING_CHIP_ANIM = 2
+const val RUNNING_CHIP_ANIM = 3
/** Chip is animating away and system is animating back */
-const val ANIMATING_OUT = 3
+const val ANIMATING_OUT = 4
/** Chip has animated away, and the persistent dot is showing */
-const val SHOWING_PERSISTENT_DOT = 4
+const val SHOWING_PERSISTENT_DOT = 5
+
+/** Commonly-needed interpolators can go here */
+@JvmField val STATUS_BAR_X_MOVE_OUT = PathInterpolator(0.33f, 0f, 0f, 1f)
+@JvmField val STATUS_BAR_X_MOVE_IN = PathInterpolator(0f, 0f, 0f, 1f)
+/**
+ * Status chip animation to dot have multiple stages of motion, the _1 and _2 interpolators should
+ * be used in succession
+ */
+val STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1 = PathInterpolator(0.44f, 0f, 0.25f, 1f)
+val STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2 = PathInterpolator(0.3f, 0f, 0.26f, 1f)
+val STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1 = PathInterpolator(0.4f, 0f, 0.17f, 1f)
+val STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2 = PathInterpolator(0.3f, 0f, 0f, 1f)
+val STATUS_CHIP_MOVE_TO_DOT = PathInterpolator(0f, 0f, 0.05f, 1f)
private const val TAG = "SystemStatusAnimationScheduler"
-private const val DELAY = 0L
+private const val DEBOUNCE_DELAY = 100L
/**
- * The total time spent animation should be 1500ms. The entrance animation is how much time
- * we give to the system to animate system elements out of the way. Total chip animation length
- * will be equivalent to 2*chip_anim_length + display_length
+ * The total time spent on the chip animation is 1500ms, broken up into 3 sections:
+ * - 500ms to animate the chip in (including animating system icons away)
+ * - 500ms holding the chip on screen
+ * - 500ms to animate the chip away (and system icons back)
+ *
+ * So DISPLAY_LENGTH should be the sum of the first 2 phases, while the final 500ms accounts for
+ * the actual animation
*/
-private const val ENTRANCE_ANIM_LENGTH = 250L
-private const val CHIP_ANIM_LENGTH = 250L
-// 1s + entrance time + chip anim_length
-private const val DISPLAY_LENGTH = 1500L
+private const val DISPLAY_LENGTH = 1000L
private const val MIN_UPTIME: Long = 5 * 1000
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index 7fbb0f1182c0..02aa1f2fd585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -25,7 +25,7 @@ class NotificationLaunchAnimatorControllerProvider @Inject constructor(
@JvmOverloads
fun getAnimatorController(
notification: ExpandableNotificationRow,
- onFinishAnimationCallback: Runnable = Runnable {}
+ onFinishAnimationCallback: Runnable? = null
): NotificationLaunchAnimatorController {
return NotificationLaunchAnimatorController(
notificationShadeWindowViewController,
@@ -49,7 +49,7 @@ class NotificationLaunchAnimatorController(
private val headsUpManager: HeadsUpManagerPhone,
private val notification: ExpandableNotificationRow,
private val jankMonitor: InteractionJankMonitor,
- private val onFinishAnimationCallback: Runnable
+ private val onFinishAnimationCallback: Runnable?
) : ActivityLaunchAnimator.Controller {
companion object {
@@ -123,7 +123,7 @@ class NotificationLaunchAnimatorController(
if (!willAnimate) {
removeHun(animate = true)
- onFinishAnimationCallback.run()
+ onFinishAnimationCallback?.run()
}
}
@@ -142,7 +142,7 @@ class NotificationLaunchAnimatorController(
notificationShadeWindowViewController.setExpandAnimationRunning(false)
notificationEntry.isExpandAnimationRunning = false
removeHun(animate = true)
- onFinishAnimationCallback.run()
+ onFinishAnimationCallback?.run()
}
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -162,7 +162,7 @@ class NotificationLaunchAnimatorController(
notificationListContainer.setExpandingNotification(null)
applyParams(null)
removeHun(animate = false)
- onFinishAnimationCallback.run()
+ onFinishAnimationCallback?.run()
}
private fun applyParams(params: ExpandAnimationParameters?) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index fca2aa167e37..577d536262b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -163,10 +163,13 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
/**
- * @return The background of this view.
+ * @param width The actual width to apply to the background view.
*/
- public NotificationBackgroundView getBackgroundNormal() {
- return mBackgroundNormal;
+ public void setBackgroundWidth(int width) {
+ if (mBackgroundNormal == null) {
+ return;
+ }
+ mBackgroundNormal.setActualWidth(width);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index c237e1deeae3..e479509247d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -79,7 +79,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.classifier.FalsingCollector;
@@ -90,6 +89,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
@@ -111,10 +111,11 @@ import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.SwipeableView;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.Compile;
import com.android.systemui.util.DumpUtilsKt;
@@ -169,6 +170,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private RowContentBindStage mRowContentBindStage;
private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
private Optional<BubblesManager> mBubblesManagerOptional;
+ private MetricsLogger mMetricsLogger;
private int mIconTransformContentShift;
private int mMaxHeadsUpHeightBeforeN;
private int mMaxHeadsUpHeightBeforeP;
@@ -304,8 +306,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
boolean nowExpanded = mGroupExpansionManager.toggleGroupExpansion(mEntry);
mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
- MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
- nowExpanded);
+ mMetricsLogger.action(MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER, nowExpanded);
onExpansionChanged(true /* userAction */, wasExpanded);
} else if (mEnableNonGroupedNotificationExpand) {
if (v.isAccessibilityFocused()) {
@@ -327,8 +328,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
notifyHeightChanged(true);
mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded);
- MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_EXPANDER,
- nowExpanded);
+ mMetricsLogger.action(MetricsEvent.ACTION_NOTIFICATION_EXPANDER, nowExpanded);
}
}
};
@@ -1271,7 +1271,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
addView(mMenuRow.getMenuView(), menuIndex);
}
for (NotificationContentView l : mLayouts) {
- l.initView();
+ l.reinflate();
l.reInflateViews();
}
mEntry.getSbn().clearPackageContext();
@@ -1464,7 +1464,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* @param fromAccessibility whether this dismiss is coming from an accessibility action
*/
public void performDismiss(boolean fromAccessibility) {
- Dependency.get(MetricsLogger.class).count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
+ mMetricsLogger.count(NotificationCounters.NOTIFICATION_DISMISSED, 1);
dismiss(fromAccessibility);
if (mEntry.isDismissable()) {
if (mOnUserInteractionCallback != null) {
@@ -1600,7 +1600,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
PeopleNotificationIdentifier peopleNotificationIdentifier,
OnUserInteractionCallback onUserInteractionCallback,
Optional<BubblesManager> bubblesManagerOptional,
- NotificationGutsManager gutsManager) {
+ NotificationGutsManager gutsManager,
+ MetricsLogger metricsLogger,
+ SmartReplyConstants smartReplyConstants,
+ SmartReplyController smartReplyController) {
mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
@@ -1623,15 +1626,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mFalsingManager = falsingManager;
mFalsingCollector = falsingCollector;
mStatusBarStateController = statusBarStateController;
-
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
for (NotificationContentView l : mLayouts) {
- l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier);
- l.setRemoteInputViewSubcomponentFactory(rivSubcomponentFactory);
+ l.initialize(
+ mPeopleNotificationIdentifier,
+ rivSubcomponentFactory,
+ smartReplyConstants,
+ smartReplyController);
}
mOnUserInteractionCallback = onUserInteractionCallback;
mBubblesManagerOptional = bubblesManagerOptional;
mNotificationGutsManager = gutsManager;
+ mMetricsLogger = metricsLogger;
cacheIsSystemNotification();
}
@@ -3127,7 +3133,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
if (mGroupMembershipManager.isGroupSummary(mEntry)) {
event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER;
}
- MetricsLogger.action(mContext, event, userExpanded);
+ mMetricsLogger.action(event, userExpanded);
}
@Override
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 c4beb5bf4d7b..599039d46556 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
@@ -27,6 +27,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -35,6 +36,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.FeedbackIcon;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
@@ -49,6 +51,7 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationRowSco
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.wmshell.BubblesManager;
@@ -82,6 +85,7 @@ public class ExpandableNotificationRowController implements NotifViewController
private final HeadsUpManager mHeadsUpManager;
private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener;
private final StatusBarStateController mStatusBarStateController;
+ private final MetricsLogger mMetricsLogger;
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion;
@@ -94,16 +98,21 @@ public class ExpandableNotificationRowController implements NotifViewController
private final boolean mAllowLongPress;
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
private final Optional<BubblesManager> mBubblesManagerOptional;
+ private final SmartReplyConstants mSmartReplyConstants;
+ private final SmartReplyController mSmartReplyController;
private final ExpandableNotificationRowDragController mDragController;
@Inject
public ExpandableNotificationRowController(
ExpandableNotificationRow view,
- NotificationListContainer listContainer,
- RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
ActivatableNotificationViewController activatableNotificationViewController,
+ RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
+ MetricsLogger metricsLogger,
+ NotificationListContainer listContainer,
NotificationMediaManager mediaManager,
+ SmartReplyConstants smartReplyConstants,
+ SmartReplyController smartReplyController,
PluginManager pluginManager,
SystemClock clock,
@AppName String appName,
@@ -152,6 +161,9 @@ public class ExpandableNotificationRowController implements NotifViewController
mPeopleNotificationIdentifier = peopleNotificationIdentifier;
mBubblesManagerOptional = bubblesManagerOptional;
mDragController = dragController;
+ mMetricsLogger = metricsLogger;
+ mSmartReplyConstants = smartReplyConstants;
+ mSmartReplyController = smartReplyController;
}
/**
@@ -179,7 +191,10 @@ public class ExpandableNotificationRowController implements NotifViewController
mPeopleNotificationIdentifier,
mOnUserInteractionCallback,
mBubblesManagerOptional,
- mNotificationGutsManager
+ mNotificationGutsManager,
+ mMetricsLogger,
+ mSmartReplyConstants,
+ mSmartReplyController
);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index adb4ce68c031..b9c7113206df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -39,7 +39,6 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.RemoteInputController;
@@ -94,7 +93,6 @@ public class NotificationContentView extends FrameLayout implements Notification
private final Rect mClipBounds = new Rect();
private int mMinContractedHeight;
- private int mNotificationContentMarginEnd;
private View mContractedChild;
private View mExpandedChild;
private View mHeadsUpChild;
@@ -116,7 +114,7 @@ public class NotificationContentView extends FrameLayout implements Notification
private NotificationViewWrapper mContractedWrapper;
private NotificationViewWrapper mExpandedWrapper;
private NotificationViewWrapper mHeadsUpWrapper;
- private HybridGroupManager mHybridGroupManager;
+ private final HybridGroupManager mHybridGroupManager;
private int mClipTopAmount;
private int mContentHeight;
private int mVisibleType = VISIBLE_TYPE_NONE;
@@ -128,7 +126,6 @@ public class NotificationContentView extends FrameLayout implements Notification
private int mHeadsUpHeight;
private int mNotificationMaxHeight;
private NotificationEntry mNotificationEntry;
- private GroupMembershipManager mGroupMembershipManager;
private RemoteInputController mRemoteInputController;
private Runnable mExpandedVisibleListener;
private PeopleNotificationIdentifier mPeopleIdentifier;
@@ -184,7 +181,6 @@ public class NotificationContentView extends FrameLayout implements Notification
private boolean mFocusOnVisibilityChange;
private boolean mHeadsUpAnimatingAway;
private int mClipBottomAmount;
- private boolean mIsLowPriority;
private boolean mIsContentExpandable;
private boolean mRemoteInputVisible;
private int mUnrestrictedContentHeight;
@@ -192,16 +188,23 @@ public class NotificationContentView extends FrameLayout implements Notification
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
mHybridGroupManager = new HybridGroupManager(getContext());
- mSmartReplyConstants = Dependency.get(SmartReplyConstants.class);
- mSmartReplyController = Dependency.get(SmartReplyController.class);
- initView();
+ reinflate();
}
- public void initView() {
+ public void initialize(
+ PeopleNotificationIdentifier peopleNotificationIdentifier,
+ RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
+ SmartReplyConstants smartReplyConstants,
+ SmartReplyController smartReplyController) {
+ mPeopleIdentifier = peopleNotificationIdentifier;
+ mRemoteInputSubcomponentFactory = rivSubcomponentFactory;
+ mSmartReplyConstants = smartReplyConstants;
+ mSmartReplyController = smartReplyController;
+ }
+
+ public void reinflate() {
mMinContractedHeight = getResources().getDimensionPixelSize(
R.dimen.min_notification_layout_height);
- mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_margin_end);
}
public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
@@ -1606,7 +1609,6 @@ public class NotificationContentView extends FrameLayout implements Notification
}
public void setGroupMembershipManager(GroupMembershipManager groupMembershipManager) {
- mGroupMembershipManager = groupMembershipManager;
}
public void setRemoteInputController(RemoteInputController r) {
@@ -1694,10 +1696,6 @@ public class NotificationContentView extends FrameLayout implements Notification
mContainingNotification = containingNotification;
}
- public void setPeopleNotificationIdentifier(PeopleNotificationIdentifier peopleIdentifier) {
- mPeopleIdentifier = peopleIdentifier;
- }
-
public void requestSelectLayout(boolean needsAnimation) {
selectLayout(needsAnimation, false);
}
@@ -1865,7 +1863,6 @@ public class NotificationContentView extends FrameLayout implements Notification
}
public void setIsLowPriority(boolean isLowPriority) {
- mIsLowPriority = isLowPriority;
}
public boolean isDimmable() {
@@ -2090,10 +2087,6 @@ public class NotificationContentView extends FrameLayout implements Notification
return false;
}
- public void setRemoteInputViewSubcomponentFactory(RemoteInputViewSubcomponent.Factory factory) {
- mRemoteInputSubcomponentFactory = factory;
- }
-
private static class RemoteInputViewData {
@Nullable RemoteInputView mView;
@Nullable RemoteInputViewController mController;
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 ade95a8cbfe7..c89f4d797819 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
@@ -217,6 +217,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private HashSet<View> mFromMoreCardAdditions = new HashSet<>();
private ArrayList<AnimationEvent> mAnimationEvents = new ArrayList<>();
private ArrayList<View> mSwipedOutViews = new ArrayList<>();
+ private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
private boolean mAnimationsEnabled;
private boolean mChangePositionInProgress;
@@ -415,6 +416,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private NotificationShelf mShelf;
private int mMaxDisplayedNotifications = -1;
private float mKeyguardBottomPadding = -1;
+ private float mKeyguardNotificationAvailableSpace = -1;
@VisibleForTesting int mStatusBarHeight;
private int mMinInteractionHeight;
private final Rect mClipRect = new Rect();
@@ -757,31 +759,34 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
} else {
mDebugTextUsedYPositions.clear();
}
- int y = mTopPadding;
- drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding = "+y);
+ int y = 0;
+ drawDebugInfo(canvas, y, Color.RED, /* label= */ "y = " + y);
+
+ y = mTopPadding;
+ drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding = " + y);
y = getLayoutHeight();
- drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight() = "+y);
+ drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight() = " + y);
y = (int) mMaxLayoutHeight;
- drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight = "+y);
+ drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight = " + y);
if (mKeyguardBottomPadding >= 0) {
y = getHeight() - (int) mKeyguardBottomPadding;
drawDebugInfo(canvas, y, Color.GRAY,
- /* label= */ "getHeight() - mKeyguardBottomPadding = "+y);
+ /* label= */ "getHeight() - mKeyguardBottomPadding = " + y);
}
y = getHeight() - getEmptyBottomMargin();
drawDebugInfo(canvas, y, Color.GREEN,
- /* label= */ "getHeight() - getEmptyBottomMargin() = "+y);
+ /* label= */ "getHeight() - getEmptyBottomMargin() = " + y);
y = (int) (mAmbientState.getStackY());
- drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY() = "+y);
+ drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY() = " + y);
y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
drawDebugInfo(canvas, y, Color.BLUE,
- /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = "+y);
+ /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = " + y);
y = (int) mAmbientState.getStackY() + mContentHeight;
drawDebugInfo(canvas, y, Color.MAGENTA,
@@ -790,6 +795,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
y = (int) mAmbientState.getStackY() + mIntrinsicContentHeight;
drawDebugInfo(canvas, y, Color.YELLOW,
/* label= */ "mAmbientState.getStackY() + mIntrinsicContentHeight = " + y);
+
+ y = (int) (mAmbientState.getStackY() + mKeyguardNotificationAvailableSpace);
+ drawDebugInfo(canvas, y, Color.RED, /* label= */
+ "mAmbientState.getStackY() + mKeyguardNotificationAvailableSpace = " + y);
}
private void drawDebugInfo(Canvas canvas, int y, int color, String label) {
@@ -956,13 +965,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
private void reinitView() {
- initView(getContext(), mSwipeHelper);
+ initView(getContext(), mSwipeHelper, mNotificationStackSizeCalculator);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- void initView(Context context, NotificationSwipeHelper swipeHelper) {
+ void initView(Context context, NotificationSwipeHelper swipeHelper,
+ NotificationStackSizeCalculator notificationStackSizeCalculator) {
mScroller = new OverScroller(getContext());
mSwipeHelper = swipeHelper;
+ mNotificationStackSizeCalculator = notificationStackSizeCalculator;
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setClipChildren(false);
@@ -2248,48 +2259,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateContentHeight() {
final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mMinimumPaddings;
- int height = (int) scrimTopPadding;
- float previousPaddingRequest = mPaddingBetweenElements;
- int numShownItems = 0;
- int numShownNotifs = 0;
- boolean finish = false;
- int maxDisplayedNotifications = mMaxDisplayedNotifications;
- ExpandableView previousView = null;
-
- for (int i = 0; i < getChildCount(); i++) {
- ExpandableView expandableView = (ExpandableView) getChildAt(i);
- boolean footerViewOnLockScreen = expandableView == mFooterView && onKeyguard();
-
- if (expandableView.getVisibility() != View.GONE
- && !expandableView.hasNoContentHeight() && !footerViewOnLockScreen) {
-
- boolean limitReached = maxDisplayedNotifications != -1
- && numShownNotifs >= maxDisplayedNotifications;
- final float viewHeight;
- if (limitReached) {
- viewHeight = mShelf.getIntrinsicHeight();
- finish = true;
- } else {
- viewHeight = expandableView.getIntrinsicHeight();
- }
- if (height != 0) {
- height += mPaddingBetweenElements;
- }
- float gapHeight = calculateGapHeight(previousView, expandableView, numShownNotifs);
- height += gapHeight;
- height += viewHeight;
-
- numShownItems++;
- if (viewHeight > 0 || !(expandableView instanceof MediaContainerView)) {
- // Only count the media as a notification if it has a positive height.
- numShownNotifs++;
- }
- previousView = expandableView;
- if (finish) {
- break;
- }
- }
- }
+ final int height =
+ (int) scrimTopPadding + (int) mNotificationStackSizeCalculator.computeHeight(
+ /* notificationStackScrollLayout= */ this, mMaxDisplayedNotifications,
+ mShelf != null ? mShelf.getIntrinsicHeight() : 0);
mIntrinsicContentHeight = height;
// The topPadding can be bigger than the regular padding when qs is expanded, in that
@@ -4932,6 +4905,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mKeyguardBottomPadding = keyguardBottomPadding;
}
+ /**
+ * For debugging only. Enables to draw a line related to the available size for notifications in
+ * keyguard.
+ */
+ public void setKeyguardAvailableSpaceForDebug(float keyguardNotificationAvailableSpace) {
+ mKeyguardNotificationAvailableSpace = keyguardNotificationAvailableSpace;
+ }
+
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) {
mShouldShowShelfOnly = shouldShowShelfOnly;
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 6bbecc8438bc..d98f8a77cc8d 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
@@ -181,6 +181,7 @@ public class NotificationStackScrollLayoutController {
private final SectionHeaderController mSilentHeaderController;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final InteractionJankMonitor mJankMonitor;
+ private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private final StackStateLogger mStackStateLogger;
private final NotificationStackScrollLogger mLogger;
@@ -307,6 +308,7 @@ public class NotificationStackScrollLayoutController {
R.dimen.lockscreen_shade_notification_movement);
mTotalDistanceForFullShadeTransition = mResources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance);
+ mNotificationStackSizeCalculator.updateResources();
}
private final StatusBarStateController.StateListener mStateListener =
@@ -662,7 +664,8 @@ public class NotificationStackScrollLayoutController {
ShadeController shadeController,
InteractionJankMonitor jankMonitor,
StackStateLogger stackLogger,
- NotificationStackScrollLogger logger) {
+ NotificationStackScrollLogger logger,
+ NotificationStackSizeCalculator notificationStackSizeCalculator) {
mStackStateLogger = stackLogger;
mLogger = logger;
mAllowLongPress = allowLongPress;
@@ -688,6 +691,7 @@ public class NotificationStackScrollLayoutController {
mCentralSurfaces = centralSurfaces;
mScrimController = scrimController;
mJankMonitor = jankMonitor;
+ mNotificationStackSizeCalculator = notificationStackSizeCalculator;
groupManager.registerGroupExpansionChangeListener(
(changedRow, expanded) -> mView.onGroupExpandChanged(changedRow, expanded));
legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() {
@@ -758,7 +762,7 @@ public class NotificationStackScrollLayoutController {
});
}
- mView.initView(mView.getContext(), mSwipeHelper);
+ mView.initView(mView.getContext(), mSwipeHelper, mNotificationStackSizeCalculator);
mView.setKeyguardBypassEnabled(mKeyguardBypassController.getBypassEnabled());
mKeyguardBypassController
.registerOnBypassStateChangedListener(mView::setKeyguardBypassEnabled);
@@ -907,6 +911,13 @@ public class NotificationStackScrollLayoutController {
return mView.getTop();
}
+ /**
+ * @return the bottom of the view.
+ */
+ public int getBottom() {
+ return mView.getBottom();
+ }
+
public float getTranslationX() {
return mView.getTranslationX();
}
@@ -1296,10 +1307,16 @@ public class NotificationStackScrollLayoutController {
* appear on the keyguard.
* Setting a negative number will disable rendering this line.
*/
- public void setKeyguardBottomPadding(float keyguardBottomPadding) {
+ public void setKeyguardBottomPaddingForDebug(float keyguardBottomPadding) {
mView.setKeyguardBottomPadding(keyguardBottomPadding);
}
+ /** For debugging only. */
+ public void mKeyguardNotificationAvailableSpaceForDebug(
+ float keyguardNotificationAvailableSpace) {
+ mView.setKeyguardAvailableSpaceForDebug(keyguardNotificationAvailableSpace);
+ }
+
public RemoteInputController.Delegate createDelegate() {
return new RemoteInputController.Delegate() {
public void setRemoteInputActive(NotificationEntry entry,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
new file mode 100644
index 000000000000..3f97155242b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -0,0 +1,261 @@
+/*
+ * 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.statusbar.notification.stack
+
+import android.content.res.Resources
+import android.util.Log
+import android.view.View.GONE
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.util.children
+import javax.inject.Inject
+import kotlin.math.max
+import kotlin.properties.Delegates.notNull
+
+private const val TAG = "NotificationStackSizeCalculator"
+private const val DEBUG = false
+
+/** Calculates number of notifications to display and the height of the notification stack. */
+@SysUISingleton
+class NotificationStackSizeCalculator
+@Inject
+constructor(
+ private val groupManager: NotificationGroupManagerLegacy,
+ private val lockscreenUserManager: NotificationLockscreenUserManager,
+ private val statusBarStateController: SysuiStatusBarStateController,
+ @Main private val resources: Resources
+) {
+
+ /**
+ * Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow shelf.
+ * If there are exactly 1 + mMaxKeyguardNotifications, and they fit in the available space
+ * (considering the overflow shelf is not displayed in this case), then all notifications are
+ * shown.
+ */
+ private var maxKeyguardNotifications by notNull<Int>()
+
+ /**
+ * Minimum space between two notifications. There might be more space, see [calculateGapHeight].
+ */
+ private var notificationPadding by notNull<Int>()
+
+ init {
+ updateResources()
+ }
+
+ /**
+ * Given the [availableSpace] constraint, calculates how many notification to show.
+ *
+ * This number is only valid in keyguard.
+ *
+ * @param availableSpace space for notifications. This doesn't include the space for the shelf.
+ */
+ fun computeMaxKeyguardNotifications(
+ stack: NotificationStackScrollLayout,
+ availableSpace: Float,
+ shelfHeight: Float
+ ): Int {
+ log {
+ "computeMaxKeyguardNotifications(" +
+ "availableSpace=$availableSpace shelfHeight=$shelfHeight)"
+ }
+
+ val children: Sequence<ExpandableView> = stack.childrenSequence
+ var remainingSpace: Float = availableSpace
+ var count = 0
+ var previous: ExpandableView? = null
+ val onLockscreen = true
+ val showableRows = children.filter { it.isShowable(onLockscreen) }
+ val showableRowsCount = showableRows.count()
+ showableRows.forEachIndexed { i, current ->
+ val spaceNeeded = current.spaceNeeded(count, previous, stack, onLockscreen)
+ previous = current
+ log { "\ti=$i spaceNeeded=$spaceNeeded remainingSpace=$remainingSpace" }
+
+ if (remainingSpace - spaceNeeded >= 0 && count < maxKeyguardNotifications) {
+ count += 1
+ remainingSpace -= spaceNeeded
+ } else if (remainingSpace - spaceNeeded > -shelfHeight && i == showableRowsCount - 1) {
+ log { "Showing all notifications. Shelf is not be needed." }
+ // If this is the last one, and it fits using the space shelf would use, then we can
+ // display it, as the shelf will not be needed (as all notifications are shown).
+ return count + 1
+ } else {
+ log {
+ "No more fit. Returning $count. Space used: ${availableSpace - remainingSpace}"
+ }
+ return count
+ }
+ }
+ log { "All fit. Returning $count" }
+ return count
+ }
+
+ /**
+ * Given the [maxNotifications] constraint, calculates the height of the
+ * [NotificationStackScrollLayout]. This might or might not be in keyguard.
+ *
+ * @param stack stack containing notifications as children.
+ * @param maxNotifications Maximum number of notifications. When reached, the others will go
+ * into the shelf.
+ * @param shelfHeight height of the shelf. It might be zero.
+ *
+ * @return height of the stack, including shelf height, if needed.
+ */
+ fun computeHeight(
+ stack: NotificationStackScrollLayout,
+ maxNotifications: Int,
+ shelfHeight: Float
+ ): Float {
+ val children: Sequence<ExpandableView> = stack.childrenSequence
+ val maxNotificationsArg = infiniteIfNegative(maxNotifications)
+ var height = 0f
+ var previous: ExpandableView? = null
+ var count = 0
+ val onLockscreen = onLockscreen()
+
+ log { "computeHeight(maxNotification=$maxNotifications, shelf=$shelfHeight" }
+ children.filter { it.isShowable(onLockscreen) }.forEach { current ->
+ if (count < maxNotificationsArg) {
+ val spaceNeeded = current.spaceNeeded(count, previous, stack, onLockscreen)
+ log { "\ti=$count spaceNeeded=$spaceNeeded" }
+ height += spaceNeeded
+ count += 1
+ } else {
+ height += shelfHeight
+ log { "returning height with shelf -> $height" }
+ return height
+ }
+ previous = current
+ }
+ log { "Returning height without shelf -> $height" }
+ return height
+ }
+
+ fun updateResources() {
+ maxKeyguardNotifications =
+ infiniteIfNegative(resources.getInteger(R.integer.keyguard_max_notification_count))
+
+ notificationPadding =
+ max(1, resources.getDimensionPixelSize(R.dimen.notification_divider_height))
+ }
+
+ private val NotificationStackScrollLayout.childrenSequence: Sequence<ExpandableView>
+ get() = children.map { it as ExpandableView }
+
+ private fun onLockscreen() = statusBarStateController.state == KEYGUARD
+
+ private fun ExpandableView.spaceNeeded(
+ visibleIndex: Int,
+ previousView: ExpandableView?,
+ stack: NotificationStackScrollLayout,
+ onLockscreen: Boolean
+ ): Float {
+ assert(isShowable(onLockscreen))
+ var size =
+ if (onLockscreen) {
+ getMinHeight(/* ignoreTemporaryStates= */ true).toFloat()
+ } else {
+ intrinsicHeight.toFloat()
+ }
+ if (visibleIndex != 0) {
+ size += notificationPadding
+ }
+ size += calculateGapHeight(stack, previousView, visibleIndex)
+ return size
+ }
+
+ private fun ExpandableView.isShowable(onLockscreen: Boolean): Boolean {
+ if (visibility == GONE || hasNoContentHeight()) return false
+ if (onLockscreen) {
+ when (this) {
+ is ExpandableNotificationRow -> {
+ if (isSummaryOfSuppressedGroup() || !canShowViewOnLockscreen() || isRemoved) {
+ return false
+ }
+ }
+ is MediaContainerView -> if (intrinsicHeight == 0) return false
+ else -> return false
+ }
+ }
+ return true
+ }
+
+ private fun ExpandableView.calculateGapHeight(
+ stack: NotificationStackScrollLayout,
+ previous: ExpandableView?,
+ visibleIndex: Int
+ ) = stack.calculateGapHeight(previous, /* current= */ this, visibleIndex)
+
+ private fun ExpandableNotificationRow.isSummaryOfSuppressedGroup() =
+ groupManager.isSummaryOfSuppressedGroup(entry.sbn)
+
+ /**
+ * Can a view be shown on the lockscreen when calculating the number of allowed notifications to
+ * show?
+ *
+ * @return `true` if it can be shown.
+ */
+ private fun ExpandableView.canShowViewOnLockscreen(): Boolean {
+ if (hasNoContentHeight()) {
+ return false
+ }
+ if (this is ExpandableNotificationRow && !canShowRowOnLockscreen()) {
+ return false
+ } else if (visibility == GONE) {
+ return false
+ }
+ return true
+ }
+
+ /**
+ * Can a row be shown on the lockscreen when calculating the number of allowed notifications to
+ * show?
+ *
+ * @return true if it can be shown
+ */
+ private fun ExpandableNotificationRow.canShowRowOnLockscreen(): Boolean {
+ if (isSummaryOfSuppressedGroup()) {
+ return false
+ }
+ if (!lockscreenUserManager.shouldShowOnKeyguard(entry)) {
+ return false
+ }
+ return !isRemoved
+ }
+
+ private fun log(s: () -> String) {
+ if (DEBUG) {
+ Log.d(TAG, s())
+ }
+ }
+
+ /** Returns infinite when [v] is negative. Useful in case a resource doesn't limit when -1. */
+ private fun infiniteIfNegative(v: Int): Int =
+ if (v < 0) {
+ Int.MAX_VALUE
+ } else {
+ v
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 732e5f0343a2..602d075b167d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -23,6 +23,7 @@ import static com.android.systemui.statusbar.notification.NotificationUtils.inte
import android.content.res.Resources;
import android.util.MathUtils;
+import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
@@ -169,7 +170,8 @@ public class KeyguardClockPositionAlgorithm {
boolean isSplitShade, float udfpsTop, float clockBottom, boolean isClockTopAligned) {
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
userSwitchHeight);
- mPanelExpansion = panelExpansion;
+ mPanelExpansion = BouncerPanelExpansionCalculator
+ .getKeyguardClockScaledExpansion(panelExpansion);
mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin;
mUserSwitchHeight = userSwitchHeight;
mUserSwitchPreferredY = userSwitchPreferredY;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 571c10b3800f..64b0b4e2909f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -16,34 +16,52 @@
package com.android.systemui.statusbar.phone
+import android.content.Context
+import android.content.pm.PackageManager
import android.hardware.Sensor
import android.hardware.TriggerEvent
import android.hardware.TriggerEventListener
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.CoreStartable
import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.util.Assert
import com.android.systemui.util.sensors.AsyncSensorManager
import java.io.FileDescriptor
import java.io.PrintWriter
+import javax.inject.Inject
-class KeyguardLiftController constructor(
+/**
+ * Triggers face auth on lift when the device is showing the lock screen. Only initialized
+ * if face auth is supported on the device. Not to be confused with the lift to wake gesture
+ * which is handled by {@link com.android.server.policy.PhoneWindowManager}.
+ */
+@SysUISingleton
+class KeyguardLiftController @Inject constructor(
+ private val context: Context,
private val statusBarStateController: StatusBarStateController,
private val asyncSensorManager: AsyncSensorManager,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- dumpManager: DumpManager
-) : StatusBarStateController.StateListener, Dumpable, KeyguardUpdateMonitorCallback() {
+ private val dumpManager: DumpManager
+) : Dumpable, CoreStartable(context) {
private val pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
private var isListening = false
private var bouncerVisible = false
- init {
+ override fun start() {
+ if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ init()
+ }
+ }
+
+ private fun init() {
dumpManager.registerDumpable(javaClass.name, this)
- statusBarStateController.addCallback(this)
- keyguardUpdateMonitor.registerCallback(this)
+ statusBarStateController.addCallback(statusBarStateListener)
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
updateListeningState()
}
@@ -58,17 +76,21 @@ class KeyguardLiftController constructor(
}
}
- override fun onDozingChanged(isDozing: Boolean) {
- updateListeningState()
- }
+ private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
+ override fun onKeyguardBouncerChanged(bouncer: Boolean) {
+ bouncerVisible = bouncer
+ updateListeningState()
+ }
- override fun onKeyguardBouncerChanged(bouncer: Boolean) {
- bouncerVisible = bouncer
- updateListeningState()
+ override fun onKeyguardVisibilityChanged(showing: Boolean) {
+ updateListeningState()
+ }
}
- override fun onKeyguardVisibilityChanged(showing: Boolean) {
- updateListeningState()
+ private val statusBarStateListener = object : StatusBarStateController.StateListener {
+ override fun onDozingChanged(isDozing: Boolean) {
+ updateListeningState()
+ }
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 65173a230871..cb332bdf59b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -174,7 +174,7 @@ public class KeyguardStatusBarView extends RelativeLayout {
}
private void updateKeyguardStatusBarHeight() {
- MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
+ MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
lp.height = getStatusBarHeaderHeightKeyguard(mContext);
setLayoutParams(lp);
}
@@ -510,28 +510,6 @@ public class KeyguardStatusBarView extends RelativeLayout {
}
}
- void onSystemChromeAnimationStart(boolean isAnimatingOut) {
- if (isAnimatingOut) {
- mSystemIconsContainer.setVisibility(View.VISIBLE);
- mSystemIconsContainer.setAlpha(0f);
- }
- }
-
- void onSystemChromeAnimationEnd(boolean isAnimatingIn) {
- // Make sure the system icons are out of the way
- if (isAnimatingIn) {
- mSystemIconsContainer.setVisibility(View.INVISIBLE);
- mSystemIconsContainer.setAlpha(0f);
- } else {
- mSystemIconsContainer.setAlpha(1f);
- mSystemIconsContainer.setVisibility(View.VISIBLE);
- }
- }
-
- void onSystemChromeAnimationUpdate(float animatedValue) {
- mSystemIconsContainer.setAlpha(animatedValue);
- }
-
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 1df1aff38593..a70ba8236e9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -17,8 +17,6 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -47,6 +45,7 @@ import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.fragment.StatusBarSystemEventAnimator;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserInfoTracker;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherFeatureController;
@@ -59,7 +58,6 @@ import com.android.systemui.util.ViewController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
@@ -107,6 +105,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
@Override
public void onDensityOrFontScaleChanged() {
mView.loadDimens();
+ // The animator is dependent on resources for offsets
+ mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, getResources());
}
@Override
@@ -123,21 +123,16 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
private final SystemStatusAnimationCallback mAnimationCallback =
new SystemStatusAnimationCallback() {
+ @NonNull
@Override
- public void onSystemChromeAnimationStart() {
- mView.onSystemChromeAnimationStart(
- mAnimationScheduler.getAnimationState() == ANIMATING_OUT);
+ public Animator onSystemEventAnimationFinish(boolean hasPersistentDot) {
+ return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
}
+ @NonNull
@Override
- public void onSystemChromeAnimationEnd() {
- mView.onSystemChromeAnimationEnd(
- mAnimationScheduler.getAnimationState() == ANIMATING_IN);
- }
-
- @Override
- public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator anim) {
- mView.onSystemChromeAnimationUpdate((float) anim.getAnimatedValue());
+ public Animator onSystemEventAnimationBegin() {
+ return mSystemEventAnimator.onSystemEventAnimationBegin();
}
};
@@ -232,6 +227,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
private int mStatusBarState;
private boolean mDozing;
private boolean mShowingKeyguardHeadsUp;
+ private StatusBarSystemEventAnimator mSystemEventAnimator;
@Inject
public KeyguardStatusBarViewController(
@@ -292,16 +288,15 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat
);
Resources r = getResources();
- mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
- r.getString(com.android.internal.R.string.status_bar_volume),
- r.getString(com.android.internal.R.string.status_bar_alarm_clock),
- r.getString(com.android.internal.R.string.status_bar_call_strength)));
+ mBlockedIcons = Arrays.asList(r.getStringArray(
+ R.array.config_keyguard_statusbar_icon_blocklist));
mNotificationsHeaderCollideDistance = r.getDimensionPixelSize(
R.dimen.header_notifications_collide_distance);
mView.setKeyguardUserAvatarEnabled(
!mFeatureController.isStatusBarUserSwitcherFeatureEnabled());
mFeatureController.addCallback(enabled -> mView.setKeyguardUserAvatarEnabled(!enabled));
+ mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 1891ab017ef8..5746ffb6debe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.view.View.GONE;
import static androidx.constraintlayout.widget.ConstraintSet.END;
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
@@ -144,7 +143,6 @@ import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -165,17 +163,16 @@ import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.render.ShadeViewManager;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
-import com.android.systemui.statusbar.notification.stack.MediaContainerView;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
@@ -312,9 +309,6 @@ public class NotificationPanelViewController extends PanelViewController {
private final ControlsComponent mControlsComponent;
private final NotificationRemoteInputManager mRemoteInputManager;
- // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
- // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
- private final int mMaxKeyguardNotifications;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final TapAgainViewController mTapAgainViewController;
private final SplitShadeHeaderController mSplitShadeHeaderController;
@@ -323,6 +317,8 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mShouldUseSplitNotificationShade;
// The bottom padding reserved for elements of the keyguard measuring notifications
private float mKeyguardNotificationBottomPadding;
+ // Space available for notifications.
+ private float mKeyguardNotificationAvailableSpace;
// Current max allowed keyguard notifications determined by measuring the panel
private int mMaxAllowedKeyguardNotifications;
@@ -446,8 +442,6 @@ public class NotificationPanelViewController extends PanelViewController {
setHeadsUpAnimatingAway(false);
updatePanelExpansionAndVisibility();
};
- // TODO (b/162832756): once migrated to the new pipeline, delete legacy group manager
- private NotificationGroupManagerLegacy mGroupManager;
private boolean mShowIconsWhenExpanded;
private int mIndicationBottomPadding;
private int mAmbientIndicationBottomPadding;
@@ -509,7 +503,6 @@ public class NotificationPanelViewController extends PanelViewController {
private final NotificationEntryManager mEntryManager;
private final CommandQueue mCommandQueue;
- private final NotificationLockscreenUserManager mLockscreenUserManager;
private final UserManager mUserManager;
private final MediaDataManager mMediaDataManager;
private final SysUiState mSysUiState;
@@ -651,6 +644,7 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationPanelUnfoldAnimationController;
private final NotificationListContainer mNotificationListContainer;
+ private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
@Override
@@ -695,7 +689,6 @@ public class NotificationPanelViewController extends PanelViewController {
DynamicPrivacyController dynamicPrivacyController,
KeyguardBypassController bypassController, FalsingManager falsingManager,
FalsingCollector falsingCollector,
- NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationEntryManager notificationEntryManager,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
@@ -721,7 +714,6 @@ public class NotificationPanelViewController extends PanelViewController {
KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory,
KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
- NotificationGroupManagerLegacy groupManager,
NotificationIconAreaController notificationIconAreaController,
AuthController authController,
ScrimController scrimController,
@@ -753,7 +745,8 @@ public class NotificationPanelViewController extends PanelViewController {
SysUiState sysUiState,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
NotificationListContainer notificationListContainer,
- PanelEventsEmitter panelEventsEmitter) {
+ PanelEventsEmitter panelEventsEmitter,
+ NotificationStackSizeCalculator notificationStackSizeCalculator) {
super(view,
falsingManager,
dozeLog,
@@ -785,9 +778,9 @@ public class NotificationPanelViewController extends PanelViewController {
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mNotificationsQSContainerController = notificationsQSContainerController;
mNotificationListContainer = notificationListContainer;
+ mNotificationStackSizeCalculator = notificationStackSizeCalculator;
mNotificationsQSContainerController.init();
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
- mGroupManager = groupManager;
mNotificationIconAreaController = notificationIconAreaController;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
@@ -849,7 +842,6 @@ public class NotificationPanelViewController extends PanelViewController {
});
mBottomAreaShadeAlphaAnimator.setDuration(160);
mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
- mLockscreenUserManager = notificationLockscreenUserManager;
mEntryManager = notificationEntryManager;
mConversationNotificationManager = conversationNotificationManager;
mAuthController = authController;
@@ -874,7 +866,6 @@ public class NotificationPanelViewController extends PanelViewController {
mView.getOverlay().add(new DebugDrawable());
}
- mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
mKeyguardUnfoldTransition = unfoldComponent.map(c -> c.getKeyguardUnfoldTransition());
mNotificationPanelUnfoldAnimationController = unfoldComponent.map(
SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
@@ -1238,12 +1229,14 @@ public class NotificationPanelViewController extends PanelViewController {
if (mKeyguardShowing && !mKeyguardBypassController.getBypassEnabled()) {
mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(
mMaxAllowedKeyguardNotifications);
- mNotificationStackScrollLayoutController.setKeyguardBottomPadding(
+ mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug(
mKeyguardNotificationBottomPadding);
+ mNotificationStackScrollLayoutController.mKeyguardNotificationAvailableSpaceForDebug(
+ mKeyguardNotificationAvailableSpace);
} else {
// no max when not on the keyguard
mNotificationStackScrollLayoutController.setMaxDisplayedNotifications(-1);
- mNotificationStackScrollLayoutController.setKeyguardBottomPadding(-1f);
+ mNotificationStackScrollLayoutController.setKeyguardBottomPaddingForDebug(-1f);
}
}
@@ -1454,127 +1447,38 @@ public class NotificationPanelViewController extends PanelViewController {
* @return the maximum keyguard notifications that can fit on the screen
*/
private int computeMaxKeyguardNotifications() {
- float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
int notificationPadding = Math.max(
1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height));
- float shelfSize =
+ float topPadding = mNotificationStackScrollLayoutController.getTopPadding();
+ float shelfHeight =
mNotificationShelfController.getVisibility() == View.GONE
? 0
: mNotificationShelfController.getIntrinsicHeight() + notificationPadding;
+ // Padding to add to the bottom of the stack to keep a minimum distance from the top of
+ // the lock icon.
float lockIconPadding = 0;
if (mLockIconViewController.getTop() != 0) {
- lockIconPadding = mCentralSurfaces.getDisplayHeight() - mLockIconViewController.getTop()
- + mResources.getDimensionPixelSize(R.dimen.min_lock_icon_padding);
+ final float lockIconTopWithPadding = mLockIconViewController.getTop()
+ - mResources.getDimensionPixelSize(R.dimen.min_lock_icon_padding);
+ lockIconPadding = mNotificationStackScrollLayoutController.getBottom()
+ - lockIconTopWithPadding;
}
- float bottomPadding = Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding);
- bottomPadding = Math.max(lockIconPadding, bottomPadding);
+ float bottomPadding = Math.max(lockIconPadding,
+ Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding));
mKeyguardNotificationBottomPadding = bottomPadding;
float availableSpace =
mNotificationStackScrollLayoutController.getHeight()
- - minPadding
- - shelfSize
+ - topPadding
+ - shelfHeight
- bottomPadding;
+ mKeyguardNotificationAvailableSpace = availableSpace;
- int count = 0;
- ExpandableView previousView = null;
- for (int i = 0; i < mNotificationStackScrollLayoutController.getChildCount(); i++) {
- ExpandableView child = mNotificationStackScrollLayoutController.getChildAt(i);
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- boolean suppressedSummary = mGroupManager != null
- && mGroupManager.isSummaryOfSuppressedGroup(row.getEntry().getSbn());
- if (suppressedSummary) {
- continue;
- }
- if (!canShowViewOnLockscreen(child)) {
- continue;
- }
- if (row.isRemoved()) {
- continue;
- }
- } else if (child instanceof MediaContainerView) {
- if (child.getVisibility() == GONE) {
- continue;
- }
- if (child.getIntrinsicHeight() == 0) {
- continue;
- }
- } else {
- continue;
- }
- availableSpace -= child.getMinHeight(true /* ignoreTemporaryStates */);
- availableSpace -= count == 0 ? 0 : notificationPadding;
- availableSpace -= mNotificationStackScrollLayoutController
- .calculateGapHeight(previousView, child, count);
- previousView = child;
- if (availableSpace >= 0
- && (mMaxKeyguardNotifications == -1 || count < mMaxKeyguardNotifications)) {
- count++;
- } else if (availableSpace > -shelfSize) {
- // if we are exactly the last view, then we can show us still!
- int childCount = mNotificationStackScrollLayoutController.getChildCount();
- for (int j = i + 1; j < childCount; j++) {
- ExpandableView view = mNotificationStackScrollLayoutController.getChildAt(j);
- if (view instanceof ExpandableNotificationRow
- && canShowViewOnLockscreen(view)) {
- return count;
- }
- }
- count++;
- return count;
- } else {
- return count;
- }
- }
- return count;
- }
-
- /**
- * Can a view be shown on the lockscreen when calculating the number of allowed notifications
- * to show?
- *
- * @param child the view in question
- * @return true if it can be shown
- */
- private boolean canShowViewOnLockscreen(ExpandableView child) {
- if (child.hasNoContentHeight()) {
- return false;
- }
- if (child instanceof ExpandableNotificationRow &&
- !canShowRowOnLockscreen((ExpandableNotificationRow) child)) {
- return false;
- } else if (child.getVisibility() == GONE) {
- // ENRs can be gone and count because their visibility is only set after
- // this calculation, but all other views should be up to date
- return false;
- }
- return true;
- }
-
- /**
- * Can a row be shown on the lockscreen when calculating the number of allowed notifications
- * to show?
- *
- * @param row the row in question
- * @return true if it can be shown
- */
- private boolean canShowRowOnLockscreen(ExpandableNotificationRow row) {
- boolean suppressedSummary =
- mGroupManager != null && mGroupManager.isSummaryOfSuppressedGroup(
- row.getEntry().getSbn());
- if (suppressedSummary) {
- return false;
- }
- if (!mLockscreenUserManager.shouldShowOnKeyguard(row.getEntry())) {
- return false;
- }
- if (row.isRemoved()) {
- return false;
- }
- return true;
+ return mNotificationStackSizeCalculator.computeMaxKeyguardNotifications(
+ mNotificationStackScrollLayoutController.getView(), availableSpace,
+ shelfHeight);
}
private void updateClock() {
@@ -4883,6 +4787,8 @@ public class NotificationPanelViewController extends PanelViewController {
"calculateNotificationsTopPadding()");
drawDebugInfo(canvas, mClockPositionResult.clockY, Color.GRAY,
"mClockPositionResult.clockY");
+ drawDebugInfo(canvas, (int) mLockIconViewController.getTop(), Color.GRAY,
+ "mLockIconViewController.getTop()");
mDebugPaint.setColor(Color.CYAN);
canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 24f5ff86a794..78edc07c8544 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -445,7 +445,7 @@ public abstract class PanelViewController {
mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK);
}
@Classifier.InteractionType int interactionType = vel == 0 ? GENERIC
- : vel > 0 ? QUICK_SETTINGS
+ : y - mInitialTouchY > 0 ? QUICK_SETTINGS
: (mKeyguardStateController.canDismissLockScreen()
? UNLOCK : BOUNCER_UNLOCK);
@@ -532,7 +532,7 @@ public abstract class PanelViewController {
return true;
}
- @Classifier.InteractionType int interactionType = vel > 0
+ @Classifier.InteractionType int interactionType = y - mInitialTouchY > 0
? QUICK_SETTINGS : (
mKeyguardStateController.canDismissLockScreen() ? UNLOCK : BOUNCER_UNLOCK);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 419661b766d6..029a7a5fcdd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -41,6 +41,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.function.TriConsumer;
+import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.Utils;
@@ -116,6 +117,15 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private float mTransitionToFullShadeProgress;
/**
+ * Same as {@link #mTransitionToFullShadeProgress}, but specifically for the notifications scrim
+ * on the lock screen.
+ *
+ * On split shade lock screen we want the different scrims to fade in at different times and
+ * rates.
+ */
+ private float mTransitionToLockScreenFullShadeNotificationsProgress;
+
+ /**
* If we're currently transitioning to the full shade.
*/
private boolean mTransitioningToFullShade;
@@ -574,11 +584,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
* Set the amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
* shade.
+ *
+ * @param progress the progress for all scrims.
+ * @param lockScreenNotificationsProgress the progress specifically for the notifications scrim.
*/
- public void setTransitionToFullShadeProgress(float progress) {
- if (progress != mTransitionToFullShadeProgress) {
+ public void setTransitionToFullShadeProgress(float progress,
+ float lockScreenNotificationsProgress) {
+ if (progress != mTransitionToFullShadeProgress || lockScreenNotificationsProgress
+ != mTransitionToLockScreenFullShadeNotificationsProgress) {
mTransitionToFullShadeProgress = progress;
- setTransitionToFullShade(progress > 0.0f);
+ mTransitionToLockScreenFullShadeNotificationsProgress = lockScreenNotificationsProgress;
+ setTransitionToFullShade(progress > 0.0f || lockScreenNotificationsProgress > 0.0f);
applyAndDispatchState();
}
}
@@ -754,12 +770,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
} else {
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
}
- if (mState == ScrimState.KEYGUARD && mTransitionToFullShadeProgress > 0.0f) {
+ if (mState == ScrimState.KEYGUARD
+ && mTransitionToLockScreenFullShadeNotificationsProgress > 0.0f) {
// Interpolate the notification alpha when transitioning!
mNotificationsAlpha = MathUtils.lerp(
mNotificationsAlpha,
getInterpolatedFraction(),
- mTransitionToFullShadeProgress);
+ mTransitionToLockScreenFullShadeNotificationsProgress);
}
mNotificationsTint = mState.getNotifTint();
mBehindTint = behindTint;
@@ -792,7 +809,15 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private Pair<Integer, Float> calculateBackStateForState(ScrimState state) {
// Either darken of make the scrim transparent when you
// pull down the shade
- float interpolatedFract = getInterpolatedFraction();
+ float interpolatedFract;
+
+ if (state == ScrimState.KEYGUARD) {
+ interpolatedFract = BouncerPanelExpansionCalculator
+ .getBackScrimScaledExpansion(mPanelExpansionFraction);
+ } else {
+ interpolatedFract = getInterpolatedFraction();
+ }
+
float stateBehind = mClipsQsScrim ? state.getNotifAlpha() : state.getBehindAlpha();
float behindAlpha;
int behindTint;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 637e4bee8948..6fe92fafc075 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -397,15 +397,25 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
mMainThreadHandler.post(() -> {
final Runnable removeNotification = () -> {
mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK, summaryToRemove);
+ if (!animate) {
+ // If we're animating, this would be invoked after the activity launch
+ // animation completes. Since we're not animating, the launch already
+ // happened synchronously, so we notify the launch is complete here after
+ // onDismiss.
+ mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+ }
};
if (mPresenter.isCollapsing()) {
- // To avoid lags we're only performing the remove
- // after the shade is collapsed
+ // To avoid lags we're only performing the remove after the shade is collapsed
mShadeController.addPostCollapseAction(removeNotification);
} else {
removeNotification.run();
}
});
+ } else if (!canBubble && !animate) {
+ // Not animating, this is the end of the launch flow (see above comment for more info).
+ mMainThreadHandler.post(
+ () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
}
mIsCollapsingToShowActivityOverLockscreen = false;
@@ -481,8 +491,9 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
boolean isActivityIntent) {
mLogger.logStartNotificationIntent(entry.getKey(), intent);
try {
- Runnable onFinishAnimationCallback =
- () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+ Runnable onFinishAnimationCallback = animate
+ ? () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry)
+ : null;
ActivityLaunchAnimator.Controller animationController =
new StatusBarLaunchAnimatorController(
mNotificationAnimationProvider
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 2c84219dbfd0..8194957c52fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -20,12 +20,10 @@ import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
import static android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP;
import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
-import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
-import android.animation.ValueAnimator;
+import android.animation.Animator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -74,6 +72,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
@@ -136,6 +135,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
}
};
private OperatorNameViewController mOperatorNameViewController;
+ private StatusBarSystemEventAnimator mSystemEventAnimator;
@SuppressLint("ValidFragment")
public CollapsedStatusBarFragment(
@@ -210,18 +210,31 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
initEmergencyCryptkeeperText();
initOperatorName();
initNotificationIconArea();
- mAnimationScheduler.addCallback(this);
+ mSystemEventAnimator =
+ new StatusBarSystemEventAnimator(mSystemIconArea, getResources());
}
@VisibleForTesting
void updateBlockedIcons() {
mBlockedIcons.clear();
- if (mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0) {
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_volume));
+ // Reload the blocklist from res
+ List<String> blockList = Arrays.asList(getResources().getStringArray(
+ R.array.config_collapsed_statusbar_icon_blocklist));
+ String vibrateIconSlot = getString(com.android.internal.R.string.status_bar_volume);
+ boolean showVibrateIcon =
+ mSecureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0) == 0;
+
+ // Filter out vibrate icon from the blocklist if the setting is on
+ for (int i = 0; i < blockList.size(); i++) {
+ if (blockList.get(i).equals(vibrateIconSlot)) {
+ if (showVibrateIcon) {
+ mBlockedIcons.add(blockList.get(i));
+ }
+ } else {
+ mBlockedIcons.add(blockList.get(i));
+ }
}
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_alarm_clock));
- mBlockedIcons.add(getString(com.android.internal.R.string.status_bar_call_strength));
mMainExecutor.execute(() -> mDarkIconManager.setBlockList(mBlockedIcons));
}
@@ -245,6 +258,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCommandQueue.addCallback(this);
mStatusBarStateController.addCallback(this);
initOngoingCallChip();
+ mAnimationScheduler.addCallback(this);
mSecureSettings.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON),
@@ -258,6 +272,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this);
mOngoingCallController.removeCallback(mOngoingCallListener);
+ mAnimationScheduler.removeCallback(this);
mSecureSettings.unregisterContentObserver(mVolumeSettingObserver);
}
@@ -265,7 +280,6 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
public void onDestroyView() {
super.onDestroyView();
mStatusBarIconController.removeIconGroup(mDarkIconManager);
- mAnimationScheduler.removeCallback(this);
if (mNetworkController.hasEmergencyCryptKeeperText()) {
mNetworkController.removeCallback(mSignalCallback);
}
@@ -576,35 +590,16 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
disable(getContext().getDisplayId(), mDisabled1, mDisabled2, false /* animate */);
}
+ @Nullable
@Override
- public void onSystemChromeAnimationStart() {
- if (mAnimationScheduler.getAnimationState() == ANIMATING_OUT
- && !isSystemIconAreaDisabled()) {
- mSystemIconArea.setVisibility(View.VISIBLE);
- mSystemIconArea.setAlpha(0f);
- }
- }
-
- @Override
- public void onSystemChromeAnimationEnd() {
- // Make sure the system icons are out of the way
- if (mAnimationScheduler.getAnimationState() == ANIMATING_IN) {
- mSystemIconArea.setVisibility(View.INVISIBLE);
- mSystemIconArea.setAlpha(0f);
- } else {
- if (isSystemIconAreaDisabled()) {
- // don't unhide
- return;
- }
-
- mSystemIconArea.setAlpha(1f);
- mSystemIconArea.setVisibility(View.VISIBLE);
- }
+ public Animator onSystemEventAnimationBegin() {
+ return mSystemEventAnimator.onSystemEventAnimationBegin();
}
+ @Nullable
@Override
- public void onSystemChromeAnimationUpdate(@NonNull ValueAnimator animator) {
- mSystemIconArea.setAlpha((float) animator.getAnimatedValue());
+ public Animator onSystemEventAnimationFinish(boolean hasPersistentDot) {
+ return mSystemEventAnimator.onSystemEventAnimationFinish(hasPersistentDot);
}
private boolean isSystemIconAreaDisabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
new file mode 100644
index 000000000000..f530ec83aec5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.statusbar.phone.fragment
+
+import android.animation.Animator
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.content.res.Resources
+import android.view.View
+import com.android.systemui.R
+import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_IN
+import com.android.systemui.statusbar.events.STATUS_BAR_X_MOVE_OUT
+import com.android.systemui.statusbar.events.SystemStatusAnimationCallback
+
+/**
+ * Tied directly to [SystemStatusAnimationScheduler]. Any StatusBar-like thing (keyguard, collapsed
+ * status bar fragment), can just feed this an animatable view to get the default system status
+ * animation.
+ *
+ * This animator relies on resources, and should be recreated whenever resources are updated. While
+ * this class could be used directly as the animation callback, it's probably best to forward calls
+ * to it so that it can be recreated at any moment without needing to remove/add callback.
+ */
+class StatusBarSystemEventAnimator(
+ val animatedView: View,
+ resources: Resources
+) : SystemStatusAnimationCallback {
+ private val translationXIn: Int = resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_animation_in_status_bar_translation_x)
+ private val translationXOut: Int = resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_animation_out_status_bar_translation_x)
+
+ override fun onSystemEventAnimationBegin(): Animator {
+ val moveOut = ValueAnimator.ofFloat(0f, 1f).setDuration(383)
+ moveOut.interpolator = STATUS_BAR_X_MOVE_OUT
+ moveOut.addUpdateListener { animation: ValueAnimator ->
+ animatedView.translationX = -(translationXIn * animation.animatedValue as Float)
+ }
+ val alphaOut = ValueAnimator.ofFloat(1f, 0f).setDuration(133)
+ alphaOut.interpolator = null
+ alphaOut.addUpdateListener { animation: ValueAnimator ->
+ animatedView.alpha = animation.animatedValue as Float
+ }
+
+ val animSet = AnimatorSet()
+ animSet.playTogether(moveOut, alphaOut)
+ return animSet
+ }
+
+ override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
+ animatedView.translationX = translationXOut.toFloat()
+ val moveIn = ValueAnimator.ofFloat(1f, 0f).setDuration(467)
+ moveIn.startDelay = 33
+ moveIn.interpolator = STATUS_BAR_X_MOVE_IN
+ moveIn.addUpdateListener { animation: ValueAnimator ->
+ animatedView.translationX = translationXOut * animation.animatedValue as Float
+ }
+ val alphaIn = ValueAnimator.ofFloat(0f, 1f).setDuration(167)
+ alphaIn.startDelay = 67
+ alphaIn.interpolator = null
+ alphaIn.addUpdateListener { animation: ValueAnimator ->
+ animatedView.alpha = animation.animatedValue as Float
+ }
+
+ val animatorSet = AnimatorSet()
+ animatorSet.playTogether(moveIn, alphaIn)
+
+ return animatorSet
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index c0d7925cf2bb..9e9b74616d29 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -23,7 +23,6 @@ import android.content.IntentFilter
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.os.UserManager
@@ -149,8 +148,8 @@ class UserSwitcherActivity @Inject constructor(
}
private fun getDrawable(item: UserRecord): Drawable {
- var drawable = if (item.isCurrent && item.isGuest) {
- getDrawable(R.drawable.ic_avatar_guest_user)
+ var drawable = if (item.isGuest) {
+ getDrawable(R.drawable.ic_account_circle)
} else {
findUserIcon(item)
}
@@ -168,7 +167,7 @@ class UserSwitcherActivity @Inject constructor(
val ld = getDrawable(R.drawable.user_switcher_icon_large).mutate()
as LayerDrawable
if (item == userSwitcherController.getCurrentUserRecord()) {
- (ld.getDrawable(1) as GradientDrawable).apply {
+ (ld.findDrawableByLayerId(R.id.ring) as GradientDrawable).apply {
val stroke = resources
.getDimensionPixelSize(R.dimen.user_switcher_icon_selected_width)
val color = Utils.getColorAttrDefaultColor(
@@ -180,15 +179,7 @@ class UserSwitcherActivity @Inject constructor(
}
}
- ld.addLayer(
- InsetDrawable(
- drawable,
- resources.getDimensionPixelSize(
- R.dimen.user_switcher_icon_large_margin
- )
- )
- )
-
+ ld.setDrawableByLayerId(R.id.user_avatar, drawable)
return ld
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
new file mode 100644
index 000000000000..6266bf146f5b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
@@ -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 com.android.keyguard
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class BouncerPanelExpansionCalculatorTest : SysuiTestCase() {
+ @Test
+ fun testGetHostViewScaledExpansion() {
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(1f))
+ .isEqualTo(1f)
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0.9f))
+ .isEqualTo(1f)
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0.59f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getHostViewScaledExpansion(0f))
+ .isEqualTo(0f)
+ assertEquals(BouncerPanelExpansionCalculator
+ .getHostViewScaledExpansion(0.8f), 2f / 3f, 0.01f)
+ }
+
+ @Test
+ fun testGetBackScrimScaledExpansion() {
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(1f))
+ .isEqualTo(1f)
+ assertEquals(BouncerPanelExpansionCalculator
+ .getBackScrimScaledExpansion(0.95f), 1f / 2f, 0.01f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.9f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.5f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0f))
+ .isEqualTo(0f)
+ }
+
+ @Test
+ fun testGetKeyguardClockScaledExpansion() {
+ assertThat(BouncerPanelExpansionCalculator.getKeyguardClockScaledExpansion(1f))
+ .isEqualTo(1f)
+ assertEquals(BouncerPanelExpansionCalculator
+ .getKeyguardClockScaledExpansion(0.8f), 1f / 3f, 0.01f)
+ assertThat(BouncerPanelExpansionCalculator.getKeyguardClockScaledExpansion(0.7f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0.5f))
+ .isEqualTo(0f)
+ assertThat(BouncerPanelExpansionCalculator.getBackScrimScaledExpansion(0f))
+ .isEqualTo(0f)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 7a0db1fd975c..8c7927782d2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -208,6 +208,11 @@ public abstract class SysuiTestCase {
}
}
+ /** Delegates to {@link android.testing.TestableResources#addOverride(int, Object)}. */
+ protected void overrideResource(int resourceId, Object value) {
+ mContext.getOrCreateTestableResources().addOverride(resourceId, value);
+ }
+
public static final class EmptyRunnable implements Runnable {
public void run() {
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index ec2c1de49b4c..a95da6295350 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -114,12 +114,13 @@ class AuthRippleControllerTest : SysuiTestCase() {
}
@Test
- fun testFingerprintTrigger_Ripple() {
+ fun testFingerprintTrigger_KeyguardVisible_Ripple() {
// GIVEN fp exists, keyguard is visible, user doesn't need strong auth
val fpsLocation = PointF(5f, 5f)
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
`when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
// WHEN fingerprint authenticated
@@ -136,7 +137,30 @@ class AuthRippleControllerTest : SysuiTestCase() {
}
@Test
- fun testFingerprintTrigger_KeyguardNotVisible_NoRipple() {
+ fun testFingerprintTrigger_Dreaming_Ripple() {
+ // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
+ val fpsLocation = PointF(5f, 5f)
+ `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
+ controller.onViewAttached()
+ `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(true)
+ `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
+
+ // WHEN fingerprint authenticated
+ val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+ verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+ captor.value.onBiometricAuthenticated(
+ 0 /* userId */,
+ BiometricSourceType.FINGERPRINT /* type */,
+ false /* isStrongBiometric */)
+
+ // THEN update sensor location and show ripple
+ verify(rippleView).setFingerprintSensorLocation(fpsLocation, -1f)
+ verify(rippleView).startUnlockedRipple(any())
+ }
+
+ @Test
+ fun testFingerprintTrigger_KeyguardNotVisible_NotDreaming_NoRipple() {
// GIVEN fp exists & user doesn't need strong auth
val fpsLocation = PointF(5f, 5f)
`when`(authController.udfpsSensorLocation).thenReturn(fpsLocation)
@@ -145,6 +169,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
// WHEN keyguard is NOT visible & fingerprint authenticated
`when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
+ `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
captor.value.onBiometricAuthenticated(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index ef82c3ec3322..fd49766dafef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -61,6 +61,8 @@ import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+private const val REQUEST_ID = 2L
+
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
@@ -119,7 +121,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
statusBarStateController, panelExpansionStateManager, statusBarKeyguardViewManager,
keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
configurationController, systemClock, keyguardStateController,
- unlockedScreenOffAnimationController, sensorProps, hbmProvider, reason,
+ unlockedScreenOffAnimationController, sensorProps, hbmProvider, REQUEST_ID, reason,
controllerCallback, onTouch, activityLaunchAnimator)
block()
}
@@ -263,6 +265,12 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
controllerOverlay.hide()
verify(udfpsView).stopIllumination()
}
+
+ @Test
+ fun matchesRequestIds() = withReason(REASON_AUTH_BP) {
+ assertThat(controllerOverlay.matchesRequestId(REQUEST_ID)).isTrue()
+ assertThat(controllerOverlay.matchesRequestId(REQUEST_ID + 1)).isFalse()
+ }
}
private class EnrollListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 613931f1341f..406ed5c17b0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -102,6 +103,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// Use this for inputs going into SystemUI. Use UdfpsController.mUdfpsSensorId for things
// leaving SystemUI.
private static final int TEST_UDFPS_SENSOR_ID = 1;
+ private static final long TEST_REQUEST_ID = 70;
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@@ -278,7 +280,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void dozeTimeTick() throws RemoteException {
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
mUdfpsController.dozeTimeTick();
@@ -293,7 +295,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -316,7 +318,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mStatusBarStateController.isDozing()).thenReturn(true);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -339,7 +341,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mStatusBarStateController.isDozing()).thenReturn(false);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -362,7 +364,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
(UdfpsAnimationViewController) mock(UdfpsEnrollViewController.class));
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -377,25 +379,42 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
- public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice() throws RemoteException {
+ public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice()
+ throws RemoteException {
+ onActionMoveTouch_whenCanDismissLockScreen_entersDevice(false /* stale */);
+ }
+
+ @Test
+ public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice_ignoreStale()
+ throws RemoteException {
+ onActionMoveTouch_whenCanDismissLockScreen_entersDevice(true /* stale */);
+ }
+
+ public void onActionMoveTouch_whenCanDismissLockScreen_entersDevice(boolean stale)
+ throws RemoteException {
// GIVEN can dismiss lock screen and the current animation is an UdfpsKeyguardViewController
when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// WHEN ACTION_MOVE is received
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ if (stale) {
+ mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+ mFgExecutor.runAllReady();
+ }
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
moveEvent.recycle();
// THEN notify keyguard authenticate to dismiss the keyguard
- verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ verify(mStatusBarKeyguardViewManager, stale ? never() : times(1))
+ .notifyKeyguardAuthenticated(anyBoolean());
}
@Test
@@ -406,7 +425,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -427,7 +446,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
// GIVEN overlay was showing and the udfps bouncer is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true);
@@ -441,7 +460,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -460,7 +479,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// WHEN ACTION_DOWN is received
@@ -472,8 +491,9 @@ public class UdfpsControllerTest extends SysuiTestCase {
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
moveEvent.recycle();
// THEN FingerprintManager is notified about onPointerDown
- verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
- eq(0), eq(0f), eq(0f));
+ verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+ eq(mUdfpsController.mSensorProps.sensorId),
+ eq(0), eq(0), eq(0f), eq(0f));
verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
// AND illumination begins
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
@@ -481,14 +501,15 @@ public class UdfpsControllerTest extends SysuiTestCase {
// AND onIlluminatedRunnable notifies FingerprintManager about onUiReady
mOnIlluminatedRunnableCaptor.getValue().run();
InOrder inOrder = inOrder(mFingerprintManager, mLatencyTracker);
- inOrder.verify(mFingerprintManager).onUiReady(eq(mUdfpsController.mSensorProps.sensorId));
+ inOrder.verify(mFingerprintManager).onUiReady(
+ eq(TEST_REQUEST_ID), eq(mUdfpsController.mSensorProps.sensorId));
inOrder.verify(mLatencyTracker).onActionEnd(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
}
@Test
public void aodInterrupt() throws RemoteException {
// GIVEN that the overlay is showing and screen is on and fp is running
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -499,14 +520,15 @@ public class UdfpsControllerTest extends SysuiTestCase {
// AND onIlluminatedRunnable that notifies FingerprintManager is set
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
mOnIlluminatedRunnableCaptor.getValue().run();
- verify(mFingerprintManager).onPointerDown(eq(mUdfpsController.mSensorProps.sensorId), eq(0),
- eq(0), eq(3f) /* minor */, eq(2f) /* major */);
+ verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
+ eq(mUdfpsController.mSensorProps.sensorId),
+ eq(0), eq(0), eq(3f) /* minor */, eq(2f) /* major */);
}
@Test
public void cancelAodInterrupt() throws RemoteException {
// GIVEN AOD interrupt
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -522,7 +544,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterruptTimeout() throws RemoteException {
// GIVEN AOD interrupt
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -539,7 +561,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterruptScreenOff() throws RemoteException {
// GIVEN screen off
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOff();
mFgExecutor.runAllReady();
@@ -555,7 +577,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterrupt_fingerprintNotRunning() throws RemoteException {
// GIVEN showing overlay
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD,
mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
@@ -577,7 +599,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing and a11y touch exploration enabled
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
@@ -612,7 +634,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the overlay is showing and a11y touch exploration NOT enabled
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index a32ff801e824..a6921b441f17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -53,6 +53,8 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.Executor;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
@@ -90,6 +92,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
@Mock
ZenModeController mZenModeController;
+ private final Executor mMainExecutor = Runnable::run;
+
DreamOverlayStatusBarViewController mController;
@Before
@@ -102,6 +106,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
mController = new DreamOverlayStatusBarViewController(
mView,
mResources,
+ mMainExecutor,
mConnectivityManager,
mTouchSession,
mAlarmManager,
@@ -134,7 +139,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
.thenReturn(false);
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
}
@Test
@@ -143,13 +149,16 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
.thenReturn(true);
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
}
@Test
public void testOnViewAttachedShowsWifiIconWhenNetworkCapabilitiesUnavailable() {
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(null);
mController.onViewAttached();
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
}
@Test
@@ -176,7 +185,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
.thenReturn(true);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
}
@Test
@@ -186,7 +196,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
.thenReturn(false);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false, null);
}
@Test
@@ -211,7 +222,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mZenModeController.getZen()).thenReturn(
Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
}
@Test
@@ -219,7 +231,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mZenModeController.getZen()).thenReturn(
Settings.Global.ZEN_MODE_OFF);
mController.onViewAttached();
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
}
@Test
@@ -250,7 +263,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture());
callbackCapture.getValue().onAvailable(mNetwork);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
}
@Test
@@ -266,7 +281,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture());
callbackCapture.getValue().onLost(mNetwork);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true);
+
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true, null);
}
@Test
@@ -283,7 +300,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
.thenReturn(true);
callbackCapture.getValue().onCapabilitiesChanged(mNetwork, mNetworkCapabilities);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false, null);
}
@Test
@@ -333,7 +352,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
callbackCapture.getValue().onSensorBlockedChanged(
SensorPrivacyManager.Sensors.MICROPHONE, true);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true, null);
}
@Test
@@ -350,7 +370,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
callbackCapture.getValue().onSensorBlockedChanged(
SensorPrivacyManager.Sensors.MICROPHONE, false);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false, null);
}
@Test
@@ -364,7 +385,8 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
verify(mZenModeController).addCallback(callbackCapture.capture());
callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true, null);
}
@Test
@@ -373,12 +395,12 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
.thenReturn(Settings.Global.ZEN_MODE_OFF);
mController.onViewAttached();
-
final ArgumentCaptor<ZenModeController.Callback> callbackCapture =
ArgumentCaptor.forClass(ZenModeController.Callback.class);
verify(mZenModeController).addCallback(callbackCapture.capture());
callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_OFF);
- verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false);
+ verify(mView).showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
index b02c506be8be..86aa14d7a877 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockDateComplicationTest.java
@@ -15,11 +15,16 @@
*/
package com.android.systemui.dreams.complication;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.testing.AndroidTestingRunner;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -32,6 +37,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import javax.inject.Provider;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamClockDateComplicationTest extends SysuiTestCase {
@@ -45,9 +52,28 @@ public class DreamClockDateComplicationTest extends SysuiTestCase {
@Mock
private DreamClockDateComplication mComplication;
+ @Mock
+ private Provider<DreamClockDateComplication.DreamClockDateViewHolder>
+ mDreamClockDateViewHolderProvider;
+
+ @Mock
+ private DreamClockDateComplication.DreamClockDateViewHolder
+ mDreamClockDateViewHolder;
+
+ @Mock
+ private ComplicationViewModel mComplicationViewModel;
+
+ @Mock
+ private View mView;
+
+ @Mock
+ private ComplicationLayoutParams mLayoutParams;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ when(mDreamClockDateViewHolderProvider.get()).thenReturn(mDreamClockDateViewHolder);
+
}
/**
@@ -63,4 +89,40 @@ public class DreamClockDateComplicationTest extends SysuiTestCase {
registrant.start();
verify(mDreamOverlayStateController).addComplication(eq(mComplication));
}
+
+ /**
+ * Verifies {@link DreamClockDateComplication} has the required type.
+ */
+ @Test
+ public void testComplicationRequiredTypeAvailability() {
+ final DreamClockDateComplication complication =
+ new DreamClockDateComplication(mDreamClockDateViewHolderProvider);
+ assertEquals(Complication.COMPLICATION_TYPE_DATE,
+ complication.getRequiredTypeAvailability());
+ }
+
+ /**
+ * Verifies {@link DreamClockDateComplication.DreamClockDateViewHolder} is obtainable from its
+ * provider when the complication creates view.
+ */
+ @Test
+ public void testComplicationViewHolderProviderOnCreateView() {
+ final DreamClockDateComplication complication =
+ new DreamClockDateComplication(mDreamClockDateViewHolderProvider);
+ final Complication.ViewHolder viewHolder = complication.createView(mComplicationViewModel);
+ verify(mDreamClockDateViewHolderProvider).get();
+ assertThat(viewHolder).isEqualTo(mDreamClockDateViewHolder);
+ }
+
+ /**
+ * Verifies {@link DreamClockDateComplication.DreamClockDateViewHolder} has the intended view
+ * and layout parameters from constructor.
+ */
+ @Test
+ public void testComplicationViewHolderContentAccessors() {
+ final DreamClockDateComplication.DreamClockDateViewHolder viewHolder =
+ new DreamClockDateComplication.DreamClockDateViewHolder(mView, mLayoutParams);
+ assertThat(viewHolder.getView()).isEqualTo(mView);
+ assertThat(viewHolder.getLayoutParams()).isEqualTo(mLayoutParams);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
index 088b4d5136ff..314a30b2d14a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java
@@ -15,11 +15,16 @@
*/
package com.android.systemui.dreams.complication;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.testing.AndroidTestingRunner;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -32,6 +37,8 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import javax.inject.Provider;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamClockTimeComplicationTest extends SysuiTestCase {
@@ -45,9 +52,27 @@ public class DreamClockTimeComplicationTest extends SysuiTestCase {
@Mock
private DreamClockTimeComplication mComplication;
+ @Mock
+ private Provider<DreamClockTimeComplication.DreamClockTimeViewHolder>
+ mDreamClockTimeViewHolderProvider;
+
+ @Mock
+ private DreamClockTimeComplication.DreamClockTimeViewHolder
+ mDreamClockTimeViewHolder;
+
+ @Mock
+ private ComplicationViewModel mComplicationViewModel;
+
+ @Mock
+ private View mView;
+
+ @Mock
+ private ComplicationLayoutParams mLayoutParams;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ when(mDreamClockTimeViewHolderProvider.get()).thenReturn(mDreamClockTimeViewHolder);
}
/**
@@ -63,4 +88,40 @@ public class DreamClockTimeComplicationTest extends SysuiTestCase {
registrant.start();
verify(mDreamOverlayStateController).addComplication(eq(mComplication));
}
+
+ /**
+ * Verifies {@link DreamClockTimeComplication} has the required type.
+ */
+ @Test
+ public void testComplicationRequiredTypeAvailability() {
+ final DreamClockTimeComplication complication =
+ new DreamClockTimeComplication(mDreamClockTimeViewHolderProvider);
+ assertEquals(Complication.COMPLICATION_TYPE_TIME,
+ complication.getRequiredTypeAvailability());
+ }
+
+ /**
+ * Verifies {@link DreamClockTimeComplication.DreamClockTimeViewHolder} is obtainable from its
+ * provider when the complication creates view.
+ */
+ @Test
+ public void testComplicationViewHolderProviderOnCreateView() {
+ final DreamClockTimeComplication complication =
+ new DreamClockTimeComplication(mDreamClockTimeViewHolderProvider);
+ final Complication.ViewHolder viewHolder = complication.createView(mComplicationViewModel);
+ verify(mDreamClockTimeViewHolderProvider).get();
+ assertThat(viewHolder).isEqualTo(mDreamClockTimeViewHolder);
+ }
+
+ /**
+ * Verifies {@link DreamClockTimeComplication.DreamClockTimeViewHolder} has the intended view
+ * and layout parameters from constructor.
+ */
+ @Test
+ public void testComplicationViewHolderContentAccessors() {
+ final DreamClockTimeComplication.DreamClockTimeViewHolder viewHolder =
+ new DreamClockTimeComplication.DreamClockTimeViewHolder(mView, mLayoutParams);
+ assertThat(viewHolder.getView()).isEqualTo(mView);
+ assertThat(viewHolder.getLayoutParams()).isEqualTo(mLayoutParams);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index dcbe0ab96dac..daf81bdc6e82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -37,7 +37,6 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import javax.inject.Provider
-import org.mockito.Mockito.`when` as whenever
private val DATA = MediaData(
userId = -1,
@@ -83,7 +82,6 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
mediaCarouselController = MediaCarouselController(
context,
mediaControlPanelFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index cb68d81287df..90eff1ae9804 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -101,7 +101,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory
@Mock private lateinit var mediaCarouselController: MediaCarouselController
@Mock private lateinit var falsingManager: FalsingManager
- @Mock private lateinit var mediaFlags: MediaFlags
private lateinit var appIcon: ImageView
private lateinit var albumView: ImageView
private lateinit var titleText: TextView
@@ -147,7 +146,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
player = MediaControlPanel(context, bgExecutor, activityStarter, broadcastSender,
mediaViewController, seekBarViewModel, Lazy { mediaDataManager },
- mediaOutputDialogFactory, mediaCarouselController, falsingManager, mediaFlags, clock)
+ mediaOutputDialogFactory, mediaCarouselController, falsingManager, clock)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Set up mock views for the players
@@ -215,9 +214,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
device = device,
active = true,
resumeAction = null)
-
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
}
/**
@@ -295,9 +291,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun bindSemanticActionsOldLayout() {
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
-
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
@@ -332,9 +325,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun bindSemanticActionsNewLayout() {
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
-
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
@@ -381,9 +371,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun bindNotificationActionsNewLayout() {
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
- whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
-
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val actions = listOf(
MediaAction(icon, Runnable {}, "previous"),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 925ae30e8773..066f49a16f19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
@@ -167,7 +168,7 @@ class MediaDataManagerTest : SysuiTestCase() {
whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf(mediaRecommendationItem))
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(false)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(false)
}
@After
@@ -594,7 +595,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackActions_noState_usesNotification() {
val desc = "Notification Action"
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
whenever(controller.playbackState).thenReturn(null)
val notifWithAction = SbnBuilder().run {
@@ -621,7 +622,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackActions_hasPrevNext() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY or
PlaybackState.ACTION_SKIP_TO_PREVIOUS or
PlaybackState.ACTION_SKIP_TO_NEXT
@@ -669,7 +670,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackActions_noPrevNext_usesCustom() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4", "custom 5")
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
val stateBuilder = PlaybackState.Builder()
.setActions(stateActions)
@@ -707,7 +708,7 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackActions_reservedSpace() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
- whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
val stateBuilder = PlaybackState.Builder()
.setActions(stateActions)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 8e201b5a3e87..203eb47165e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -223,6 +223,18 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
}
@Test
+ fun calculateTransformationType_onLockSplitShade_goingToFullShade_mediaInvisible_returnsFade() {
+ enableSplitShade()
+ goToLockscreen()
+ expandQS()
+ whenever(lockHost.visible).thenReturn(false)
+ mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ }
+
+ @Test
fun calculateTransformationType_onLockShade_inSplitShade_notExpanding_returnsFade() {
enableSplitShade()
goToLockscreen()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
index 962d78c129f9..b9a69bb8641a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
@@ -192,9 +192,9 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
verify(windowManager, never()).removeView(any())
}
-
+
@Test
- fun displayChip_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
+ fun setIcon_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -204,7 +204,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
+ fun setIcon_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -226,7 +226,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_hasAppIconDrawable_iconIsDrawable() {
+ fun setIcon_hasAppIconDrawable_iconIsDrawable() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -237,7 +237,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_nullAppNameAndNullPackageName_stillHasContentDescription() {
+ fun setIcon_nullAppNameAndNullPackageName_stillHasContentDescription() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -247,7 +247,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
+ fun setIcon_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -259,7 +259,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_nullAppName_iconContentDescriptionIsFromPackageName() {
+ fun setIcon_nullAppName_iconContentDescriptionIsFromPackageName() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -269,7 +269,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
- fun displayChip_hasAppName_iconContentDescriptionIsAppNameOverride() {
+ fun setIcon_hasAppName_iconContentDescriptionIsAppNameOverride() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
@@ -280,6 +280,21 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
}
@Test
+ fun setIcon_iconSizeMatchesGetIconSize() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(chipView, PACKAGE_NAME)
+ chipView.measure(
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ )
+
+ assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
+ assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
+ }
+
+ @Test
fun tapGestureDetected_outsideViewBounds_viewHidden() {
controllerCommon.displayChip(getState())
whenever(viewUtil.touchIsWithinView(any(), any(), any())).thenReturn(false)
@@ -344,6 +359,8 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
override fun updateChipView(chipInfo: ChipInfo, currentChipView: ViewGroup) {
}
+
+ override fun getIconSize(isAppIcon: Boolean): Int? = ICON_SIZE
}
inner class ChipInfo : ChipInfoCommon {
@@ -354,3 +371,4 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
private const val PACKAGE_NAME = "com.android.systemui"
private const val APP_NAME = "Fake App Name"
private const val TIMEOUT_MS = 10000L
+private const val ICON_SIZE = 47 \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index 355d3fe4b8d1..067607f9b8ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -174,12 +174,47 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
verify(logger).logStateChange(any(), any())
}
+ @Test
+ fun setIcon_isAppIcon_usesAppIconSize() {
+ controllerReceiver.displayChip(getChipReceiverInfo())
+ val chipView = getChipView()
+
+ controllerReceiver.setIcon(chipView, PACKAGE_NAME)
+ chipView.measure(
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ )
+
+ val expectedSize = controllerReceiver.getIconSize(isAppIcon = true)
+ assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
+ assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
+ }
+
+ @Test
+ fun setIcon_notAppIcon_usesGenericIconSize() {
+ controllerReceiver.displayChip(getChipReceiverInfo())
+ val chipView = getChipView()
+
+ controllerReceiver.setIcon(chipView, appPackageName = null)
+ chipView.measure(
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ )
+
+ val expectedSize = controllerReceiver.getIconSize(isAppIcon = false)
+ assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
+ assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
+ }
+
private fun getChipView(): ViewGroup {
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
verify(windowManager).addView(viewCaptor.capture(), any())
return viewCaptor.value as ViewGroup
}
+ private fun getChipReceiverInfo(): ChipReceiverInfo =
+ ChipReceiverInfo(routeInfo, null, null)
+
private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
index 350822691121..38b448fb362c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
@@ -19,8 +19,11 @@ package com.android.systemui.privacy
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
+import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ResolveInfoFlags
+import android.content.pm.ResolveInfo
import android.content.pm.UserInfo
import android.os.Process.SYSTEM_UID
import android.os.UserHandle
@@ -648,6 +651,77 @@ class PrivacyDialogControllerTest : SysuiTestCase() {
}
}
+ @Test
+ fun testCorrectIntentSubAttribution() {
+ val usage = createMockPermGroupUsage(
+ attributionTag = TEST_ATTRIBUTION_TAG,
+ attributionLabel = "TEST_LABEL"
+ )
+
+ val activityInfo = createMockActivityInfo()
+ val resolveInfo = createMockResolveInfo(activityInfo)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+ .thenAnswer { resolveInfo }
+ controller.showDialog(context)
+ exhaustExecutors()
+
+ dialogProvider.list?.let { list ->
+ val navigationIntent = list.get(0).navigationIntent!!
+ assertThat(navigationIntent.action).isEqualTo(Intent.ACTION_MANAGE_PERMISSION_USAGE)
+ assertThat(navigationIntent.getStringExtra(Intent.EXTRA_PERMISSION_GROUP_NAME))
+ .isEqualTo(PERM_CAMERA)
+ assertThat(navigationIntent.getStringArrayExtra(Intent.EXTRA_ATTRIBUTION_TAGS))
+ .isEqualTo(arrayOf(TEST_ATTRIBUTION_TAG.toString()))
+ assertThat(navigationIntent.getBooleanExtra(Intent.EXTRA_SHOWING_ATTRIBUTION, false))
+ .isTrue()
+ }
+ }
+
+ @Test
+ fun testDefaultIntentOnMissingAttributionLabel() {
+ val usage = createMockPermGroupUsage(
+ attributionTag = TEST_ATTRIBUTION_TAG
+ )
+
+ val activityInfo = createMockActivityInfo()
+ val resolveInfo = createMockResolveInfo(activityInfo)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+ .thenAnswer { resolveInfo }
+ controller.showDialog(context)
+ exhaustExecutors()
+
+ dialogProvider.list?.let { list ->
+ assertThat(isIntentEqual(list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
+ .isTrue()
+ }
+ }
+
+ @Test
+ fun testDefaultIntentOnIncorrectPermission() {
+ val usage = createMockPermGroupUsage(
+ attributionTag = TEST_ATTRIBUTION_TAG
+ )
+
+ val activityInfo = createMockActivityInfo(
+ permission = "INCORRECT_PERMISSION"
+ )
+ val resolveInfo = createMockResolveInfo(activityInfo)
+ `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage))
+ `when`(packageManager.resolveActivity(any(), any<ResolveInfoFlags>()))
+ .thenAnswer { resolveInfo }
+ controller.showDialog(context)
+ exhaustExecutors()
+
+ dialogProvider.list?.let { list ->
+ assertThat(isIntentEqual(list.get(0).navigationIntent!!,
+ controller.getDefaultManageAppPermissionsIntent(TEST_PACKAGE_NAME, USER_ID)))
+ .isTrue()
+ }
+ }
+
private fun exhaustExecutors() {
FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor)
}
@@ -680,6 +754,24 @@ class PrivacyDialogControllerTest : SysuiTestCase() {
return user * UserHandle.PER_USER_RANGE + nextUid++
}
+ private fun createMockResolveInfo(
+ activityInfo: ActivityInfo? = null
+ ): ResolveInfo {
+ val resolveInfo = mock(ResolveInfo::class.java)
+ resolveInfo.activityInfo = activityInfo
+ return resolveInfo
+ }
+
+ private fun createMockActivityInfo(
+ permission: String = android.Manifest.permission.START_VIEW_PERMISSION_USAGE,
+ className: String = "TEST_CLASS_NAME"
+ ): ActivityInfo {
+ val activityInfo = mock(ActivityInfo::class.java)
+ activityInfo.permission = permission
+ activityInfo.name = className
+ return activityInfo
+ }
+
private fun createMockPermGroupUsage(
packageName: String = TEST_PACKAGE_NAME,
uid: Int = generateUidForUser(USER_ID),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
index d3bb241baad4..f306fd601136 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
@@ -4,14 +4,19 @@ import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.graphics.drawable.Drawable;
import android.testing.AndroidTestingRunner;
import android.testing.TestableResources;
@@ -30,6 +35,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -40,6 +46,7 @@ import java.util.List;
@RunWith(AndroidTestingRunner.class)
public class InternetAdapterTest extends SysuiTestCase {
+ private static final String WIFI_KEY = "Wi-Fi_Key";
private static final String WIFI_TITLE = "Wi-Fi Title";
private static final String WIFI_SUMMARY = "Wi-Fi Summary";
private static final int GEAR_ICON_RES_ID = R.drawable.ic_settings_24dp;
@@ -47,6 +54,8 @@ public class InternetAdapterTest extends SysuiTestCase {
@Rule
public MockitoRule mRule = MockitoJUnit.rule();
+ @Spy
+ private Context mSpyContext = mContext;
@Mock
private WifiEntry mInternetWifiEntry;
@@ -74,6 +83,7 @@ public class InternetAdapterTest extends SysuiTestCase {
when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
+ when(mWifiEntry.getKey()).thenReturn(WIFI_KEY);
when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
@@ -197,6 +207,66 @@ public class InternetAdapterTest extends SysuiTestCase {
}
@Test
+ public void viewHolderShouldEnabled_wifiCanConnect_returnTrue() {
+ when(mWifiEntry.canConnect()).thenReturn(true);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+ }
+
+ @Test
+ public void viewHolderShouldEnabled_wifiCanNotConnect_returnFalse() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isFalse();
+ }
+
+ @Test
+ public void viewHolderShouldEnabled_wifiCanNotConnectButCanDisconnect_returnTrue() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+ when(mWifiEntry.canConnect()).thenReturn(true);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+ }
+
+ @Test
+ public void viewHolderShouldEnabled_wifiCanNotConnectButIsSaved_returnTrue() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+ when(mWifiEntry.isSaved()).thenReturn(true);
+
+ assertThat(mViewHolder.shouldEnabled(mWifiEntry)).isTrue();
+ }
+
+ @Test
+ public void viewHolderOnWifiClick_wifiShouldEditBeforeConnect_startActivity() {
+ when(mWifiEntry.shouldEditBeforeConnect()).thenReturn(true);
+ mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mSpyContext), 0);
+ doNothing().when(mSpyContext).startActivity(any());
+
+ mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+ verify(mSpyContext).startActivity(any());
+ }
+
+ @Test
+ public void viewHolderOnWifiClick_wifiCanConnect_connectWifi() {
+ when(mWifiEntry.canConnect()).thenReturn(true);
+
+ mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+ verify(mInternetDialogController).connect(mWifiEntry);
+ }
+
+ @Test
+ public void viewHolderOnWifiClick_wifiCanNotConnectButIsSaved_launchWifiDetailsSetting() {
+ when(mWifiEntry.canConnect()).thenReturn(false);
+ when(mWifiEntry.isSaved()).thenReturn(true);
+
+ mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
+
+ verify(mInternetDialogController).launchWifiDetailsSetting(anyString(), any());
+ }
+
+ @Test
public void viewHolderUpdateEndIcon_wifiConnected_updateGearIcon() {
mTestableResources.addOverride(GEAR_ICON_RES_ID, mGearIcon);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index a2959e2fb917..633a9c3a03d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -385,18 +385,16 @@ public class InternetDialogControllerTest extends SysuiTestCase {
}
@Test
- public void launchWifiNetworkDetailsSetting_withNoWifiEntryKey_doNothing() {
- mInternetDialogController.launchWifiNetworkDetailsSetting(null /* key */,
- mDialogLaunchView);
+ public void launchWifiDetailsSetting_withNoWifiEntryKey_doNothing() {
+ mInternetDialogController.launchWifiDetailsSetting(null /* key */, mDialogLaunchView);
verify(mActivityStarter, never())
.postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
}
@Test
- public void launchWifiNetworkDetailsSetting_withWifiEntryKey_startActivity() {
- mInternetDialogController.launchWifiNetworkDetailsSetting("wifi_entry_key",
- mDialogLaunchView);
+ public void launchWifiDetailsSetting_withWifiEntryKey_startActivity() {
+ mInternetDialogController.launchWifiDetailsSetting("wifi_entry_key", mDialogLaunchView);
verify(mActivityStarter).postStartActivityDismissingKeyguard(any(Intent.class), anyInt(),
any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 64a0a2342a44..1d2a0ca3777a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.statusbar
+import org.mockito.Mockito.`when` as whenever
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -18,11 +19,11 @@ import com.android.systemui.statusbar.notification.row.NotificationTestHelper
import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
import com.android.systemui.statusbar.phone.NotificationPanelViewController
import com.android.systemui.statusbar.phone.ScrimController
-import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.statusbar.policy.FakeConfigurationController
import org.junit.After
import org.junit.Assert.assertFalse
@@ -37,14 +38,13 @@ import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyFloat
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
+import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
-import org.mockito.Mockito.`when` as whenever
-import org.mockito.ArgumentMatchers.eq
private fun <T> anyObject(): T {
return Mockito.anyObject<T>()
@@ -231,7 +231,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
transitionController.dragDownAmount = 10f
verify(nsslController, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(mediaHierarchyManager, never()).setTransitionToFullShadeAmount(anyFloat())
- verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat())
+ verify(scrimController, never()).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController, never()).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
verify(qS, never()).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
@@ -242,7 +242,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
transitionController.dragDownAmount = 10f
verify(nsslController).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(mediaHierarchyManager).setTransitionToFullShadeAmount(anyFloat())
- verify(scrimController).setTransitionToFullShadeProgress(anyFloat())
+ verify(scrimController).setTransitionToFullShadeProgress(anyFloat(), anyFloat())
verify(notificationPanelController).setTransitionToFullShadeAmount(anyFloat(),
anyBoolean(), anyLong())
verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
@@ -311,6 +311,75 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
}
@Test
+ fun setDragAmount_setsScrimProgressBasedOnScrimDistance() {
+ val distance = 10
+ context.orCreateTestableResources
+ .addOverride(R.dimen.lockscreen_shade_scrim_transition_distance, distance)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 5f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = eq(0.5f),
+ lockScreenNotificationsProgress = anyFloat()
+ )
+ }
+
+ @Test
+ fun setDragAmount_setsNotificationsScrimProgressBasedOnNotificationsScrimDistanceAndDelay() {
+ val distance = 100
+ val delay = 10
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 20f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(0.1f)
+ )
+ }
+
+ @Test
+ fun setDragAmount_dragAmountLessThanNotifDelayDistance_setsNotificationsScrimProgressToZero() {
+ val distance = 100
+ val delay = 50
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 20f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(0f)
+ )
+ }
+
+ @Test
+ fun setDragAmount_dragAmountMoreThanTotalDistance_setsNotificationsScrimProgressToOne() {
+ val distance = 100
+ val delay = 50
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_distance, distance)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.lockscreen_shade_notifications_scrim_transition_delay, delay)
+ configurationController.notifyConfigurationChanged()
+
+ transitionController.dragDownAmount = 999999f
+
+ verify(scrimController).transitionToFullShadeProgress(
+ progress = anyFloat(),
+ lockScreenNotificationsProgress = eq(1f)
+ )
+ }
+
+ @Test
fun setDragDownAmount_inSplitShade_setsValueOnMediaHierarchyManager() {
enableSplitShade()
@@ -328,9 +397,21 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
}
private fun setSplitShadeEnabled(enabled: Boolean) {
- context.getOrCreateTestableResources().addOverride(
- R.bool.config_use_split_notification_shade, enabled
- )
+ overrideResource(R.bool.config_use_split_notification_shade, enabled)
configurationController.notifyConfigurationChanged()
}
+
+ /**
+ * Wrapper around [ScrimController.transitionToFullShadeProgress] that has named parameters for
+ * clarify and easier refactoring of parameter names.
+ */
+ private fun ScrimController.transitionToFullShadeProgress(
+ progress: Float,
+ lockScreenNotificationsProgress: Float
+ ) {
+ scrimController.setTransitionToFullShadeProgress(
+ progress,
+ lockScreenNotificationsProgress
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 7fc5ece670d4..251ac7d250fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -41,6 +41,7 @@ import android.testing.TestableLooper;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.R;
@@ -87,6 +88,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -252,13 +254,17 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
.thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
new ExpandableNotificationRowController(
viewCaptor.getValue(),
- mListContainer,
- mock(RemoteInputViewSubcomponent.Factory.class),
mock(ActivatableNotificationViewController.class),
+ mock(RemoteInputViewSubcomponent.Factory.class),
+ mock(MetricsLogger.class),
+ mListContainer,
mNotificationMediaManager,
+ mock(SmartReplyConstants.class),
+ mock(SmartReplyController.class),
mock(PluginManager.class),
new FakeSystemClock(),
- "FOOBAR", "FOOBAR",
+ "FOOBAR",
+ "FOOBAR",
mKeyguardBypassController,
mGroupMembershipManager,
mGroupExpansionManager,
@@ -275,8 +281,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
mock(FeatureFlags.class),
mPeopleNotificationIdentifier,
Optional.of(mock(BubblesManager.class)),
- mock(ExpandableNotificationRowDragController.class)
- ));
+ mock(ExpandableNotificationRowDragController.class)));
when(mNotificationRowComponentBuilder.activatableNotificationView(any()))
.thenReturn(mNotificationRowComponentBuilder);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 72f8f70058fc..1ecb09bc8514 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -44,6 +44,7 @@ import android.text.TextUtils;
import android.view.LayoutInflater;
import android.widget.RemoteViews;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.TestableDependency;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -54,6 +55,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -73,6 +75,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.SmartReplyStateInflater;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.tests.R;
@@ -505,7 +508,10 @@ public class NotificationTestHelper {
mPeopleNotificationIdentifier,
mOnUserInteractionCallback,
Optional.of(mock(BubblesManager.class)),
- mock(NotificationGutsManager.class));
+ mock(NotificationGutsManager.class),
+ mock(MetricsLogger.class),
+ mock(SmartReplyConstants.class),
+ mock(SmartReplyController.class));
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index bf16e0ab39c6..c9de60806b66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -134,6 +134,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
@Mock private InteractionJankMonitor mJankMonitor;
@Mock private StackStateLogger mStackLogger;
@Mock private NotificationStackScrollLogger mLogger;
+ @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -186,7 +187,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mShadeController,
mJankMonitor,
mStackLogger,
- mLogger
+ mLogger,
+ mNotificationStackSizeCalculator
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
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 56541f3ceb6f..7a92b96f40db 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
@@ -103,6 +103,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
@Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Mock private NotificationShelf mNotificationShelf;
+ @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
@Before
@UiThreadTest
@@ -138,7 +139,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
// holds a copy of the CUT's instances of these KeyguardBypassController, so they still
// refer to the CUT's member variables, not the spy's member variables.
mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null);
- mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper);
+ mStackScrollerInternal.initView(getContext(), mNotificationSwipeHelper,
+ mNotificationStackSizeCalculator);
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setCentralSurfaces(mCentralSurfaces);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
new file mode 100644
index 000000000000..d1848e38ca06
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
@@ -0,0 +1,266 @@
+/*
+ * 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.statusbar.notification.stack
+
+import android.service.notification.StatusBarNotification
+import android.testing.AndroidTestingRunner
+import android.view.View.VISIBLE
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.nullable
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotificationStackSizeCalculatorTest : SysuiTestCase() {
+
+ @Mock private lateinit var groupManager: NotificationGroupManagerLegacy
+
+ @Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
+
+ @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
+
+ @Mock private lateinit var stackLayout: NotificationStackScrollLayout
+
+ private val testableResources = mContext.getOrCreateTestableResources()
+
+ private lateinit var sizeCalculator: NotificationStackSizeCalculator
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(stackLayout.calculateGapHeight(nullable(), nullable(), any()))
+ .thenReturn(GAP_HEIGHT)
+ whenever(groupManager.isSummaryOfSuppressedGroup(any())).thenReturn(false)
+ with(testableResources) {
+ addOverride(R.integer.keyguard_max_notification_count, -1)
+ addOverride(R.dimen.notification_divider_height, NOTIFICATION_PADDING.toInt())
+ }
+
+ sizeCalculator =
+ NotificationStackSizeCalculator(
+ groupManager = groupManager,
+ lockscreenUserManager = notificationLockscreenUserManager,
+ statusBarStateController = sysuiStatusBarStateController,
+ testableResources.resources)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_zeroSpace_returnZero() {
+ val rows = listOf(createMockRow(height = ROW_HEIGHT, visibleOnLockscreen = true))
+
+ val maxNotifications =
+ computeMaxKeyguardNotifications(rows, availableSpace = 0f, shelfHeight = 0f)
+
+ assertThat(maxNotifications).isEqualTo(0)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_infiniteSpace_returnsAll() {
+ val numberOfRows = 30
+ val rows = createLockscreenRows(numberOfRows)
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, Float.MAX_VALUE)
+
+ assertThat(maxNotifications).isEqualTo(numberOfRows)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_spaceForOne_returnsOne() {
+ val rowHeight = ROW_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+ val shelfHeight =
+ totalSpaceForEachRow / 2 // In this way shelf absence will not leave room for another.
+ val spaceForOne = totalSpaceForEachRow
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications =
+ computeMaxKeyguardNotifications(
+ rows, availableSpace = spaceForOne, shelfHeight = shelfHeight)
+
+ assertThat(maxNotifications).isEqualTo(1)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_spaceForOne_shelfUsableForLastNotification_returnsTwo() {
+ val rowHeight = ROW_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+ val shelfHeight = totalSpaceForEachRow + NOTIFICATION_PADDING
+ val spaceForOne = totalSpaceForEachRow
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications =
+ computeMaxKeyguardNotifications(
+ rows, availableSpace = spaceForOne, shelfHeight = shelfHeight)
+
+ assertThat(maxNotifications).isEqualTo(1)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_invisibleOnLockscreen_returnsZero() {
+ val rows = listOf(createMockRow(visibleOnLockscreen = false))
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, Float.MAX_VALUE)
+
+ assertThat(maxNotifications).isEqualTo(0)
+ }
+
+ @Test
+ fun computeMaxKeyguardNotifications_spaceForTwo_returnsTwo() {
+ val rowHeight = ROW_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight
+ val spaceForTwo = totalSpaceForEachRow * 2 + NOTIFICATION_PADDING
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, spaceForTwo, shelfHeight = 0f)
+
+ assertThat(maxNotifications).isEqualTo(2)
+ }
+
+ @Test
+ fun computeHeight_returnsLessThanAvailableSpaceUsedToCalculateMaxNotifications() {
+ val rowHeight = ROW_HEIGHT
+ val shelfHeight = SHELF_HEIGHT
+ val totalSpaceForEachRow = GAP_HEIGHT + rowHeight + NOTIFICATION_PADDING
+ val availableSpace = totalSpaceForEachRow * 2
+ val rows =
+ listOf(
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true),
+ createMockRow(rowHeight, visibleOnLockscreen = true))
+
+ val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
+ assertThat(maxNotifications).isEqualTo(2)
+
+ val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, SHELF_HEIGHT)
+ assertThat(height).isAtMost(availableSpace + SHELF_HEIGHT)
+ }
+
+ @Test
+ fun computeHeight_allInvisibleToLockscreen_NotInLockscreen_returnsHigherThanZero() {
+ setOnLockscreen(false)
+ val rowHeight = 10f
+ setupChildren(listOf(createMockRow(rowHeight, visibleOnLockscreen = false)))
+
+ val height =
+ sizeCalculator.computeHeight(
+ stackLayout, maxNotifications = Int.MAX_VALUE, SHELF_HEIGHT)
+
+ assertThat(height).isGreaterThan(rowHeight)
+ }
+
+ @Test
+ fun computeHeight_allInvisibleToLockscreen_onLockscreen_returnsZero() {
+ setOnLockscreen(true)
+ setupChildren(listOf(createMockRow(visibleOnLockscreen = false)))
+
+ val height =
+ sizeCalculator.computeHeight(
+ stackLayout, maxNotifications = Int.MAX_VALUE, SHELF_HEIGHT)
+
+ assertThat(height).isEqualTo(0)
+ }
+
+ private fun computeMaxKeyguardNotifications(
+ rows: List<ExpandableView>,
+ availableSpace: Float,
+ shelfHeight: Float = SHELF_HEIGHT
+ ): Int {
+ setupChildren(rows)
+ return sizeCalculator.computeMaxKeyguardNotifications(
+ stackLayout, availableSpace, shelfHeight)
+ }
+
+ private fun setupChildren(children: List<ExpandableView>) {
+ whenever(stackLayout.getChildAt(any())).thenAnswer { invocation ->
+ val inx = invocation.getArgument<Int>(0)
+ return@thenAnswer children[inx]
+ }
+ whenever(stackLayout.childCount).thenReturn(children.size)
+ }
+
+ private fun createLockscreenRows(number: Int): List<ExpandableNotificationRow> =
+ (1..number).map { createMockRow(visibleOnLockscreen = true) }.toList()
+
+ private fun createMockRow(
+ height: Float = ROW_HEIGHT,
+ visibleOnLockscreen: Boolean = true,
+ isRemoved: Boolean = false,
+ visibility: Int = VISIBLE,
+ summaryOfSuppressed: Boolean = false
+ ): ExpandableNotificationRow {
+ val row = mock(ExpandableNotificationRow::class.java)
+ val entry = mock(NotificationEntry::class.java)
+ val sbn = mock(StatusBarNotification::class.java)
+ whenever(entry.sbn).thenReturn(sbn)
+ whenever(row.entry).thenReturn(entry)
+ whenever(row.isRemoved).thenReturn(isRemoved)
+ whenever(row.visibility).thenReturn(visibility)
+ whenever(notificationLockscreenUserManager.shouldShowOnKeyguard(entry))
+ .thenReturn(visibleOnLockscreen)
+ whenever(groupManager.isSummaryOfSuppressedGroup(sbn)).thenReturn(summaryOfSuppressed)
+ whenever(row.getMinHeight(any())).thenReturn(height.toInt())
+ whenever(row.intrinsicHeight).thenReturn(height.toInt())
+ return row
+ }
+
+ private fun setOnLockscreen(onLockscreen: Boolean) {
+ whenever(sysuiStatusBarStateController.state)
+ .thenReturn(
+ if (onLockscreen) {
+ KEYGUARD
+ } else {
+ SHADE
+ })
+ }
+
+ /** Default dimensions for tests that don't overwrite them. */
+ companion object {
+ const val GAP_HEIGHT = 12f
+ const val NOTIFICATION_PADDING = 3f
+ const val SHELF_HEIGHT = 14f
+ const val ROW_HEIGHT = SHELF_HEIGHT * 3
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 4bac08ea536b..06b20380c0ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -104,7 +104,6 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -119,12 +118,12 @@ import com.android.systemui.statusbar.notification.ConversationNotificationManag
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
@@ -174,8 +173,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private NotificationShelfController mNotificationShelfController;
@Mock
- private NotificationGroupManagerLegacy mGroupManager;
- @Mock
private KeyguardStatusBarView mKeyguardStatusBar;
@Mock
private KeyguardUserSwitcherView mUserSwitcherView;
@@ -200,10 +197,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private DynamicPrivacyController mDynamicPrivacyController;
@Mock
- private ShadeController mShadeController;
- @Mock
- private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
- @Mock
private NotificationEntryManager mNotificationEntryManager;
@Mock
private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@@ -336,6 +329,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private SysUiState mSysUiState;
@Mock
private NotificationListContainer mNotificationListContainer;
+ @Mock
+ private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
@@ -466,7 +461,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mFeatureFlags,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, new FalsingCollectorFake(),
- mNotificationLockscreenUserManager, mNotificationEntryManager,
+ mNotificationEntryManager,
mKeyguardStateController,
mStatusBarStateController,
mStatusBarWindowStateController,
@@ -484,7 +479,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mKeyguardUserSwitcherComponentFactory,
mKeyguardStatusBarViewComponentFactory,
mLockscreenShadeTransitionController,
- mGroupManager,
mNotificationAreaController,
mAuthController,
mScrimController,
@@ -516,7 +510,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mSysUiState,
mKeyguardUnlockAnimationController,
mNotificationListContainer,
- mPanelEventsEmitter);
+ mPanelEventsEmitter,
+ mNotificationStackSizeCalculator);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
() -> {},
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
index 83eabb667997..6526fabefe49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
@@ -6,7 +6,6 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowManagerPolicyConstants
-import androidx.annotation.AnyRes
import androidx.annotation.IdRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
@@ -104,10 +103,6 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
windowInsetsCallback = windowInsetsCallbackCaptor.value
}
- private fun overrideResource(@AnyRes id: Int, value: Any) {
- mContext.orCreateTestableResources.addOverride(id, value)
- }
-
@Test
fun testTaskbarVisibleInSplitShade() {
enableSplitShade()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 0b25467d20d8..786a8586ea39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.statusbar.phone.ScrimController.KEYGUARD_SCRIM_ALPHA;
import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
@@ -1263,19 +1262,36 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimController.setClipsQsScrim(true);
float progress = 0.5f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ float lsNotifProgress = 0.3f;
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
progress = 0.0f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
progress = 1.0f;
- mScrimController.setTransitionToFullShadeProgress(progress);
+ mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
assertEquals(MathUtils.lerp(keyguardAlpha, shadeLockedAlpha, progress),
mNotificationsScrim.getViewAlpha(), 0.2);
}
+ @Test
+ public void notificationTransparency_followsNotificationScrimProgress() {
+ mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
+ finishAnimationsImmediately();
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.setRawPanelExpansionFraction(1.0f);
+ finishAnimationsImmediately();
+
+ float progress = 0.5f;
+ float notifProgress = 0.3f;
+ mScrimController.setTransitionToFullShadeProgress(progress, notifProgress);
+
+ assertThat(mNotificationsScrim.getViewAlpha()).isEqualTo(notifProgress);
+ }
+
private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
mScrimController.setRawPanelExpansionFraction(expansion);
finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index d48ce8c6803e..fa867e2796f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -447,4 +447,15 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
controllerCaptor.getValue().onIntentStarted(false);
verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
}
+
+ @Test
+ public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse_noAnimate() {
+ NotifActivityLaunchEvents.Listener listener =
+ mock(NotifActivityLaunchEvents.Listener.class);
+ mLaunchEventsEmitter.registerListener(listener);
+ when(mCentralSurfaces.shouldAnimateLaunch(anyBoolean())).thenReturn(false);
+ mNotificationActivityStarter
+ .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+ verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
+ }
}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 3f712dd1492f..3801c2473c11 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -2260,10 +2260,12 @@ message MetricsEvent {
ACCOUNTS_WORK_PROFILE_SETTINGS = 401;
// Settings -> Dev options -> Convert to file encryption
- CONVERT_FBE = 402;
+ // DEPRECATED: this setting was removed in Android T.
+ CONVERT_FBE = 402 [deprecated=true];
// Settings -> Dev options -> Convert to file encryption -> WIPE AND CONVERT...
- CONVERT_FBE_CONFIRM = 403;
+ // DEPRECATED: this setting was removed in Android T.
+ CONVERT_FBE_CONFIRM = 403 [deprecated=true];
// Settings -> Dev options -> Running services
RUNNING_SERVICES = 404;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 249ee16afaae..61e3da8aae51 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -322,28 +322,28 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
@Override
public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
boolean enabled) {
- mService.setImeSessionEnabled(sessions, enabled);
+ mService.scheduleSetImeSessionEnabled(sessions, enabled);
}
@Override
public void unbindInput() {
- mService.unbindInput();
+ mService.scheduleUnbindInput();
}
@Override
public void bindInput(InputBinding binding) {
- mService.bindInput(binding);
+ mService.scheduleBindInput(binding);
}
@Override
public void createImeSession(ArraySet<Integer> ignoreSet) {
- mService.createImeSession(ignoreSet);
+ mService.scheduleCreateImeSession(ignoreSet);
}
@Override
public void startInput(IBinder startInputToken, IInputContext inputContext,
EditorInfo editorInfo, boolean restarting) {
- mService.startInput(startInputToken, inputContext, editorInfo, restarting);
+ mService.scheduleStartInput(startInputToken, inputContext, editorInfo, restarting);
}
}
@@ -4377,12 +4377,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*
* @param binding Information given to an accessibility service about a client connecting to it.
*/
- public void bindInput(InputBinding binding) {
- AccessibilityUserState userState;
+ public void scheduleBindInput(InputBinding binding) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::bindInput, this,
+ binding));
+ }
+
+ private void bindInput(InputBinding binding) {
synchronized (mLock) {
// Keep records of these in case new Accessibility Services are enabled.
mInputBinding = binding;
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.requestImeApis()) {
@@ -4395,11 +4399,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
/**
* Unbind input for accessibility services which request ime capabilities.
*/
- public void unbindInput() {
- AccessibilityUserState userState;
- // TODO(b/218182733): Resolve the Imf lock and mLock possible deadlock
+ public void scheduleUnbindInput() {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::unbindInput, this));
+ }
+
+ private void unbindInput() {
synchronized (mLock) {
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.requestImeApis()) {
@@ -4412,16 +4418,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
/**
* Start input for accessibility services which request ime capabilities.
*/
- public void startInput(IBinder startInputToken, IInputContext inputContext,
+ public void scheduleStartInput(IBinder startInputToken, IInputContext inputContext,
+ EditorInfo editorInfo, boolean restarting) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::startInput, this,
+ startInputToken, inputContext, editorInfo, restarting));
+ }
+
+ private void startInput(IBinder startInputToken, IInputContext inputContext,
EditorInfo editorInfo, boolean restarting) {
- AccessibilityUserState userState;
synchronized (mLock) {
// Keep records of these in case new Accessibility Services are enabled.
mStartInputToken = startInputToken;
mInputContext = inputContext;
mEditorInfo = editorInfo;
mRestarting = restarting;
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (service.requestImeApis()) {
@@ -4435,11 +4446,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* Request input sessions from all accessibility services which request ime capabilities and
* whose id is not in the ignoreSet
*/
- public void createImeSession(ArraySet<Integer> ignoreSet) {
- AccessibilityUserState userState;
+ public void scheduleCreateImeSession(ArraySet<Integer> ignoreSet) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::createImeSession,
+ this, ignoreSet));
+ }
+
+ private void createImeSession(ArraySet<Integer> ignoreSet) {
synchronized (mLock) {
mInputSessionRequested = true;
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if ((!ignoreSet.contains(service.mId)) && service.requestImeApis()) {
@@ -4455,10 +4470,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* @param sessions Sessions to enable or disable.
* @param enabled True if enable the sessions or false if disable the sessions.
*/
- public void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
- AccessibilityUserState userState;
+ public void scheduleSetImeSessionEnabled(SparseArray<IInputMethodSession> sessions,
+ boolean enabled) {
+ mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::setImeSessionEnabled,
+ this, sessions, enabled));
+ }
+
+ private void setImeSessionEnabled(SparseArray<IInputMethodSession> sessions, boolean enabled) {
synchronized (mLock) {
- userState = getCurrentUserStateLocked();
+ AccessibilityUserState userState = getCurrentUserStateLocked();
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
final AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (sessions.contains(service.mId) && service.requestImeApis()) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index fa32452f389e..ecc45eb743c6 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -18,6 +18,7 @@ package com.android.server.accessibility.magnification;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL;
import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_FULLSCREEN;
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID;
@@ -31,15 +32,20 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.CompatibilityInfo;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.DisplayManagerInternal;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.MathUtils;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.Display;
+import android.view.DisplayInfo;
import android.view.MagnificationSpec;
import android.view.View;
import android.view.accessibility.MagnificationAnimationCallback;
@@ -93,6 +99,8 @@ public class FullScreenMagnificationController implements
// Whether the following typing focus feature for magnification is enabled.
private boolean mMagnificationFollowTypingEnabled = true;
+ private final DisplayManagerInternal mDisplayManagerInternal;
+
/**
* This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds
* magnification information per display.
@@ -395,6 +403,18 @@ public class FullScreenMagnificationController implements
outRegion.set(mMagnificationRegion);
}
+ private DisplayMetrics getDisplayMetricsForId() {
+ final DisplayMetrics outMetrics = new DisplayMetrics();
+ final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+ if (displayInfo != null) {
+ displayInfo.getLogicalMetrics(outMetrics,
+ CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+ } else {
+ outMetrics.setToDefaults();
+ }
+ return outMetrics;
+ }
+
void requestRectangleOnScreen(int left, int top, int right, int bottom) {
synchronized (mLock) {
final Rect magnifiedFrame = mTempRect;
@@ -408,6 +428,12 @@ public class FullScreenMagnificationController implements
final float scrollX;
final float scrollY;
+ // We offset an additional distance for a user to know the surrounding context.
+ DisplayMetrics metrics = getDisplayMetricsForId();
+ final float offsetViewportX = (float) magnifFrameInScreenCoords.width() / 4;
+ final float offsetViewportY =
+ TypedValue.applyDimension(COMPLEX_UNIT_DIP, 10, metrics);
+
if (right - left > magnifFrameInScreenCoords.width()) {
final int direction = TextUtils
.getLayoutDirectionFromLocale(Locale.getDefault());
@@ -417,9 +443,9 @@ public class FullScreenMagnificationController implements
scrollX = right - magnifFrameInScreenCoords.right;
}
} else if (left < magnifFrameInScreenCoords.left) {
- scrollX = left - magnifFrameInScreenCoords.left;
+ scrollX = left - magnifFrameInScreenCoords.left - offsetViewportX;
} else if (right > magnifFrameInScreenCoords.right) {
- scrollX = right - magnifFrameInScreenCoords.right;
+ scrollX = right - magnifFrameInScreenCoords.right + offsetViewportX;
} else {
scrollX = 0;
}
@@ -427,9 +453,9 @@ public class FullScreenMagnificationController implements
if (bottom - top > magnifFrameInScreenCoords.height()) {
scrollY = top - magnifFrameInScreenCoords.top;
} else if (top < magnifFrameInScreenCoords.top) {
- scrollY = top - magnifFrameInScreenCoords.top;
+ scrollY = top - magnifFrameInScreenCoords.top - offsetViewportY;
} else if (bottom > magnifFrameInScreenCoords.bottom) {
- scrollY = bottom - magnifFrameInScreenCoords.bottom;
+ scrollY = bottom - magnifFrameInScreenCoords.bottom + offsetViewportY;
} else {
scrollY = 0;
}
@@ -687,6 +713,7 @@ public class FullScreenMagnificationController implements
mScreenStateObserver = new ScreenStateObserver(mControllerCtx.getContext(), this);
mMagnificationInfoChangedCallback = magnificationInfoChangedCallback;
mScaleProvider = scaleProvider;
+ mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
}
/**
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index bf8b18ce3157..7a5fa628f645 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -51,6 +51,7 @@ import android.os.Parcel;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
+import android.util.Log;
import android.util.PackageUtils;
import android.util.Slog;
@@ -332,13 +333,28 @@ class AssociationRequestsProcessor {
}
}
- String[] sameOemPackages = mContext.getResources()
+ // Below we check if the requesting package is allowlisted (usually by the OEM) for creating
+ // CDM associations without user confirmation (prompt).
+ // For this we'll check to config arrays:
+ // - com.android.internal.R.array.config_companionDevicePackages
+ // and
+ // - com.android.internal.R.array.config_companionDeviceCerts.
+ // Both arrays are expected to contain similar number of entries.
+ // config_companionDevicePackages contains package names of the allowlisted packages.
+ // config_companionDeviceCerts contains SHA256 digests of the signatures of the
+ // corresponding packages.
+ // If a package may be signed with one of several certificates, its package name would
+ // appear multiple times in the config_companionDevicePackages, with different entries
+ // (one for each of the valid signing certificates) at the corresponding positions in
+ // config_companionDeviceCerts.
+ final String[] allowlistedPackages = mContext.getResources()
.getStringArray(com.android.internal.R.array.config_companionDevicePackages);
- if (!ArrayUtils.contains(sameOemPackages, packageName)) {
- Slog.w(TAG, packageName
- + " can not silently create associations due to no package found."
- + " Packages from OEM: " + Arrays.toString(sameOemPackages)
- );
+ if (!ArrayUtils.contains(allowlistedPackages, packageName)) {
+ if (DEBUG) {
+ Log.d(TAG, packageName + " is not allowlisted for creating associations "
+ + "without user confirmation (prompt)");
+ Log.v(TAG, "Allowlisted packages=" + Arrays.toString(allowlistedPackages));
+ }
return false;
}
@@ -361,44 +377,41 @@ class AssociationRequestsProcessor {
}
}
- String[] sameOemCerts = mContext.getResources()
+ final String[] allowlistedPackagesSignatureDigests = mContext.getResources()
.getStringArray(com.android.internal.R.array.config_companionDeviceCerts);
-
- Signature[] signatures = mPackageManager.getPackage(packageName).getSigningDetails()
- .getSignatures();
- String[] apkCerts = PackageUtils.computeSignaturesSha256Digests(signatures);
-
- Set<String> sameOemPackageCerts =
- getSameOemPackageCerts(packageName, sameOemPackages, sameOemCerts);
-
- for (String cert : apkCerts) {
- if (sameOemPackageCerts.contains(cert)) {
- return true;
+ final Set<String> allowlistedSignatureDigestsForRequestingPackage = new HashSet<>();
+ for (int i = 0; i < allowlistedPackages.length; i++) {
+ if (allowlistedPackages[i].equals(packageName)) {
+ final String digest = allowlistedPackagesSignatureDigests[i].replaceAll(":", "");
+ allowlistedSignatureDigestsForRequestingPackage.add(digest);
}
}
- Slog.w(TAG, packageName
- + " can not silently create associations. " + packageName
- + " has SHA256 certs from APK: " + Arrays.toString(apkCerts)
- + " and from OEM: " + Arrays.toString(sameOemCerts)
- );
+ final Signature[] requestingPackageSignatures = mPackageManager.getPackage(packageName)
+ .getSigningDetails().getSignatures();
+ final String[] requestingPackageSignatureDigests =
+ PackageUtils.computeSignaturesSha256Digests(requestingPackageSignatures);
- return false;
- }
-
- private static Set<String> getSameOemPackageCerts(
- String packageName, String[] oemPackages, String[] sameOemCerts) {
- Set<String> sameOemPackageCerts = new HashSet<>();
+ boolean requestingPackageSignatureAllowlisted = false;
+ for (String signatureDigest : requestingPackageSignatureDigests) {
+ if (allowlistedSignatureDigestsForRequestingPackage.contains(signatureDigest)) {
+ requestingPackageSignatureAllowlisted = true;
+ break;
+ }
+ }
- // Assume OEM may enter same package name in the parallel string array with
- // multiple APK certs corresponding to it
- for (int i = 0; i < oemPackages.length; i++) {
- if (oemPackages[i].equals(packageName)) {
- sameOemPackageCerts.add(sameOemCerts[i].replaceAll(":", ""));
+ if (!requestingPackageSignatureAllowlisted) {
+ Slog.w(TAG, "Certificate mismatch for allowlisted package " + packageName);
+ if (DEBUG) {
+ Log.d(TAG, " > allowlisted signatures for " + packageName + ": ["
+ + String.join(", ", allowlistedSignatureDigestsForRequestingPackage)
+ + "]");
+ Log.d(TAG, " > actual signatures for " + packageName + ": "
+ + Arrays.toString(requestingPackageSignatureDigests));
}
}
- return sameOemPackageCerts;
+ return requestingPackageSignatureAllowlisted;
}
/**
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index 4c7b9b80d5be..a6bd48056e12 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -51,12 +51,12 @@ class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDe
void onBindingDied(@UserIdInt int userId, @NonNull String packageName);
}
- @UserIdInt
- private final int mUserId;
- @NonNull
- private final ComponentName mComponentName;
- @Nullable
- private Listener mListener;
+ private final @UserIdInt int mUserId;
+ private final @NonNull ComponentName mComponentName;
+ // IMPORTANT: this can (and will!) be null (at the moment, CompanionApplicationController only
+ // installs a listener to the primary ServiceConnector), hence we should always null-check the
+ // reference before calling on it.
+ private @Nullable Listener mListener;
/**
* Create a CompanionDeviceServiceConnector instance.
@@ -125,7 +125,9 @@ class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDe
if (DEBUG) Log.d(TAG, "onBindingDied() " + mComponentName.toShortString());
- mListener.onBindingDied(mUserId, mComponentName.getPackageName());
+ if (mListener != null) {
+ mListener.onBindingDied(mUserId, mComponentName.getPackageName());
+ }
}
@Override
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 186ff6215c9c..2015dc929a59 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -196,13 +196,15 @@ public class NetworkTimeUpdateService extends Binder {
* Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
* test value, i.e. so the normal value will be used next time.
*/
- void setServerConfigForTests(@Nullable String hostname, @Nullable Duration timeout) {
+ void setServerConfigForTests(
+ @Nullable String hostname, @Nullable Integer port, @Nullable Duration timeout) {
mContext.enforceCallingPermission(
android.Manifest.permission.SET_TIME, "set NTP server config for tests");
mLocalLog.log("Setting server config for tests: hostname=" + hostname
+ + ", port=" + port
+ ", timeout=" + timeout);
- mTime.setServerConfigForTests(hostname, timeout);
+ mTime.setServerConfigForTests(hostname, port, timeout);
}
private void onPollNetworkTime(int event) {
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
index 464af01a009a..d7504ceb9d4d 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
@@ -46,6 +46,7 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
*/
private static final String SHELL_COMMAND_SET_SERVER_CONFIG = "set_server_config";
private static final String SET_SERVER_CONFIG_HOSTNAME_ARG = "--hostname";
+ private static final String SET_SERVER_CONFIG_PORT_ARG = "--port";
private static final String SET_SERVER_CONFIG_TIMEOUT_ARG = "--timeout_millis";
@NonNull
@@ -87,6 +88,7 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
private int runSetServerConfig() {
String hostname = null;
+ Integer port = null;
Duration timeout = null;
String opt;
while ((opt = getNextArg()) != null) {
@@ -95,6 +97,10 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
hostname = getNextArgRequired();
break;
}
+ case SET_SERVER_CONFIG_PORT_ARG: {
+ port = Integer.parseInt(getNextArgRequired());
+ break;
+ }
case SET_SERVER_CONFIG_TIMEOUT_ARG: {
timeout = Duration.ofMillis(Integer.parseInt(getNextArgRequired()));
break;
@@ -104,7 +110,7 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
}
}
}
- mNetworkTimeUpdateService.setServerConfigForTests(hostname, timeout);
+ mNetworkTimeUpdateService.setServerConfigForTests(hostname, port, timeout);
return 0;
}
@@ -120,8 +126,9 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
pw.printf(" Refreshes the latest time. Prints whether it was successful.\n");
pw.printf(" %s\n", SHELL_COMMAND_SET_SERVER_CONFIG);
pw.printf(" Sets the NTP server config for tests. The config is not persisted.\n");
- pw.printf(" Options: [%s <hostname>] [%s <millis>]\n",
- SET_SERVER_CONFIG_HOSTNAME_ARG, SET_SERVER_CONFIG_TIMEOUT_ARG);
+ pw.printf(" Options: [%s <hostname>] [%s <port>] [%s <millis>]\n",
+ SET_SERVER_CONFIG_HOSTNAME_ARG, SET_SERVER_CONFIG_PORT_ARG,
+ SET_SERVER_CONFIG_TIMEOUT_ARG);
pw.printf(" Each key/value is optional and must be specified to override the\n");
pw.printf(" normal value, not specifying a key causes it to reset to the original.\n");
pw.println();
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 677fc7931f64..a2cfe4928249 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3130,23 +3130,6 @@ class StorageManagerService extends IStorageManager.Stub
}
/**
- * Is userdata convertible to file based encryption?
- * @return non zero for convertible
- */
- @Override
- public boolean isConvertibleToFBE() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- try {
- return mVold.isConvertibleToFbe();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return false;
- }
- }
-
- /**
* Check whether the device supports filesystem checkpointing.
*
* @return true if the device supports filesystem checkpointing, false otherwise.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0735648c1069..db2c566e8337 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2911,12 +2911,35 @@ public class ActivityManagerService extends IActivityManager.Stub
return mAtmInternal.compatibilityInfoForPackage(ai);
}
+ /**
+ * Enforces that the uid that calls a method is not an
+ * {@link UserHandle#isIsolated(int) isolated} uid.
+ *
+ * @param caller the name of the method being called.
+ * @throws SecurityException if the calling uid is an isolated uid.
+ */
/* package */ void enforceNotIsolatedCaller(String caller) {
if (UserHandle.isIsolated(Binder.getCallingUid())) {
throw new SecurityException("Isolated process not allowed to call " + caller);
}
}
+ /**
+ * Enforces that the uid that calls a method is not an
+ * {@link UserHandle#isIsolated(int) isolated} uid or an
+ * {@link Process#isSdkSandboxUid(int) SDK sandbox} uid.
+ *
+ * @param caller the name of the method being called.
+ * @throws SecurityException if the calling uid is an isolated uid or SDK sandbox uid.
+ */
+ void enforceNotIsolatedOrSdkSandboxCaller(String caller) {
+ enforceNotIsolatedCaller(caller);
+
+ if (Process.isSdkSandboxUid(Binder.getCallingUid())) {
+ throw new SecurityException("SDK sandbox process not allowed to call " + caller);
+ }
+ }
+
@Override
public void setPackageScreenCompatMode(String packageName, int mode) {
mActivityTaskManager.setPackageScreenCompatMode(packageName, mode);
@@ -9186,6 +9209,10 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppRestrictionController.dump(pw, "");
}
+ void dumpAppRestrictionController(ProtoOutputStream proto, int uid) {
+ mAppRestrictionController.dumpAsProto(proto, uid);
+ }
+
/**
* Wrapper function to print out debug data filtered by specified arguments.
*/
@@ -9298,6 +9325,29 @@ public class ActivityManagerService extends IActivityManager.Stub
mProcessList.writeProcessesToProtoLSP(proto, dumpPackage);
}
}
+ } else if ("app-restrictions".equals(cmd)) {
+ int uid = Process.INVALID_UID;
+ boolean error = false;
+ for (int i = 0; i < args.length; i++) {
+ if ("--uid".equals(args[i])) {
+ if (i + 1 < args.length) {
+ try {
+ uid = Integer.parseInt(args[i + 1]);
+ } catch (NumberFormatException e) {
+ error = true;
+ }
+ } else {
+ error = true;
+ }
+ break;
+ }
+ }
+ if (error) {
+ pw.println("Invalid --uid argument");
+ pw.println("Use -h for help.");
+ } else {
+ dumpAppRestrictionController(proto, uid);
+ }
} else {
// default option, dump everything, output is ActivityManagerServiceProto
synchronized (this) {
@@ -12843,7 +12893,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
- enforceNotIsolatedCaller("registerReceiver");
+ enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
diff --git a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
index d1cf0049d146..6f11b0001c7a 100644
--- a/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryExemptionTracker.java
@@ -26,10 +26,13 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.SystemClock;
+import android.util.ArrayMap;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
import com.android.server.am.AppBatteryExemptionTracker.UidBatteryStates;
@@ -65,6 +68,11 @@ final class AppBatteryExemptionTracker
// As it's a UID-based tracker, anywhere which requires a package name, use this default name.
static final String DEFAULT_NAME = "";
+ // As it's a UID-based tracker, while the state change event it receives could be
+ // in the combination of UID + package name, we'd have to leverage each package's state.
+ @GuardedBy("mLock")
+ private UidProcessMap<Integer> mUidPackageStates = new UidProcessMap<>();
+
AppBatteryExemptionTracker(Context context, AppRestrictionController controller) {
this(context, controller, null, null);
}
@@ -103,12 +111,75 @@ final class AppBatteryExemptionTracker
.getUidBatteryUsage(uid);
final int stateTypeIndex = stateTypeToIndex(stateType);
synchronized (mLock) {
- UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
- if (pkg == null) {
- pkg = createAppStateEvents(uid, DEFAULT_NAME);
- mPkgEvents.put(uid, DEFAULT_NAME, pkg);
+ final SparseArray<ArrayMap<String, Integer>> map = mUidPackageStates.getMap();
+ ArrayMap<String, Integer> pkgsStates = map.get(uid);
+ if (pkgsStates == null) {
+ pkgsStates = new ArrayMap<>();
+ map.put(uid, pkgsStates);
+ }
+ int states = 0;
+ int indexOfPkg = pkgsStates.indexOfKey(packageName);
+ if (indexOfPkg >= 0) {
+ states = pkgsStates.valueAt(indexOfPkg);
+ } else {
+ pkgsStates.put(packageName, 0);
+ indexOfPkg = pkgsStates.indexOfKey(packageName);
+ }
+ boolean addEvent = false;
+ if (start) {
+ // Check if there is another package within this UID with this type of event start.
+ boolean alreadyStarted = false;
+ for (int i = pkgsStates.size() - 1; i >= 0; i--) {
+ final int s = pkgsStates.valueAt(i);
+ if ((s & stateType) != 0) {
+ alreadyStarted = true;
+ break;
+ }
+ }
+ pkgsStates.setValueAt(indexOfPkg, states | stateType);
+ if (!alreadyStarted) {
+ // This is the first package within this UID with this type of event start.
+ addEvent = true;
+ }
+ } else {
+ states &= ~stateType;
+ pkgsStates.setValueAt(indexOfPkg, states);
+ boolean allStopped = true;
+ for (int i = pkgsStates.size() - 1; i >= 0; i--) {
+ final int s = pkgsStates.valueAt(i);
+ if ((s & stateType) != 0) {
+ allStopped = false;
+ break;
+ }
+ }
+ if (allStopped) {
+ // None of the packages in this UID has an active event of this type.
+ addEvent = true;
+ }
+ if (states == 0) { // None of the states of this package are active, prune it.
+ pkgsStates.removeAt(indexOfPkg);
+ if (pkgsStates.size() == 0) {
+ map.remove(uid);
+ }
+ }
+ }
+ if (addEvent) {
+ UidBatteryStates pkg = mPkgEvents.get(uid, DEFAULT_NAME);
+ if (pkg == null) {
+ pkg = createAppStateEvents(uid, DEFAULT_NAME);
+ mPkgEvents.put(uid, DEFAULT_NAME, pkg);
+ }
+ pkg.addEvent(start, now, batteryUsage, stateTypeIndex);
}
- pkg.addEvent(start, now, batteryUsage, stateTypeIndex);
+ }
+ }
+
+ @VisibleForTesting
+ @Override
+ void reset() {
+ super.reset();
+ synchronized (mLock) {
+ mUidPackageStates.clear();
}
}
@@ -116,6 +187,7 @@ final class AppBatteryExemptionTracker
if (!enabled) {
synchronized (mLock) {
mPkgEvents.clear();
+ mUidPackageStates.clear();
}
}
}
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index ea1e3357c4dc..b7185ed7a302 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -46,6 +46,7 @@ import android.content.Context;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.os.AppBatteryStatsProto;
import android.os.BatteryConsumer;
import android.os.BatteryConsumer.Dimensions;
import android.os.BatteryStatsInternal;
@@ -62,6 +63,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -676,6 +678,63 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
super.dump(pw, prefix);
}
+ @Override
+ void dumpAsProto(ProtoOutputStream proto, int uid) {
+ synchronized (mLock) {
+ final SparseArray<ImmutableBatteryUsage> uidConsumers = mUidBatteryUsageInWindow;
+ if (uid != android.os.Process.INVALID_UID) {
+ final BatteryUsage usage = uidConsumers.get(uid);
+ if (usage != null) {
+ dumpUidStats(proto, uid, usage);
+ }
+ } else {
+ for (int i = 0, size = uidConsumers.size(); i < size; i++) {
+ final int aUid = uidConsumers.keyAt(i);
+ final BatteryUsage usage = uidConsumers.valueAt(i);
+ dumpUidStats(proto, aUid, usage);
+ }
+ }
+ }
+ }
+
+ private void dumpUidStats(ProtoOutputStream proto, int uid, BatteryUsage usage) {
+ if (usage.mUsage == null) {
+ return;
+ }
+
+ final double foregroundUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND);
+ final double backgroundUsage = usage.getUsagePowerMah(PROCESS_STATE_BACKGROUND);
+ final double fgsUsage = usage.getUsagePowerMah(PROCESS_STATE_FOREGROUND_SERVICE);
+
+ if (foregroundUsage == 0 && backgroundUsage == 0 && fgsUsage == 0) {
+ return;
+ }
+
+ final long token = proto.start(AppBatteryStatsProto.UID_STATS);
+ proto.write(AppBatteryStatsProto.UidStats.UID, uid);
+ dumpProcessStateStats(proto,
+ AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND,
+ foregroundUsage);
+ dumpProcessStateStats(proto,
+ AppBatteryStatsProto.UidStats.ProcessStateStats.BACKGROUND,
+ backgroundUsage);
+ dumpProcessStateStats(proto,
+ AppBatteryStatsProto.UidStats.ProcessStateStats.FOREGROUND_SERVICE,
+ fgsUsage);
+ proto.end(token);
+ }
+
+ private void dumpProcessStateStats(ProtoOutputStream proto, int processState, double powerMah) {
+ if (powerMah == 0) {
+ return;
+ }
+
+ final long token = proto.start(AppBatteryStatsProto.UidStats.PROCESS_STATE_STATS);
+ proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.PROCESS_STATE, processState);
+ proto.write(AppBatteryStatsProto.UidStats.ProcessStateStats.POWER_MAH, powerMah);
+ proto.end(token);
+ }
+
static class BatteryUsage {
static final int BATTERY_USAGE_INDEX_UNSPECIFIED = PROCESS_STATE_UNSPECIFIED;
static final int BATTERY_USAGE_INDEX_FOREGROUND = PROCESS_STATE_FOREGROUND;
@@ -795,6 +854,15 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
return formatBatteryUsage(mUsage);
}
+ double getUsagePowerMah(@BatteryConsumer.ProcessState int processState) {
+ switch (processState) {
+ case PROCESS_STATE_FOREGROUND: return mUsage[1];
+ case PROCESS_STATE_BACKGROUND: return mUsage[2];
+ case PROCESS_STATE_FOREGROUND_SERVICE: return mUsage[3];
+ }
+ return 0;
+ }
+
boolean isValid() {
for (int i = 0; i < mUsage.length; i++) {
if (mUsage[i] < 0.0d) {
diff --git a/services/core/java/com/android/server/am/AppPermissionTracker.java b/services/core/java/com/android/server/am/AppPermissionTracker.java
index 69f70ca0d0e0..622d7465d4bf 100644
--- a/services/core/java/com/android/server/am/AppPermissionTracker.java
+++ b/services/core/java/com/android/server/am/AppPermissionTracker.java
@@ -17,6 +17,14 @@
package com.android.server.am;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.CAMERA;
+import static android.Manifest.permission.RECORD_AUDIO;
+import static android.app.AppOpsManager.OPSTR_CAMERA;
+import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
+import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.opToPublicName;
+import static android.app.AppOpsManager.strOpToOp;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
@@ -27,28 +35,37 @@ import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNA
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.OnPermissionsChangedListener;
import android.content.pm.PackageManagerInternal;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.permission.PermissionManager;
import android.provider.DeviceConfig;
+import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
import com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/**
* The tracker for monitoring selected permission state of apps.
@@ -61,8 +78,17 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
private final MyHandler mHandler;
+ /**
+ * Keep a new instance of callback for each appop we're monitoring,
+ * as the AppOpsService doesn't support monitoring multiple appops with single callback
+ * instance (except the ALL_OPS case).
+ */
+ @GuardedBy("mAppOpsCallbacks")
+ private final SparseArray<MyAppOpsCallback> mAppOpsCallbacks = new SparseArray<>();
+
@GuardedBy("mLock")
- private SparseArray<ArraySet<String>> mUidGrantedPermissionsInMonitor = new SparseArray<>();
+ private SparseArray<ArraySet<UidGrantedPermissionState>> mUidGrantedPermissionsInMonitor =
+ new SparseArray<>();
private volatile boolean mLockedBootCompleted = false;
@@ -82,12 +108,25 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
}
+ private void handleAppOpsInit() {
+ final ArrayList<Integer> ops = new ArrayList<>();
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ for (int i = 0; i < permissions.length; i++) {
+ final Pair<String, Integer> pair = permissions[i];
+ if (pair.second != OP_NONE) {
+ ops.add(pair.second);
+ }
+ }
+ startWatchingMode(ops.toArray(new Integer[ops.size()]));
+ }
+
private void handlePermissionsInit() {
final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
- final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
- final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+ mUidGrantedPermissionsInMonitor;
for (int userId : allUsers) {
final List<ApplicationInfo> apps = pmi.getInstalledApplications(0, userId, SYSTEM_UID);
if (apps == null) {
@@ -96,33 +135,44 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
final long now = SystemClock.elapsedRealtime();
for (int i = 0, size = apps.size(); i < size; i++) {
final ApplicationInfo ai = apps.get(i);
- for (String permission : permissions) {
- if (pm.checkUidPermission(ai.uid, permission) != PERMISSION_GRANTED) {
+ for (Pair<String, Integer> permission : permissions) {
+ final UidGrantedPermissionState state = new UidGrantedPermissionState(
+ ai.uid, permission.first, permission.second);
+ if (!state.isGranted()) {
+ // No need to track it.
continue;
}
synchronized (mLock) {
- ArraySet<String> grantedPermissions = uidPerms.get(ai.uid);
+ ArraySet<UidGrantedPermissionState> grantedPermissions =
+ uidPerms.get(ai.uid);
if (grantedPermissions == null) {
- grantedPermissions = new ArraySet<String>();
+ grantedPermissions = new ArraySet<UidGrantedPermissionState>();
uidPerms.put(ai.uid, grantedPermissions);
+ // This UID has at least one active permission-in-interest now,
+ // let the listeners know.
+ notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
+ STATE_TYPE_PERMISSION);
}
- grantedPermissions.add(permission);
- notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
- STATE_TYPE_PERMISSION);
+ grantedPermissions.add(state);
}
}
}
}
}
+ private void handleAppOpsDestroy() {
+ stopWatchingMode();
+ }
+
private void handlePermissionsDestroy() {
synchronized (mLock) {
- final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+ mUidGrantedPermissionsInMonitor;
final long now = SystemClock.elapsedRealtime();
for (int i = 0, size = uidPerms.size(); i < size; i++) {
final int uid = uidPerms.keyAt(i);
- final ArraySet<String> grantedPermissions = uidPerms.valueAt(i);
- for (int j = 0, numOfPerms = grantedPermissions.size(); j < numOfPerms; j++) {
+ final ArraySet<UidGrantedPermissionState> grantedPermissions = uidPerms.valueAt(i);
+ if (grantedPermissions.size() > 0) {
notifyListenersOnStateChange(uid, DEFAULT_NAME, false, now,
STATE_TYPE_PERMISSION);
}
@@ -131,44 +181,78 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
}
}
+ private void handleOpChanged(int op, int uid, String packageName) {
+ if (DEBUG_PERMISSION_TRACKER) {
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ try {
+ final int mode = appOpsService.checkOperation(op, uid, packageName);
+ Slog.i(TAG, "onOpChanged: " + opToPublicName(op)
+ + " " + UserHandle.formatUid(uid)
+ + " " + packageName + " " + mode);
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ if (permissions != null && permissions.length > 0) {
+ for (int i = 0; i < permissions.length; i++) {
+ final Pair<String, Integer> pair = permissions[i];
+ if (pair.second != op) {
+ continue;
+ }
+ final UidGrantedPermissionState state =
+ new UidGrantedPermissionState(uid, pair.first, op);
+ synchronized (mLock) {
+ handlePermissionsChangedLocked(uid, new UidGrantedPermissionState[] {state});
+ }
+ break;
+ }
+ }
+ }
+
private void handlePermissionsChanged(int uid) {
- final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ if (DEBUG_PERMISSION_TRACKER) {
+ Slog.i(TAG, "handlePermissionsChanged " + UserHandle.formatUid(uid));
+ }
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
if (permissions != null && permissions.length > 0) {
final PermissionManagerServiceInternal pm =
mInjector.getPermissionManagerServiceInternal();
- final boolean[] states = new boolean[permissions.length];
+ final UidGrantedPermissionState[] states =
+ new UidGrantedPermissionState[permissions.length];
for (int i = 0; i < permissions.length; i++) {
- states[i] = pm.checkUidPermission(uid, permissions[i]) == PERMISSION_GRANTED;
+ final Pair<String, Integer> pair = permissions[i];
+ states[i] = new UidGrantedPermissionState(uid, pair.first, pair.second);
if (DEBUG_PERMISSION_TRACKER) {
- Slog.i(TAG, UserHandle.formatUid(uid) + " " + permissions[i] + "=" + states[i]);
+ Slog.i(TAG, states[i].toString());
}
}
synchronized (mLock) {
- handlePermissionsChangedLocked(uid, permissions, states);
+ handlePermissionsChangedLocked(uid, states);
}
}
}
@GuardedBy("mLock")
- private void handlePermissionsChangedLocked(int uid, String[] permissions, boolean[] states) {
+ private void handlePermissionsChangedLocked(int uid, UidGrantedPermissionState[] states) {
final int index = mUidGrantedPermissionsInMonitor.indexOfKey(uid);
- ArraySet<String> grantedPermissions = index >= 0
+ ArraySet<UidGrantedPermissionState> grantedPermissions = index >= 0
? mUidGrantedPermissionsInMonitor.valueAt(index) : null;
final long now = SystemClock.elapsedRealtime();
- for (int i = 0; i < permissions.length; i++) {
- final String permission = permissions[i];
- final boolean granted = states[i];
+ for (int i = 0; i < states.length; i++) {
+ final boolean granted = states[i].isGranted();
boolean changed = false;
if (granted) {
if (grantedPermissions == null) {
grantedPermissions = new ArraySet<>();
mUidGrantedPermissionsInMonitor.put(uid, grantedPermissions);
+ changed = true;
}
- changed = grantedPermissions.add(permission);
- } else if (grantedPermissions != null) {
- changed = grantedPermissions.remove(permission);
- if (grantedPermissions.isEmpty()) {
+ grantedPermissions.add(states[i]);
+ } else if (grantedPermissions != null && !grantedPermissions.isEmpty()) {
+ if (grantedPermissions.remove(states[i]) && grantedPermissions.isEmpty()) {
mUidGrantedPermissionsInMonitor.removeAt(index);
+ changed = true;
}
}
if (changed) {
@@ -178,10 +262,141 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
}
}
+ /**
+ * Represents the grant state of a permission + appop of the given UID.
+ */
+ private class UidGrantedPermissionState {
+ final int mUid;
+ final @Nullable String mPermission;
+ final int mAppOp;
+
+ private boolean mPermissionGranted;
+ private boolean mAppOpAllowed;
+
+ UidGrantedPermissionState(int uid, @Nullable String permission, int appOp) {
+ mUid = uid;
+ mPermission = permission;
+ mAppOp = appOp;
+ updatePermissionState();
+ updateAppOps();
+ }
+
+ void updatePermissionState() {
+ if (TextUtils.isEmpty(mPermission)) {
+ mPermissionGranted = true;
+ return;
+ }
+ mPermissionGranted = mInjector.getPermissionManagerServiceInternal()
+ .checkUidPermission(mUid, mPermission) == PERMISSION_GRANTED;
+ }
+
+ void updateAppOps() {
+ if (mAppOp == OP_NONE) {
+ mAppOpAllowed = true;
+ return;
+ }
+ final String[] packages = mInjector.getPackageManager().getPackagesForUid(mUid);
+ if (packages != null) {
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ for (String pkg : packages) {
+ try {
+ final int mode = appOpsService.checkOperation(mAppOp, mUid, pkg);
+ if (mode == AppOpsManager.MODE_ALLOWED) {
+ mAppOpAllowed = true;
+ return;
+ }
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ }
+ mAppOpAllowed = false;
+ }
+
+ boolean isGranted() {
+ return mPermissionGranted && mAppOpAllowed;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null || !(other instanceof UidGrantedPermissionState)) {
+ return false;
+ }
+ final UidGrantedPermissionState otherState = (UidGrantedPermissionState) other;
+ return mUid == otherState.mUid && mAppOp == otherState.mAppOp
+ && Objects.equals(mPermission, otherState.mPermission);
+ }
+
+ @Override
+ public int hashCode() {
+ return (Integer.hashCode(mUid) * 31 + Integer.hashCode(mAppOp)) * 31
+ + (mPermission == null ? 0 : mPermission.hashCode());
+ }
+
+ @Override
+ public String toString() {
+ String s = "UidGrantedPermissionState{"
+ + System.identityHashCode(this) + " "
+ + UserHandle.formatUid(mUid) + ": ";
+ final boolean emptyPermissionName = TextUtils.isEmpty(mPermission);
+ if (!emptyPermissionName) {
+ s += mPermission + "=" + mPermissionGranted;
+ }
+ if (mAppOp != OP_NONE) {
+ if (!emptyPermissionName) {
+ s += ",";
+ }
+ s += opToPublicName(mAppOp) + "=" + mAppOpAllowed;
+ }
+ s += "}";
+ return s;
+ }
+ }
+
+ private void startWatchingMode(@NonNull Integer[] ops) {
+ synchronized (mAppOpsCallbacks) {
+ stopWatchingMode();
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ try {
+ for (int op: ops) {
+ final MyAppOpsCallback cb = new MyAppOpsCallback();
+ mAppOpsCallbacks.put(op, cb);
+ appOpsService.startWatchingModeWithFlags(op, null,
+ AppOpsManager.WATCH_FOREGROUND_CHANGES, cb);
+ }
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ }
+
+ private void stopWatchingMode() {
+ synchronized (mAppOpsCallbacks) {
+ final IAppOpsService appOpsService = mInjector.getIAppOpsService();
+ for (int i = mAppOpsCallbacks.size() - 1; i >= 0; i--) {
+ try {
+ appOpsService.stopWatchingMode(mAppOpsCallbacks.valueAt(i));
+ } catch (RemoteException e) {
+ // Intra-process call, should never happen.
+ }
+ }
+ mAppOpsCallbacks.clear();
+ }
+ }
+
+ private class MyAppOpsCallback extends IAppOpsCallback.Stub {
+ @Override
+ public void opChanged(int op, int uid, String packageName) {
+ mHandler.obtainMessage(MyHandler.MSG_APPOPS_CHANGED, op, uid, packageName)
+ .sendToTarget();
+ }
+ }
+
private static class MyHandler extends Handler {
static final int MSG_PERMISSIONS_INIT = 0;
static final int MSG_PERMISSIONS_DESTROY = 1;
static final int MSG_PERMISSIONS_CHANGED = 2;
+ static final int MSG_APPOPS_CHANGED = 3;
private @NonNull AppPermissionTracker mTracker;
@@ -194,14 +409,19 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_PERMISSIONS_INIT:
+ mTracker.handleAppOpsInit();
mTracker.handlePermissionsInit();
break;
case MSG_PERMISSIONS_DESTROY:
mTracker.handlePermissionsDestroy();
+ mTracker.handleAppOpsDestroy();
break;
case MSG_PERMISSIONS_CHANGED:
mTracker.handlePermissionsChanged(msg.arg1);
break;
+ case MSG_APPOPS_CHANGED:
+ mTracker.handleOpChanged(msg.arg1, msg.arg2, (String) msg.obj);
+ break;
}
}
}
@@ -231,25 +451,41 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
pw.println("APP PERMISSIONS TRACKER:");
- final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
final String prefixMore = " " + prefix;
final String prefixMoreMore = " " + prefixMore;
- for (String permission : permissions) {
+ for (Pair<String, Integer> permission : permissions) {
pw.print(prefixMore);
- pw.print(permission);
+ final boolean emptyPermissionName = TextUtils.isEmpty(permission.first);
+ if (!emptyPermissionName) {
+ pw.print(permission.first);
+ }
+ if (permission.second != OP_NONE) {
+ if (!emptyPermissionName) {
+ pw.print('+');
+ }
+ pw.print(opToPublicName(permission.second));
+ }
pw.println(':');
synchronized (mLock) {
- final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
+ final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
+ mUidGrantedPermissionsInMonitor;
pw.print(prefixMoreMore);
pw.print('[');
boolean needDelimiter = false;
for (int i = 0, size = uidPerms.size(); i < size; i++) {
- if (uidPerms.valueAt(i).contains(permission)) {
- if (needDelimiter) {
- pw.print(',');
+ final ArraySet<UidGrantedPermissionState> uidPerm = uidPerms.valueAt(i);
+ for (int j = uidPerm.size() - 1; j >= 0; j--) {
+ final UidGrantedPermissionState state = uidPerm.valueAt(j);
+ if (state.mAppOp == permission.second
+ && TextUtils.equals(state.mPermission, permission.first)) {
+ if (needDelimiter) {
+ pw.print(',');
+ }
+ needDelimiter = true;
+ pw.print(UserHandle.formatUid(state.mUid));
+ break;
}
- needDelimiter = true;
- pw.print(UserHandle.formatUid(uidPerms.keyAt(i)));
}
}
pw.println(']');
@@ -277,20 +513,25 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
static final boolean DEFAULT_BG_PERMISSION_MONITOR_ENABLED = true;
/**
- * Default value to {@link #mBgPermissionsInMonitor}.
+ * Default value to {@link #mBgPermissionsInMonitor}, it comes in pair;
+ * the first string strings in the pair is the permission name, and the second string
+ * is the appops name, if they are associated.
*/
static final String[] DEFAULT_BG_PERMISSIONS_IN_MONITOR = new String[] {
- ACCESS_FINE_LOCATION,
+ ACCESS_FINE_LOCATION, OPSTR_FINE_LOCATION,
+ CAMERA, OPSTR_CAMERA,
+ RECORD_AUDIO, OPSTR_RECORD_AUDIO,
};
/**
* @see #KEY_BG_PERMISSIONS_IN_MONITOR.
*/
- volatile String[] mBgPermissionsInMonitor = DEFAULT_BG_PERMISSIONS_IN_MONITOR;
+ volatile @NonNull Pair[] mBgPermissionsInMonitor;
AppPermissionPolicy(@NonNull Injector injector, @NonNull AppPermissionTracker tracker) {
super(injector, tracker, KEY_BG_PERMISSION_MONITOR_ENABLED,
DEFAULT_BG_PERMISSION_MONITOR_ENABLED);
+ mBgPermissionsInMonitor = parsePermissionConfig(DEFAULT_BG_PERMISSIONS_IN_MONITOR);
}
@Override
@@ -311,17 +552,38 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
}
}
- String[] getBgPermissionsInMonitor() {
+ Pair[] getBgPermissionsInMonitor() {
return mBgPermissionsInMonitor;
}
+ private @NonNull Pair[] parsePermissionConfig(@NonNull String[] perms) {
+ final Pair[] result = new Pair[perms.length / 2];
+ for (int i = 0, j = 0; i < perms.length; i += 2, j++) {
+ try {
+ result[j] = Pair.create(TextUtils.isEmpty(perms[i]) ? null : perms[i],
+ TextUtils.isEmpty(perms[i + 1]) ? OP_NONE : strOpToOp(perms[i + 1]));
+ } catch (Exception e) {
+ // Ignore.
+ }
+ }
+ return result;
+ }
+
private void updateBgPermissionsInMonitor() {
final String config = DeviceConfig.getString(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_BG_PERMISSIONS_IN_MONITOR,
null);
- mBgPermissionsInMonitor = config != null
- ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR;
+ final Pair[] newPermsInMonitor = parsePermissionConfig(
+ config != null ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR);
+ if (!Arrays.equals(mBgPermissionsInMonitor, newPermsInMonitor)) {
+ mBgPermissionsInMonitor = newPermsInMonitor;
+ if (isEnabled()) {
+ // Trigger a reload.
+ onTrackerEnabled(false);
+ onTrackerEnabled(true);
+ }
+ }
}
@Override
@@ -338,7 +600,21 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
pw.print(prefix);
pw.print(KEY_BG_PERMISSIONS_IN_MONITOR);
pw.print('=');
- pw.println(Arrays.toString(mBgPermissionsInMonitor));
+ pw.print('[');
+ for (int i = 0; i < mBgPermissionsInMonitor.length; i++) {
+ if (i > 0) {
+ pw.print(',');
+ }
+ final Pair<String, Integer> pair = mBgPermissionsInMonitor[i];
+ if (pair.first != null) {
+ pw.print(pair.first);
+ }
+ pw.print(',');
+ if (pair.second != OP_NONE) {
+ pw.print(opToPublicName(pair.second));
+ }
+ }
+ pw.println(']');
}
}
}
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index dc8403aea1b3..15484b2d618e 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -135,6 +135,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArrayMap;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -1369,6 +1370,12 @@ public final class AppRestrictionController {
}
}
+ void dumpAsProto(ProtoOutputStream proto, int uid) {
+ for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
+ mAppStateTrackers.get(i).dumpAsProto(proto, uid);
+ }
+ }
+
private void applyRestrictionLevel(String pkgName, int uid, @RestrictionLevel int level,
int curBucket, boolean allowUpdateBucket, int reason, int subReason) {
int curLevel;
diff --git a/services/core/java/com/android/server/am/BaseAppStateTracker.java b/services/core/java/com/android/server/am/BaseAppStateTracker.java
index 0fada53d622e..570d7e53fadc 100644
--- a/services/core/java/com/android/server/am/BaseAppStateTracker.java
+++ b/services/core/java/com/android/server/am/BaseAppStateTracker.java
@@ -33,9 +33,12 @@ import android.media.session.MediaSessionManager;
import android.os.BatteryManagerInternal;
import android.os.BatteryStatsInternal;
import android.os.Handler;
+import android.os.ServiceManager;
import android.permission.PermissionManager;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+import com.android.internal.app.IAppOpsService;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.notification.NotificationManagerInternal;
@@ -250,6 +253,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
mInjector.getPolicy().dump(pw, " " + prefix);
}
+ void dumpAsProto(ProtoOutputStream proto, int uid) {
+ }
+
static class Injector<T extends BaseAppStatePolicy> {
T mAppStatePolicy;
@@ -266,6 +272,7 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
MediaSessionManager mMediaSessionManager;
RoleManager mRoleManager;
NotificationManagerInternal mNotificationManagerInternal;
+ IAppOpsService mIAppOpsService;
void setPolicy(T policy) {
mAppStatePolicy = policy;
@@ -288,6 +295,8 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
mRoleManager = context.getSystemService(RoleManager.class);
mNotificationManagerInternal = LocalServices.getService(
NotificationManagerInternal.class);
+ mIAppOpsService = IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
getPolicy().onSystemReady();
}
@@ -358,5 +367,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
NotificationManagerInternal getNotificationManagerInternal() {
return mNotificationManagerInternal;
}
+
+ IAppOpsService getIAppOpsService() {
+ return mIAppOpsService;
+ }
}
}
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 1131fa8a32b8..4fdc88d3fd64 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -561,8 +561,18 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
// We were asked to fetch Bluetooth data.
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
- bluetoothReceiver = new SynchronousResultReceiver("bluetooth");
- adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+ SynchronousResultReceiver resultReceiver =
+ new SynchronousResultReceiver("bluetooth");
+ adapter.requestControllerActivityEnergyInfo(
+ Runnable::run,
+ info -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY,
+ info);
+ resultReceiver.send(0, bundle);
+ }
+ );
+ bluetoothReceiver = resultReceiver;
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 7ed3dcf40f65..9626bbe0b4b2 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -407,7 +407,6 @@ public class OomAdjuster {
uids.clear();
uids.put(uidRec.getUid(), uidRec);
updateUidsLSP(uids, SystemClock.elapsedRealtime());
- mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(uids);
}
}
@@ -1144,8 +1143,6 @@ public class OomAdjuster {
}
}
- mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(activeUids);
-
return mService.mAppProfiler.updateLowMemStateLSP(numCached, numEmpty, numTrimming);
}
@@ -1180,6 +1177,11 @@ public class OomAdjuster {
@GuardedBy({"mService", "mProcLock"})
private void updateUidsLSP(ActiveUids activeUids, final long nowElapsed) {
+ // This compares previously set procstate to the current procstate in regards to whether
+ // or not the app's network access will be blocked. So, this needs to be called before
+ // we update the UidRecord's procstate by calling {@link UidRecord#setSetProcState}.
+ mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(activeUids);
+
ArrayList<UidRecord> becameIdle = mTmpBecameIdle;
becameIdle.clear();
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index e9205230a4ad..67d6d3111955 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -85,15 +85,6 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
Slog.w(TAG, "Failed to send connected event", ex);
}
}
-
- @Override
- public void onDisconnected(@NonNull IGameService service) {
- try {
- service.disconnected();
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to send disconnected event", ex);
- }
- }
};
private final ServiceLifecycleCallbacks<IGameSessionService>
@@ -181,7 +172,8 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
}
@Override
- public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {}
+ public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+ }
};
private final IGameServiceController mGameServiceController =
@@ -338,7 +330,9 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
destroyAndClearAllGameSessionsLocked();
- mGameServiceConnector.unbind();
+ mGameServiceConnector.post(IGameService::disconnected).whenComplete((result, t) -> {
+ mGameServiceConnector.unbind();
+ });
mGameSessionServiceConnector.unbind();
mGameServiceConnector.setServiceLifecycleCallbacks(null);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d01be5820d34..309a4ff16753 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -102,6 +102,7 @@ import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerOutputCallback;
import android.media.IStrategyPreferredDevicesDispatcher;
@@ -8723,6 +8724,11 @@ public class AudioService extends IAudioService.Stub
return mSpatializerHelper.isHeadTrackerEnabled(Objects.requireNonNull(device));
}
+ /** @see Spatializer#isHeadTrackerAvailable() */
+ public boolean isHeadTrackerAvailable() {
+ return mSpatializerHelper.isHeadTrackerAvailable();
+ }
+
/** @see Spatializer#setSpatializerEnabled(boolean) */
public void setSpatializerEnabled(boolean enabled) {
enforceModifyDefaultAudioEffectsPermission();
@@ -8767,6 +8773,13 @@ public class AudioService extends IAudioService.Stub
mSpatializerHelper.unregisterHeadTrackingModeCallback(cb);
}
+ /** @see Spatializer.SpatializerHeadTrackerAvailableDispatcherStub */
+ public void registerSpatializerHeadTrackerAvailableCallback(
+ @NonNull ISpatializerHeadTrackerAvailableCallback cb, boolean register) {
+ Objects.requireNonNull(cb);
+ mSpatializerHelper.registerHeadTrackerAvailableCallback(cb, register);
+ }
+
/** @see Spatializer#setOnHeadToSoundstagePoseUpdatedListener */
public void registerHeadToSoundstagePoseCallback(
@NonNull ISpatializerHeadToSoundStagePoseCallback cb) {
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 5af73c9e46ea..f0f04e27b7de 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -30,6 +30,7 @@ import android.media.INativeSpatializerCallback;
import android.media.ISpatializer;
import android.media.ISpatializerCallback;
import android.media.ISpatializerHeadToSoundStagePoseCallback;
+import android.media.ISpatializerHeadTrackerAvailableCallback;
import android.media.ISpatializerHeadTrackingCallback;
import android.media.ISpatializerHeadTrackingModeCallback;
import android.media.ISpatializerOutputCallback;
@@ -126,6 +127,7 @@ public class SpatializerHelper {
private boolean mBinauralSupported = false;
private int mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
private int mDesiredHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
+ private boolean mHeadTrackerAvailable = false;
/**
* The desired head tracking mode when enabling head tracking, tracks mDesiredHeadTrackingMode,
* except when head tracking gets disabled through setting the desired mode to
@@ -137,6 +139,7 @@ public class SpatializerHelper {
private @Nullable SpatializerCallback mSpatCallback;
private @Nullable SpatializerHeadTrackingCallback mSpatHeadTrackingCallback;
private @Nullable HelperDynamicSensorCallback mDynSensorCallback;
+ private boolean mIsHeadTrackingSupported = false;
// default attributes and format that determine basic availability of spatialization
private static final AudioAttributes DEFAULT_ATTRIBUTES = new AudioAttributes.Builder()
@@ -811,8 +814,9 @@ public class SpatializerHelper {
mSpat = AudioSystem.getSpatializer(mSpatCallback);
try {
mSpat.setLevel((byte) Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
+ mIsHeadTrackingSupported = mSpat.isHeadTrackingSupported();
//TODO: register heatracking callback only when sensors are registered
- if (mSpat.isHeadTrackingSupported()) {
+ if (mIsHeadTrackingSupported) {
mSpat.registerHeadTrackingCallback(mSpatHeadTrackingCallback);
}
} catch (RemoteException e) {
@@ -830,11 +834,15 @@ public class SpatializerHelper {
if (mSpat != null) {
mSpatCallback = null;
try {
- mSpat.registerHeadTrackingCallback(null);
+ if (mIsHeadTrackingSupported) {
+ mSpat.registerHeadTrackingCallback(null);
+ }
+ mHeadTrackerAvailable = false;
mSpat.release();
} catch (RemoteException e) {
Log.e(TAG, "Can't set release spatializer cleanly", e);
}
+ mIsHeadTrackingSupported = false;
mSpat = null;
}
}
@@ -890,6 +898,18 @@ public class SpatializerHelper {
mHeadTrackingModeCallbacks.unregister(callback);
}
+ final RemoteCallbackList<ISpatializerHeadTrackerAvailableCallback> mHeadTrackerCallbacks =
+ new RemoteCallbackList<>();
+
+ synchronized void registerHeadTrackerAvailableCallback(
+ @NonNull ISpatializerHeadTrackerAvailableCallback cb, boolean register) {
+ if (register) {
+ mHeadTrackerCallbacks.register(cb);
+ } else {
+ mHeadTrackerCallbacks.unregister(cb);
+ }
+ }
+
synchronized int[] getSupportedHeadTrackingModes() {
switch (mState) {
case STATE_UNINITIALIZED:
@@ -1090,6 +1110,10 @@ public class SpatializerHelper {
return false;
}
+ synchronized boolean isHeadTrackerAvailable() {
+ return mHeadTrackerAvailable;
+ }
+
private boolean checkSpatForHeadTracking(String funcName) {
switch (mState) {
case STATE_UNINITIALIZED:
@@ -1105,7 +1129,7 @@ public class SpatializerHelper {
}
break;
}
- return true;
+ return mIsHeadTrackingSupported;
}
private void dispatchActualHeadTrackingMode(int newMode) {
@@ -1115,7 +1139,8 @@ public class SpatializerHelper {
mHeadTrackingModeCallbacks.getBroadcastItem(i)
.dispatchSpatializerActualHeadTrackingModeChanged(newMode);
} catch (RemoteException e) {
- Log.e(TAG, "Error in dispatchSpatializerActualHeadTrackingModeChanged", e);
+ Log.e(TAG, "Error in dispatchSpatializerActualHeadTrackingModeChanged("
+ + newMode + ")", e);
}
}
mHeadTrackingModeCallbacks.finishBroadcast();
@@ -1128,12 +1153,27 @@ public class SpatializerHelper {
mHeadTrackingModeCallbacks.getBroadcastItem(i)
.dispatchSpatializerDesiredHeadTrackingModeChanged(newMode);
} catch (RemoteException e) {
- Log.e(TAG, "Error in dispatchSpatializerDesiredHeadTrackingModeChanged", e);
+ Log.e(TAG, "Error in dispatchSpatializerDesiredHeadTrackingModeChanged("
+ + newMode + ")", e);
}
}
mHeadTrackingModeCallbacks.finishBroadcast();
}
+ private void dispatchHeadTrackerAvailable(boolean available) {
+ final int nbCallbacks = mHeadTrackerCallbacks.beginBroadcast();
+ for (int i = 0; i < nbCallbacks; i++) {
+ try {
+ mHeadTrackerCallbacks.getBroadcastItem(i)
+ .dispatchSpatializerHeadTrackerAvailable(available);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in dispatchSpatializerHeadTrackerAvailable("
+ + available + ")", e);
+ }
+ }
+ mHeadTrackerCallbacks.finishBroadcast();
+ }
+
//------------------------------------------------------
// head pose
final RemoteCallbackList<ISpatializerHeadToSoundStagePoseCallback> mHeadPoseCallbacks =
@@ -1279,13 +1319,8 @@ public class SpatializerHelper {
Log.e(TAG, "not " + action + " sensors, null spatializer");
return;
}
- try {
- if (!mSpat.isHeadTrackingSupported()) {
- Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
- return;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "not " + action + " sensors, error querying headtracking", e);
+ if (!mIsHeadTrackingSupported) {
+ Log.e(TAG, "not " + action + " sensors, spatializer doesn't support headtracking");
return;
}
int headHandle = -1;
@@ -1348,6 +1383,10 @@ public class SpatializerHelper {
try {
Log.i(TAG, "setHeadSensor:" + headHandle);
mSpat.setHeadSensor(headHandle);
+ if (mHeadTrackerAvailable != (headHandle != -1)) {
+ mHeadTrackerAvailable = (headHandle != -1);
+ dispatchHeadTrackerAvailable(mHeadTrackerAvailable);
+ }
} catch (Exception e) {
Log.e(TAG, "Error calling setHeadSensor:" + headHandle, e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 1b2e606117e7..1370fd83f6a8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -38,7 +38,7 @@ import java.util.NoSuchElementException;
*/
public abstract class BaseClientMonitor implements IBinder.DeathRecipient {
- private static final String TAG = "Biometrics/ClientMonitor";
+ private static final String TAG = "BaseClientMonitor";
protected static final boolean DEBUG = true;
// Counter used to distinguish between ClientMonitor instances to help debugging.
@@ -120,8 +120,18 @@ public abstract class BaseClientMonitor implements IBinder.DeathRecipient {
}
/**
+ * Sets the lifecycle callback before the operation is started via
+ * {@link #start(ClientMonitorCallback)} when the client must wait for a cookie before starting.
+ *
+ * @param callback lifecycle callback (typically same callback used for starting the operation)
+ */
+ public void waitForCookie(@NonNull ClientMonitorCallback callback) {
+ mCallback = callback;
+ }
+
+ /**
* Starts the ClientMonitor's lifecycle.
- * @param callback invoked when the operation is complete (succeeds, fails, etc)
+ * @param callback invoked when the operation is complete (succeeds, fails, etc.)
*/
public void start(@NonNull ClientMonitorCallback callback) {
mCallback = wrapCallbackForStart(callback);
@@ -246,12 +256,12 @@ public abstract class BaseClientMonitor implements IBinder.DeathRecipient {
}
/** Unique request id. */
- public final long getRequestId() {
+ public long getRequestId() {
return mRequestId;
}
/** If a unique id has been set via {@link #setRequestId(long)} */
- public final boolean hasRequestId() {
+ public boolean hasRequestId() {
return mRequestId > 0;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index d0ec4470d3e6..19a93f30937f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -285,7 +285,7 @@ public class BiometricScheduler {
// Not all operations start immediately. BiometricPrompt waits for its operation
// to arrive at the head of the queue, before pinging it to start.
- final int cookie = mCurrentOperation.isReadyToStart();
+ final int cookie = mCurrentOperation.isReadyToStart(mInternalCallback);
if (cookie == 0) {
if (!mCurrentOperation.start(mInternalCallback)) {
// Note down current length of queue
@@ -463,6 +463,18 @@ public class BiometricScheduler {
return mCurrentOperation != null ? mCurrentOperation.getClientMonitor() : null;
}
+ /** The current operation if the requestId is set and matches. */
+ @Deprecated
+ @Nullable
+ public BaseClientMonitor getCurrentClientIfMatches(long requestId) {
+ if (mCurrentOperation != null) {
+ if (mCurrentOperation.isMatchingRequestId(requestId)) {
+ return mCurrentOperation.getClientMonitor();
+ }
+ }
+ return null;
+ }
+
public int getCurrentPendingCount() {
return mPendingOperations.size();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
index 15f0cadced99..968146a166ed 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
@@ -123,11 +123,12 @@ public class BiometricSchedulerOperation {
*
* @return cookie or 0 if ready/started
*/
- public int isReadyToStart() {
+ public int isReadyToStart(@NonNull ClientMonitorCallback callback) {
if (mState == STATE_WAITING_FOR_COOKIE || mState == STATE_WAITING_IN_QUEUE) {
final int cookie = mClientMonitor.getCookie();
if (cookie != 0) {
mState = STATE_WAITING_FOR_COOKIE;
+ mClientMonitor.waitForCookie(getWrappedCallback(callback));
}
return cookie;
}
@@ -137,7 +138,7 @@ public class BiometricSchedulerOperation {
/**
* Start this operation without waiting for a cookie
- * (i.e. {@link #isReadyToStart() returns zero}
+ * (i.e. {@link #isReadyToStart(ClientMonitorCallback)} returns zero}
*
* @param callback lifecycle callback
* @return if this operation started
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
index 008717899aba..aeb6b6e2a907 100644
--- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
@@ -84,7 +84,8 @@ public final class SensorOverlays {
};
try {
- mUdfpsOverlayController.get().showUdfpsOverlay(sensorId, reason, callback);
+ mUdfpsOverlayController.get().showUdfpsOverlay(
+ client.getRequestId(), sensorId, reason, callback);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
index 4f900208841e..a0999771a1be 100644
--- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
@@ -57,30 +57,25 @@ public class UserAwareBiometricScheduler extends BiometricScheduler {
@Nullable private StopUserClient<?> mStopUserClient;
private class ClientFinishedCallback implements ClientMonitorCallback {
- private final BaseClientMonitor mOwner;
+ @NonNull private final BaseClientMonitor mOwner;
- ClientFinishedCallback(BaseClientMonitor owner) {
+ ClientFinishedCallback(@NonNull BaseClientMonitor owner) {
mOwner = owner;
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
mHandler.post(() -> {
- if (mOwner != clientMonitor) {
- Slog.e(getTag(), "[Wrong client finished], actual: "
- + clientMonitor + ", expected: " + mOwner);
- return;
- }
-
Slog.d(getTag(), "[Client finished] " + clientMonitor + ", success: " + success);
if (mCurrentOperation != null && mCurrentOperation.isFor(mOwner)) {
mCurrentOperation = null;
- startNextOperationIfIdle();
} else {
- // can usually be ignored (hal died, etc.)
- Slog.d(getTag(), "operation is already null or different (reset?): "
+ // can happen if the hal dies and is usually okay
+ // do not unset the current operation that may be newer
+ Slog.w(getTag(), "operation is already null or different (reset?): "
+ mCurrentOperation);
}
+ startNextOperationIfIdle();
});
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index b4befd23671f..e8d8fb828542 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -928,7 +928,8 @@ public class FingerprintService extends SystemService {
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -936,11 +937,11 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "No matching provider for onFingerDown, sensorId: " + sensorId);
return;
}
- provider.onPointerDown(sensorId, x, y, minor, major);
+ provider.onPointerDown(requestId, sensorId, x, y, minor, major);
}
@Override
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -948,11 +949,11 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "No matching provider for onFingerUp, sensorId: " + sensorId);
return;
}
- provider.onPointerUp(sensorId);
+ provider.onPointerUp(requestId, sensorId);
}
@Override
- public void onUiReady(int sensorId) {
+ public void onUiReady(long requestId, int sensorId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -960,7 +961,7 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "No matching provider for onUiReady, sensorId: " + sensorId);
return;
}
- provider.onUiReady(sensorId);
+ provider.onUiReady(requestId, sensorId);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 0bdc4ebad66e..9cdbdc9158fb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -142,11 +142,11 @@ public interface ServiceProvider {
long getAuthenticatorId(int sensorId, int userId);
- void onPointerDown(int sensorId, int x, int y, float minor, float major);
+ void onPointerDown(long requestId, int sensorId, int x, int y, float minor, float major);
- void onPointerUp(int sensorId);
+ void onPointerUp(long requestId, int sensorId);
- void onUiReady(int sensorId);
+ void onUiReady(long requestId, int sensorId);
void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index f810bca9707d..1fac8a8ce5c9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -580,39 +580,37 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClient();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.e(getTag(), "onPointerDown received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerDown(x, y, minor, major);
+ ((Udfps) client).onPointerDown(x, y, minor, major);
}
@Override
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClient();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.e(getTag(), "onPointerUp received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerUp();
+ ((Udfps) client).onPointerUp();
}
@Override
- public void onUiReady(int sensorId) {
+ public void onUiReady(long requestId, int sensorId) {
final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClient();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.e(getTag(), "onUiReady received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onUiReady();
+ ((Udfps) client).onUiReady();
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 9d60859a4a21..1d2a3655021c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -792,36 +792,34 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
+ public void onPointerDown(long requestId, int sensorId, int x, int y,
+ float minor, float major) {
+ final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onFingerDown received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerDown(x, y, minor, major);
+ ((Udfps) client).onPointerDown(x, y, minor, major);
}
@Override
- public void onPointerUp(int sensorId) {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
+ public void onPointerUp(long requestId, int sensorId) {
+ final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onFingerDown received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onPointerUp();
+ ((Udfps) client).onPointerUp();
}
@Override
- public void onUiReady(int sensorId) {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
+ public void onUiReady(long requestId, int sensorId) {
+ final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onUiReady received during client: " + client);
return;
}
- final Udfps udfps = (Udfps) client;
- udfps.onUiReady();
+ ((Udfps) client).onUiReady();
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 149526f21fdb..a4e343e786c1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -441,7 +441,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
}
@Override
- public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
+ public void onPointerDown(long requestId, int sensorId, int x, int y, float minor,
+ float major) {
mHandler.post(() -> {
Slog.d(TAG, "onFingerDown");
final AuthenticationConsumer lastAuthenticatedConsumer =
@@ -488,7 +489,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
}
@Override
- public void onPointerUp(int sensorId) {
+ public void onPointerUp(long requestId, int sensorId) {
mHandler.post(() -> {
Slog.d(TAG, "onFingerUp");
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 7cb29215b5bf..cb04ddfd636d 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -156,9 +156,15 @@ final class ColorFade {
mMode = mode;
+ DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+ if (displayInfo == null) {
+ // displayInfo can be null if the associated display has been removed. There
+ // is a delay between the display being removed and ColorFade being dismissed.
+ return false;
+ }
+
// Get the display size and layer stack.
// This is not expected to change while the color fade surface is showing.
- DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
mDisplayLayerStack = displayInfo.layerStack;
mDisplayWidth = displayInfo.getNaturalWidth();
mDisplayHeight = displayInfo.getNaturalHeight();
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7a0cf4b592e7..540ae8165dbd 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -73,6 +73,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private final SurfaceControlProxy mSurfaceControlProxy;
+ private final boolean mIsBootDisplayModeSupported;
+
// Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
@@ -85,6 +87,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
super(syncRoot, context, handler, listener, TAG);
mInjector = injector;
mSurfaceControlProxy = mInjector.getSurfaceControlProxy();
+ mIsBootDisplayModeSupported = mSurfaceControlProxy.getBootDisplayModeSupport();
}
@Override
@@ -349,8 +352,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
if (preferredRecord != null) {
int preferredModeId = preferredRecord.mMode.getModeId();
- if (mSurfaceControlProxy.getBootDisplayModeSupport()
- && mSystemPreferredModeId != preferredModeId) {
+ if (mIsBootDisplayModeSupported && mSystemPreferredModeId != preferredModeId) {
mSystemPreferredModeId = preferredModeId;
preferredModeChanged = true;
}
@@ -900,7 +902,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
updateDeviceInfoLocked();
- if (!mSurfaceControlProxy.getBootDisplayModeSupport()) {
+ if (!mIsBootDisplayModeSupported) {
return;
}
if (mUserPreferredModeId == INVALID_MODE_ID) {
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index 176c08c8da29..924db6a49eeb 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -22,12 +22,14 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ILocaleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.res.Configuration;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.LocaleList;
@@ -154,6 +156,12 @@ public class LocaleManagerService extends SystemService {
}
@Override
+ @NonNull
+ public LocaleList getSystemLocales() throws RemoteException {
+ return LocaleManagerService.this.getSystemLocales();
+ }
+
+ @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
@@ -426,6 +434,32 @@ public class LocaleManagerService extends SystemService {
return null;
}
+ /**
+ * Returns the current system locales.
+ */
+ @NonNull
+ public LocaleList getSystemLocales() throws RemoteException {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getSystemLocalesUnchecked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @NonNull
+ private LocaleList getSystemLocalesUnchecked() throws RemoteException {
+ LocaleList systemLocales = null;
+ Configuration conf = ActivityManager.getService().getConfiguration();
+ if (conf != null) {
+ systemLocales = conf.getLocales();
+ }
+ if (systemLocales == null) {
+ systemLocales = LocaleList.getEmptyLocaleList();
+ }
+ return systemLocales;
+ }
+
private void logMetric(@NonNull AppLocaleChangedAtomRecord atomRecordForMetrics) {
FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_LOCALES_CHANGED,
atomRecordForMetrics.mCallingUid,
diff --git a/services/core/java/com/android/server/locales/TEST_MAPPING b/services/core/java/com/android/server/locales/TEST_MAPPING
index 27d2851a1bbe..160542b6aa0f 100644
--- a/services/core/java/com/android/server/locales/TEST_MAPPING
+++ b/services/core/java/com/android/server/locales/TEST_MAPPING
@@ -9,10 +9,13 @@
]
},
{
- "name": "CtsLocaleManagerTestCases"
- },
- {
"name": "CtsLocaleManagerHostTestCases"
}
+ ],
+ "postsubmit": [
+ // TODO(b/225192026): Move back to presubmit after b/225192026 is fixed
+ {
+ "name": "CtsLocaleManagerTestCases"
+ }
]
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 3ce8e4659737..1937852fa333 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -45,6 +45,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
+import android.window.WindowContainerToken;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -410,6 +411,7 @@ public final class MediaProjectionManagerService extends SystemService
private IBinder mToken;
private IBinder.DeathRecipient mDeathEater;
private boolean mRestoreSystemAlertWindow;
+ private WindowContainerToken mTaskRecordingWindowContainerToken = null;
MediaProjection(int type, int uid, String packageName, int targetSdkVersion,
boolean isPrivileged) {
@@ -568,7 +570,7 @@ public final class MediaProjectionManagerService extends SystemService
}
}
- @Override
+ @Override // Binder call
public void registerCallback(IMediaProjectionCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
@@ -576,7 +578,7 @@ public final class MediaProjectionManagerService extends SystemService
mCallbackDelegate.add(callback);
}
- @Override
+ @Override // Binder call
public void unregisterCallback(IMediaProjectionCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
@@ -584,6 +586,17 @@ public final class MediaProjectionManagerService extends SystemService
mCallbackDelegate.remove(callback);
}
+ @Override // Binder call
+ public void setTaskRecordingWindowContainerToken(WindowContainerToken token) {
+ // TODO(b/221417940) set the task id to record from sysui, for the package chosen.
+ mTaskRecordingWindowContainerToken = token;
+ }
+
+ @Override // Binder call
+ public WindowContainerToken getTaskRecordingWindowContainerToken() {
+ return mTaskRecordingWindowContainerToken;
+ }
+
public MediaProjectionInfo getProjectionInfo() {
return new MediaProjectionInfo(packageName, userHandle);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 35f6a94f3ed6..57ffba70ba2e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -5421,6 +5421,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, enable);
mLogger.meteredAllowlistChanged(uid, enable);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setUidOnMeteredNetworkDenylist(sdkSandboxUid, enable);
+ mLogger.meteredAllowlistChanged(sdkSandboxUid, enable);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting denylist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5433,6 +5438,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, enable);
mLogger.meteredDenylistChanged(uid, enable);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setUidOnMeteredNetworkAllowlist(sdkSandboxUid, enable);
+ mLogger.meteredDenylistChanged(sdkSandboxUid, enable);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting allowlist (" + enable + ") rules for " + uid, e);
} catch (RemoteException e) {
@@ -5471,12 +5481,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void addSdkSandboxUidsIfNeeded(SparseIntArray uidRules) {
+ final int size = uidRules.size();
+ final SparseIntArray sdkSandboxUids = new SparseIntArray();
+ for (int index = 0; index < size; index++) {
+ final int uid = uidRules.keyAt(index);
+ final int rule = uidRules.valueAt(index);
+ if (Process.isApplicationUid(uid)) {
+ sdkSandboxUids.put(Process.toSdkSandboxUid(uid), rule);
+ }
+ }
+
+ for (int index = 0; index < sdkSandboxUids.size(); index++) {
+ final int uid = sdkSandboxUids.keyAt(index);
+ final int rule = sdkSandboxUids.valueAt(index);
+ uidRules.put(uid, rule);
+ }
+ }
+
/**
* Set uid rules on a particular firewall chain. This is going to synchronize the rules given
* here to netd. It will clean up dead rules and make sure the target chain only contains rules
* specified here.
*/
private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) {
+ addSdkSandboxUidsIfNeeded(uidRules);
try {
int size = uidRules.size();
int[] uids = new int[size];
@@ -5519,6 +5548,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try {
mNetworkManager.setFirewallUidRule(chain, uid, rule);
mLogger.uidFirewallRuleChanged(chain, uid, rule);
+ if (Process.isApplicationUid(uid)) {
+ final int sdkSandboxUid = Process.toSdkSandboxUid(uid);
+ mNetworkManager.setFirewallUidRule(chain, sdkSandboxUid, rule);
+ mLogger.uidFirewallRuleChanged(chain, sdkSandboxUid, rule);
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) {
@@ -5555,15 +5589,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
private void resetUidFirewallRules(int uid) {
try {
- mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, FIREWALL_RULE_DEFAULT);
- mNetworkManager
- .setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
- FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid,
+ FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid,
+ FIREWALL_RULE_DEFAULT);
mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false);
mLogger.meteredAllowlistChanged(uid, false);
mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false);
@@ -5573,6 +5608,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} catch (RemoteException e) {
// ignored; service lives in system_server
}
+ if (Process.isApplicationUid(uid)) {
+ resetUidFirewallRules(Process.toSdkSandboxUid(uid));
+ }
}
@Deprecated
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 9ff4aab83cff..d26a1ac4fba0 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -253,7 +253,8 @@ public final class BackgroundDexOptService {
*
* <p>This is only for shell command and only root or shell user can use this.
*
- * @param packageNames dex optimize the passed packages or all packages if null
+ * @param packageNames dex optimize the passed packages in the given order, or all packages in
+ * the default order if null
*
* @return true if dex optimization is complete. false if the task is cancelled or if there was
* an error.
@@ -268,11 +269,11 @@ public final class BackgroundDexOptService {
resetStatesForNewDexOptRunLocked(Thread.currentThread());
}
PackageManagerService pm = mInjector.getPackageManagerService();
- ArraySet<String> packagesToOptimize;
+ List<String> packagesToOptimize;
if (packageNames == null) {
packagesToOptimize = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
} else {
- packagesToOptimize = new ArraySet<>(packageNames);
+ packagesToOptimize = packageNames;
}
return runIdleOptimization(pm, packagesToOptimize, /* isPostBootUpdate= */ false);
} finally {
@@ -335,7 +336,7 @@ public final class BackgroundDexOptService {
return false;
}
- ArraySet<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
+ List<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
if (pkgs.isEmpty()) {
Slog.i(TAG, "No packages to optimize");
markPostBootUpdateCompleted(params);
@@ -525,7 +526,7 @@ public final class BackgroundDexOptService {
}
/** Returns true if completed */
- private boolean runIdleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
+ private boolean runIdleOptimization(PackageManagerService pm, List<String> pkgs,
boolean isPostBootUpdate) {
synchronized (mLock) {
mLastExecutionStartTimeMs = SystemClock.elapsedRealtime();
@@ -581,10 +582,9 @@ public final class BackgroundDexOptService {
}
@Status
- private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+ private int idleOptimizePackages(PackageManagerService pm, List<String> pkgs,
long lowStorageThreshold, boolean isPostBootUpdate) {
ArraySet<String> updatedPackages = new ArraySet<>();
- ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();
try {
boolean supportSecondaryDex = mInjector.supportSecondaryDex();
@@ -640,25 +640,12 @@ public final class BackgroundDexOptService {
}
}
- pkgs = new ArraySet<>(pkgs);
+ pkgs = new ArrayList<>(pkgs);
pkgs.removeAll(unusedPackages);
}
}
- @Status int primaryResult = optimizePackages(pkgs, lowStorageThreshold,
- /*isForPrimaryDex=*/ true, updatedPackages, isPostBootUpdate);
- if (primaryResult != STATUS_OK) {
- return primaryResult;
- }
-
- if (!supportSecondaryDex) {
- return STATUS_OK;
- }
-
- @Status int secondaryResult = optimizePackages(pkgs, lowStorageThreshold,
- /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex,
- isPostBootUpdate);
- return secondaryResult;
+ return optimizePackages(pkgs, lowStorageThreshold, updatedPackages, isPostBootUpdate);
} finally {
// Always let the pinner service know about changes.
notifyPinService(updatedPackages);
@@ -670,8 +657,10 @@ public final class BackgroundDexOptService {
}
@Status
- private int optimizePackages(ArraySet<String> pkgs, long lowStorageThreshold,
- boolean isForPrimaryDex, ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+ private int optimizePackages(List<String> pkgs, long lowStorageThreshold,
+ ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
+ boolean supportSecondaryDex = mInjector.supportSecondaryDex();
+
for (String pkg : pkgs) {
int abortCode = abortIdleOptimizations(lowStorageThreshold);
if (abortCode != STATUS_OK) {
@@ -679,11 +668,23 @@ public final class BackgroundDexOptService {
return abortCode;
}
- @DexOptResult int result = optimizePackage(pkg, isForPrimaryDex, isPostBootUpdate);
- if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+ @DexOptResult int primaryResult =
+ optimizePackage(pkg, true /* isForPrimaryDex */, isPostBootUpdate);
+ if (primaryResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
- } else if (result != PackageDexOptimizer.DEX_OPT_SKIPPED) {
- return convertPackageDexOptimizerStatusToInternal(result);
+ } else if (primaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+ return convertPackageDexOptimizerStatusToInternal(primaryResult);
+ }
+
+ if (!supportSecondaryDex) {
+ continue;
+ }
+
+ @DexOptResult int secondaryResult =
+ optimizePackage(pkg, false /* isForPrimaryDex */, isPostBootUpdate);
+ if (secondaryResult != PackageDexOptimizer.DEX_OPT_PERFORMED
+ && secondaryResult != PackageDexOptimizer.DEX_OPT_SKIPPED) {
+ return convertPackageDexOptimizerStatusToInternal(secondaryResult);
}
}
return STATUS_OK;
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 50b2e2321886..bb2ba5cc498d 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -293,8 +293,8 @@ final class DexOptHelper {
MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds);
}
- public ArraySet<String> getOptimizablePackages(@NonNull Computer snapshot) {
- ArraySet<String> pkgs = new ArraySet<>();
+ public List<String> getOptimizablePackages(@NonNull Computer snapshot) {
+ ArrayList<String> pkgs = new ArrayList<>();
mPm.forEachPackageState(snapshot, packageState -> {
final AndroidPackage pkg = packageState.getPkg();
if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) {
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 91750dee7688..15f26e7a6d6c 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -32,6 +32,7 @@ import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_CHECK_MAX_SDK_VERSION;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.os.Environment;
@@ -61,14 +62,24 @@ import java.util.concurrent.ExecutorService;
* further cleanup and eventually all the installation/scanning related logic will go to another
* class.
*/
-final class InitAndSystemPackageHelper {
+final class InitAppsHelper {
private final PackageManagerService mPm;
-
private final List<ScanPartition> mDirsToScanAsSystem;
private final int mScanFlags;
private final int mSystemParseFlags;
private final int mSystemScanFlags;
private final InstallPackageHelper mInstallPackageHelper;
+ private final ApexManager mApexManager;
+ private final ExecutorService mExecutorService;
+ /* Tracks how long system scan took */
+ private long mSystemScanTime;
+ /* Track of the number of cached system apps */
+ private int mCachedSystemApps;
+ /* Track of the number of system apps */
+ private int mSystemPackagesCount;
+ private final boolean mIsDeviceUpgrading;
+ private final boolean mIsOnlyCoreApps;
+ private final List<ScanPartition> mSystemPartitions;
/**
* Tracks new system packages [received in an OTA] that we expect to
@@ -76,21 +87,33 @@ final class InitAndSystemPackageHelper {
* are package location.
*/
private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
+ /* Tracks of any system packages that no longer exist that needs to be pruned. */
+ private final List<String> mPossiblyDeletedUpdatedSystemApps = new ArrayList<>();
+ // Tracks of stub packages that must either be replaced with full versions in the /data
+ // partition or be disabled.
+ private final List<String> mStubSystemApps = new ArrayList<>();
// TODO(b/198166813): remove PMS dependency
- InitAndSystemPackageHelper(PackageManagerService pm) {
+ InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
+ InstallPackageHelper installPackageHelper,
+ List<ScanPartition> systemPartitions) {
mPm = pm;
- mInstallPackageHelper = new InstallPackageHelper(pm);
+ mApexManager = apexManager;
+ mInstallPackageHelper = installPackageHelper;
+ mSystemPartitions = systemPartitions;
mDirsToScanAsSystem = getSystemScanPartitions();
+ mIsDeviceUpgrading = mPm.isDeviceUpgrading();
+ mIsOnlyCoreApps = mPm.isOnlyCoreApps();
// Set flag to monitor and not change apk file paths when scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
- if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()) {
+ if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
} else {
mScanFlags = scanFlags;
}
mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
+ mExecutorService = ParallelPackageParser.makeExecutorService();
}
private List<File> getFrameworkResApkSplitFiles() {
@@ -118,7 +141,7 @@ final class InitAndSystemPackageHelper {
private List<ScanPartition> getSystemScanPartitions() {
final List<ScanPartition> scanPartitions = new ArrayList<>();
- scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
+ scanPartitions.addAll(mSystemPartitions);
scanPartitions.addAll(getApexScanPartitions());
Slog.d(TAG, "Directories scanned as system partitions: " + scanPartitions);
return scanPartitions;
@@ -126,8 +149,7 @@ final class InitAndSystemPackageHelper {
private List<ScanPartition> getApexScanPartitions() {
final List<ScanPartition> scanPartitions = new ArrayList<>();
- final List<ApexManager.ActiveApexInfo> activeApexInfos =
- mPm.mApexManager.getActiveApexInfos();
+ final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos();
for (int i = 0; i < activeApexInfos.size(); i++) {
final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
if (scanPartition != null) {
@@ -144,117 +166,134 @@ final class InitAndSystemPackageHelper {
if (apexInfo.preInstalledApexPath.getAbsolutePath().equals(
sp.getFolder().getAbsolutePath())
|| apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
- sp.getFolder().getAbsolutePath() + File.separator)) {
+ sp.getFolder().getAbsolutePath() + File.separator)) {
return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
}
}
return null;
}
- public OverlayConfig initPackages(
- WatchedArrayMap<String, PackageSetting> packageSettings, int[] userIds,
- long startTime) {
- PackageParser2 packageParser = mPm.mInjector.getScanningCachingPackageParser();
-
- ExecutorService executorService = ParallelPackageParser.makeExecutorService();
+ /**
+ * Install apps from system dirs.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ public OverlayConfig initSystemApps(PackageParser2 packageParser,
+ WatchedArrayMap<String, PackageSetting> packageSettings,
+ int[] userIds, long startTime) {
// Prepare apex package info before scanning APKs, this information is needed when
// scanning apk in apex.
- mPm.mApexManager.scanApexPackagesTraced(packageParser, executorService);
+ mApexManager.scanApexPackagesTraced(packageParser, mExecutorService);
- scanSystemDirs(packageParser, executorService);
+ scanSystemDirs(packageParser, mExecutorService);
// Parse overlay configuration files to set default enable state, mutability, and
// priority of system overlays.
final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>();
- for (ApexManager.ActiveApexInfo apexInfo : mPm.mApexManager.getActiveApexInfos()) {
- for (String packageName : mPm.mApexManager.getApksInApex(apexInfo.apexModuleName)) {
+ for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {
+ for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) {
apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);
}
}
- OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
+ final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
consumer -> mPm.forEachPackage(mPm.snapshotComputer(),
pkg -> consumer.accept(pkg, pkg.isSystem(),
- apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
- // Prune any system packages that no longer exist.
- final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
- // Stub packages must either be replaced with full versions in the /data
- // partition or be disabled.
- final List<String> stubSystemApps = new ArrayList<>();
-
- if (!mPm.isOnlyCoreApps()) {
+ apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
+
+ if (!mIsOnlyCoreApps) {
// do this first before mucking with mPackages for the "expecting better" case
- updateStubSystemAppsList(stubSystemApps);
+ updateStubSystemAppsList(mStubSystemApps);
mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
- possiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
+ mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
}
- final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
+ logSystemAppsScanningTime(startTime);
+ return overlayConfig;
+ }
+
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void logSystemAppsScanningTime(long startTime) {
+ mCachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
// Remove any shared userIDs that have no associated packages
mPm.mSettings.pruneSharedUsersLPw();
- final long systemScanTime = SystemClock.uptimeMillis() - startTime;
- final int systemPackagesCount = mPm.mPackages.size();
- Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
- + " ms, packageCount: " + systemPackagesCount
+ mSystemScanTime = SystemClock.uptimeMillis() - startTime;
+ mSystemPackagesCount = mPm.mPackages.size();
+ Slog.i(TAG, "Finished scanning system apps. Time: " + mSystemScanTime
+ + " ms, packageCount: " + mSystemPackagesCount
+ " , timePerPackage: "
- + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
- + " , cached: " + cachedSystemApps);
- if (mPm.isDeviceUpgrading() && systemPackagesCount > 0) {
+ + (mSystemPackagesCount == 0 ? 0 : mSystemScanTime / mSystemPackagesCount)
+ + " , cached: " + mCachedSystemApps);
+ if (mIsDeviceUpgrading && mSystemPackagesCount > 0) {
//CHECKSTYLE:OFF IndentationCheck
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
- systemScanTime / systemPackagesCount);
+ mSystemScanTime / mSystemPackagesCount);
//CHECKSTYLE:ON IndentationCheck
}
+ }
- if (!mPm.isOnlyCoreApps()) {
+ /**
+ * Install apps/updates from data dir and fix system apps that are affected.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ public void initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds,
+ long startTime) {
+ if (!mIsOnlyCoreApps) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
- mScanFlags | SCAN_REQUIRE_KNOWN, 0,
- packageParser, executorService);
-
+ mScanFlags | SCAN_REQUIRE_KNOWN,
+ packageParser, mExecutorService);
}
- List<Runnable> unfinishedTasks = executorService.shutdownNow();
+ List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
throw new IllegalStateException("Not all tasks finished before calling close: "
+ unfinishedTasks);
}
-
- if (!mPm.isOnlyCoreApps()) {
- mInstallPackageHelper.cleanupDisabledPackageSettings(possiblyDeletedUpdatedSystemApps,
- userIds, mScanFlags);
- mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
- stubSystemApps, mSystemScanFlags, mSystemParseFlags);
-
- // Uncompress and install any stubbed system applications.
- // This must be done last to ensure all stubs are replaced or disabled.
- mInstallPackageHelper.installSystemStubPackages(stubSystemApps, mScanFlags);
-
- final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
- - cachedSystemApps;
-
- final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
- final int dataPackagesCount = mPm.mPackages.size() - systemPackagesCount;
- Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
- + " ms, packageCount: " + dataPackagesCount
- + " , timePerPackage: "
- + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
- + " , cached: " + cachedNonSystemApps);
- if (mPm.isDeviceUpgrading() && dataPackagesCount > 0) {
- //CHECKSTYLE:OFF IndentationCheck
- FrameworkStatsLog.write(
- FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
- BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
- dataScanTime / dataPackagesCount);
- //CHECKSTYLE:OFF IndentationCheck
- }
+ if (!mIsOnlyCoreApps) {
+ fixSystemPackages(userIds);
+ logNonSystemAppScanningTime(startTime);
}
mExpectingBetter.clear();
-
mPm.mSettings.pruneRenamedPackagesLPw();
- packageParser.close();
- return overlayConfig;
+ }
+
+ /**
+ * Clean up system packages now that some system package updates have been installed from
+ * the data dir. Also install system stub packages as the last step.
+ */
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void fixSystemPackages(@NonNull int[] userIds) {
+ mInstallPackageHelper.cleanupDisabledPackageSettings(mPossiblyDeletedUpdatedSystemApps,
+ userIds, mScanFlags);
+ mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
+ mStubSystemApps, mSystemScanFlags, mSystemParseFlags);
+
+ // Uncompress and install any stubbed system applications.
+ // This must be done last to ensure all stubs are replaced or disabled.
+ mInstallPackageHelper.installSystemStubPackages(mStubSystemApps, mScanFlags);
+ }
+
+ @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
+ private void logNonSystemAppScanningTime(long startTime) {
+ final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
+ - mCachedSystemApps;
+
+ final long dataScanTime = SystemClock.uptimeMillis() - mSystemScanTime - startTime;
+ final int dataPackagesCount = mPm.mPackages.size() - mSystemPackagesCount;
+ Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+ + " ms, packageCount: " + dataPackagesCount
+ + " , timePerPackage: "
+ + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+ + " , cached: " + cachedNonSystemApps);
+ if (mIsDeviceUpgrading && dataPackagesCount > 0) {
+ //CHECKSTYLE:OFF IndentationCheck
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+ BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+ dataScanTime / dataPackagesCount);
+ //CHECKSTYLE:OFF IndentationCheck
+ }
}
/**
@@ -274,13 +313,13 @@ final class InitAndSystemPackageHelper {
continue;
}
scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null,
- mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+ mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService);
}
scanDirTracedLI(frameworkDir, null,
mSystemParseFlags,
- mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
+ mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
packageParser, executorService);
if (!mPm.mPackages.containsKey("android")) {
throw new IllegalStateException(
@@ -292,11 +331,11 @@ final class InitAndSystemPackageHelper {
if (partition.getPrivAppFolder() != null) {
scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null,
mSystemParseFlags,
- mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
+ mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
packageParser, executorService);
}
scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null,
- mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
+ mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService);
}
}
@@ -315,7 +354,7 @@ final class InitAndSystemPackageHelper {
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirTracedLI(File scanDir, List<File> frameworkSplits,
int parseFlags, int scanFlags,
- long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
+ PackageParser2 packageParser, ExecutorService executorService) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
@@ -323,7 +362,7 @@ final class InitAndSystemPackageHelper {
parseFlags |= PARSE_CHECK_MAX_SDK_VERSION;
}
mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
- scanFlags, currentTime, packageParser, executorService);
+ scanFlags, packageParser, executorService);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index b39b24f6defa..870a11ac2d61 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -3062,7 +3062,7 @@ final class InstallPackageHelper {
final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
removePackageHelper.removePackageLI(stubPkg, true /*chatty*/);
try {
- return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+ return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
e);
@@ -3194,7 +3194,7 @@ final class InstallPackageHelper {
| ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
@PackageManagerService.ScanFlags int scanFlags = mPm.getSystemPackageScanFlags(codePath);
final AndroidPackage pkg = scanSystemPackageTracedLI(
- codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
+ codePath, parseFlags, scanFlags, null);
PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -3368,7 +3368,7 @@ final class InstallPackageHelper {
mRemovePackageHelper.removePackageLI(pkg, true);
try {
final File codePath = new File(pkg.getPath());
- scanSystemPackageTracedLI(codePath, 0, scanFlags, 0, null);
+ scanSystemPackageTracedLI(codePath, 0, scanFlags, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ e.getMessage());
@@ -3389,7 +3389,7 @@ final class InstallPackageHelper {
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
- int scanFlags, long currentTime, PackageParser2 packageParser,
+ int scanFlags, PackageParser2 packageParser,
ExecutorService executorService) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
@@ -3432,7 +3432,7 @@ final class InstallPackageHelper {
parseResult.parsedPackage);
}
try {
- addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime,
+ addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
null);
} catch (PackageManagerException e) {
errorCode = e.error;
@@ -3495,7 +3495,7 @@ final class InstallPackageHelper {
try {
final AndroidPackage newPkg = scanSystemPackageTracedLI(
- scanFile, reparseFlags, rescanFlags, 0, null);
+ scanFile, reparseFlags, rescanFlags, null);
// We rescanned a stub, add it to the list of stubbed system packages
if (newPkg.isStub()) {
stubSystemApps.add(packageName);
@@ -3509,14 +3509,14 @@ final class InstallPackageHelper {
/**
* Traces a package scan.
- * @see #scanSystemPackageLI(File, int, int, long, UserHandle)
+ * @see #scanSystemPackageLI(File, int, int, UserHandle)
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags,
- int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
+ int scanFlags, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
try {
- return scanSystemPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
+ return scanSystemPackageLI(scanFile, parseFlags, scanFlags, user);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -3528,7 +3528,7 @@ final class InstallPackageHelper {
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags,
- long currentTime, UserHandle user) throws PackageManagerException {
+ UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
@@ -3544,7 +3544,7 @@ final class InstallPackageHelper {
PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
}
- return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
+ return addForInitLI(parsedPackage, parseFlags, scanFlags, user);
}
/**
@@ -3563,11 +3563,11 @@ final class InstallPackageHelper {
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
- @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+ @PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user) throws PackageManagerException {
final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
- parsedPackage, parseFlags, scanFlags, currentTime, user);
+ parsedPackage, parseFlags, scanFlags, user);
final ScanResult scanResult = scanResultPair.first;
boolean shouldHideSystemApp = scanResultPair.second;
if (scanResult.mSuccess) {
@@ -3762,7 +3762,7 @@ final class InstallPackageHelper {
private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
- @PackageManagerService.ScanFlags int scanFlags, long currentTime,
+ @PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user) throws PackageManagerException {
final boolean scanSystemPartition =
(parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
@@ -3950,7 +3950,7 @@ final class InstallPackageHelper {
}
final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags,
- scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
+ scanFlags | SCAN_UPDATE_SIGNATURE, 0 /* currentTime */, user, null);
return new Pair<>(scanResult, shouldHideSystemApp);
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 5902f487d353..45c5116bea59 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -89,6 +89,14 @@ public class Installer extends SystemService {
*/
public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3;
+ /**
+ * The results of {@code getOdexVisibility}. See
+ * {@link #getOdexVisibility(String, String, String)} for details.
+ */
+ public static final int ODEX_NOT_FOUND = 0;
+ public static final int ODEX_IS_PUBLIC = 1;
+ public static final int ODEX_IS_PRIVATE = 2;
+
public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
@@ -866,6 +874,15 @@ public class Installer extends SystemService {
}
}
+ /**
+ * Prepares the app profile for the package at the given path:
+ * <ul>
+ * <li>Creates the current profile for the given user ID, unless the user ID is
+ * {@code UserHandle.USER_NULL}.</li>
+ * <li>Merges the profile from the dex metadata file (if present) into the reference
+ * profile.</li>
+ * </ul>
+ */
public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
String profileName, String codePath, String dexMetadataPath) throws InstallerException {
if (!checkBeforeRemote()) return false;
@@ -1016,6 +1033,33 @@ public class Installer extends SystemService {
}
}
+ /**
+ * Returns the visibility of the optimized artifacts.
+ *
+ * @param packageName name of the package.
+ * @param apkPath path to the APK.
+ * @param instructionSet instruction set of the optimized artifacts.
+ * @param outputPath path to the directory that contains the optimized artifacts (i.e., the
+ * directory that {@link #dexopt} outputs to).
+ *
+ * @return {@link #ODEX_NOT_FOUND} if the optimized artifacts are not found, or
+ * {@link #ODEX_IS_PUBLIC} if the optimized artifacts are accessible by all apps, or
+ * {@link #ODEX_IS_PRIVATE} if the optimized artifacts are only accessible by this app.
+ *
+ * @throws InstallerException if failed to get the visibility of the optimized artifacts.
+ */
+ public int getOdexVisibility(String packageName, String apkPath, String instructionSet,
+ String outputPath) throws InstallerException {
+ if (!checkBeforeRemote()) return -1;
+ BlockGuard.getVmPolicy().onPathAccess(apkPath);
+ BlockGuard.getVmPolicy().onPathAccess(outputPath);
+ try {
+ return mInstalld.getOdexVisibility(packageName, apkPath, instructionSet, outputPath);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
public static class InstallerException extends Exception {
public InstallerException(String detailMessage) {
super(detailMessage);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 69d498794e64..27c6d9bec2e8 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -319,28 +319,42 @@ public class PackageDexOptimizer {
String profileName = ArtManager.getProfileName(
i == 0 ? null : pkg.getSplitNames()[i - 1]);
+ final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
+ || packageUseInfo.isUsedByOtherApps(path);
+ String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter());
+ // If the app is used by other apps, we must not use the existing profile because it
+ // may contain user data, unless the profile is newly created on install.
+ final boolean resetProfile = isProfileGuidedCompilerFilter(compilerFilter)
+ && isUsedByOtherApps
+ && options.getCompilationReason() != PackageManagerService.REASON_INSTALL;
String dexMetadataPath = null;
- if (options.isDexoptInstallWithDexMetadata()) {
+ if (options.isDexoptInstallWithDexMetadata() || resetProfile) {
File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path));
dexMetadataPath = dexMetadataFile == null
? null : dexMetadataFile.getAbsolutePath();
}
- final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
- || packageUseInfo.isUsedByOtherApps(path);
- final String compilerFilter = getRealCompilerFilter(pkg,
- options.getCompilerFilter(), isUsedByOtherApps);
// If we don't have to check for profiles updates assume
// PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA which will be a no-op with respect to
// profiles.
- final int profileAnalysisResult = options.isCheckForProfileUpdates()
- ? analyseProfiles(pkg, sharedGid, profileName, compilerFilter)
- : PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
+ int profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
+ if (resetProfile) {
+ if (!resetProfile(pkg, profileName, path, dexMetadataPath)) {
+ // Fall back to use the shared filter.
+ compilerFilter =
+ PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+ PackageManagerService.REASON_SHARED);
+ }
+ } else if (options.isCheckForProfileUpdates()) {
+ profileAnalysisResult =
+ analyseProfiles(pkg, sharedGid, profileName, compilerFilter);
+ }
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
// flags.
- final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, options);
+ final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, resetProfile,
+ options);
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,
@@ -391,6 +405,30 @@ public class PackageDexOptimizer {
}
/**
+ * Resets the profiles of the dex file at {@code path} belonging to the package {@code pkg} to
+ * the initial state as if the package is newly installed. Returns true on success, or false
+ * otherwise.
+ */
+ @GuardedBy("mInstallLock")
+ private boolean resetProfile(AndroidPackage pkg, String profileName, String path,
+ @Nullable String dexMetadataPath) {
+ if (dexMetadataPath != null) {
+ try {
+ mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
+ final int appId = UserHandle.getAppId(pkg.getUid());
+ mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL,
+ appId, profileName, path, dexMetadataPath);
+ return true;
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to reset profile", e);
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /**
* Performs dexopt on the {@code path} belonging to the package {@code pkg}.
*
* @return
@@ -405,15 +443,15 @@ public class PackageDexOptimizer {
String classLoaderContext, int dexoptFlags, int uid,
CompilerStats.PackageStats packageStats, boolean downgrade, String profileName,
String dexMetadataPath, int compilationReason) {
- int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
- profileAnalysisResult, downgrade);
+ String oatDir = getPackageOatDirIfSupported(pkg,
+ pkgSetting.getTransientState().isUpdatedSystemApp());
+
+ int dexoptNeeded = getDexoptNeeded(pkg.getPackageName(), path, isa, compilerFilter,
+ classLoaderContext, profileAnalysisResult, downgrade, dexoptFlags, oatDir);
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
return DEX_OPT_SKIPPED;
}
- String oatDir = getPackageOatDirIfSupported(pkg,
- pkgSetting.getTransientState().isUpdatedSystemApp());
-
Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
+ " pkg=" + pkg.getPackageName() + " isa=" + isa
+ " dexoptFlags=" + printDexoptFlags(dexoptFlags)
@@ -456,6 +494,7 @@ public class PackageDexOptimizer {
/**
* Perform dexopt (if needed) on a system server code path).
*/
+ @GuardedBy("mInstallLock")
@DexOptResult
public int dexoptSystemServerPath(
String dexPath, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
@@ -466,12 +505,15 @@ public class PackageDexOptimizer {
int result = DEX_OPT_SKIPPED;
for (String isa : dexUseInfo.getLoaderIsas()) {
int dexoptNeeded = getDexoptNeeded(
+ PackageManagerService.PLATFORM_PACKAGE_NAME,
dexPath,
isa,
options.getCompilerFilter(),
dexUseInfo.getClassLoaderContext(),
PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES,
- /* downgrade= */ false);
+ /* downgrade= */ false,
+ dexoptFlags,
+ /* oatDir= */ null);
if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
continue;
@@ -714,7 +756,7 @@ public class PackageDexOptimizer {
}
/**
- * Returns the compiler filter that should be used to optimize the package code.
+ * Returns the compiler filter that should be used to optimize the secondary dex.
* The target filter will be updated if the package code is used by other apps
* or if it has the safe mode flag set.
*/
@@ -754,12 +796,12 @@ public class PackageDexOptimizer {
}
/**
- * Returns the compiler filter that should be used to optimize the package code.
- * The target filter will be updated if the package code is used by other apps
- * or if it has the safe mode flag set.
+ * Returns the compiler filter that should be used to optimize the primary dex.
+ * The target filter will be updated if the package has the safe mode flag set. Note that this
+ * method does NOT take other app use into account. The caller should be responsible for
+ * handling the case where the package code is used by other apps.
*/
- private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter,
- boolean isUsedByOtherApps) {
+ private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter) {
// When an app or priv app is configured to run out of box, only verify it.
if (pkg.isUseEmbeddedDex()
|| (pkg.isPrivileged()
@@ -783,12 +825,6 @@ public class PackageDexOptimizer {
return getSafeModeCompilerFilter(targetCompilerFilter);
}
- if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
- // If the dex files is used by other apps, apply the shared filter.
- return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_SHARED);
- }
-
return targetCompilerFilter;
}
@@ -799,14 +835,16 @@ public class PackageDexOptimizer {
private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0,
info.getHiddenApiEnforcementPolicy(), info.splitDependencies,
- info.requestsIsolatedSplitLoading(), compilerFilter, options);
+ info.requestsIsolatedSplitLoading(), compilerFilter, false /* resetProfile */,
+ options);
}
+
private int getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting,
- String compilerFilter, DexoptOptions options) {
+ String compilerFilter, boolean resetProfile, DexoptOptions options) {
return getDexFlags(pkg.isDebuggable(),
AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting),
pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter,
- options);
+ resetProfile, options);
}
/**
@@ -815,13 +853,15 @@ public class PackageDexOptimizer {
*/
private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy,
SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
- String compilerFilter, DexoptOptions options) {
+ String compilerFilter, boolean resetProfile, DexoptOptions options) {
// Profile guide compiled oat files should not be public unles they are based
// on profiles from dex metadata archives.
// The flag isDexoptInstallWithDexMetadata applies only on installs when we know that
// the user does not have an existing profile.
+ // The flag resetProfile applies only when the existing profile is already reset.
boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
- boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata();
+ boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata()
+ || resetProfile;
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
// Some apps are executed with restrictions on hidden API usage. If this app is one
// of them, pass a flag to dexopt to enable the same restrictions during compilation.
@@ -866,8 +906,19 @@ public class PackageDexOptimizer {
* Assesses if there's a need to perform dexopt on {@code path} for the given
* configuration (isa, compiler filter, profile).
*/
- private int getDexoptNeeded(String path, String isa, String compilerFilter,
- String classLoaderContext, int profileAnalysisResult, boolean downgrade) {
+ @GuardedBy("mInstallLock")
+ private int getDexoptNeeded(String packageName, String path, String isa, String compilerFilter,
+ String classLoaderContext, int profileAnalysisResult, boolean downgrade,
+ int dexoptFlags, String oatDir) {
+ final boolean shouldBePublic = (dexoptFlags & DEXOPT_PUBLIC) != 0;
+ // If the artifacts should be public while the current artifacts are not, we should
+ // re-compile anyway.
+ if (shouldBePublic && isOdexPrivate(packageName, path, isa, oatDir)) {
+ // Ensure compilation by pretending a compiler filter change on the apk/odex location
+ // (the reason for the '-'. A positive value means the 'oat' location).
+ return adjustDexoptNeeded(-DexFile.DEX2OAT_FOR_FILTER);
+ }
+
int dexoptNeeded;
try {
// A profile guided optimizations with an empty profile is essentially 'verify' and
@@ -901,6 +952,18 @@ public class PackageDexOptimizer {
return compilerFilter.endsWith("-profile");
}
+ /** Returns true if the current artifacts of the app are private to the app itself. */
+ @GuardedBy("mInstallLock")
+ private boolean isOdexPrivate(String packageName, String path, String isa, String oatDir) {
+ try {
+ return mInstaller.getOdexVisibility(packageName, path, isa, oatDir)
+ == Installer.ODEX_IS_PRIVATE;
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to get odex visibility for " + path, e);
+ return false;
+ }
+ }
+
/**
* Checks if there is an update on the profile information of the {@code pkg}.
* If the compiler filter is not profile guided the method returns a safe default:
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index eaecb17103a5..b1b05bedfcad 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -229,7 +229,6 @@ import com.android.server.pm.resolution.ComponentResolverApi;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
-import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
import com.android.server.sdksandbox.SdkSandboxManagerLocal;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.SnapshotCache;
@@ -936,7 +935,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
private final BroadcastHelper mBroadcastHelper;
private final RemovePackageHelper mRemovePackageHelper;
private final DeletePackageHelper mDeletePackageHelper;
- private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
+ private final InitAppsHelper mInitAppsHelper;
private final AppDataHelper mAppDataHelper;
private final InstallPackageHelper mInstallPackageHelper;
private final PreferredActivityHelper mPreferredActivityHelper;
@@ -1671,7 +1670,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mAppDataHelper = testParams.appDataHelper;
mInstallPackageHelper = testParams.installPackageHelper;
mRemovePackageHelper = testParams.removePackageHelper;
- mInitAndSystemPackageHelper = testParams.initAndSystemPackageHelper;
+ mInitAppsHelper = testParams.initAndSystemPackageHelper;
mDeletePackageHelper = testParams.deletePackageHelper;
mPreferredActivityHelper = testParams.preferredActivityHelper;
mResolveIntentHelper = testParams.resolveIntentHelper;
@@ -1821,7 +1820,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mAppDataHelper = new AppDataHelper(this);
mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
- mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this);
+ mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
+ mInjector.getSystemPartitions());
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mAppDataHelper);
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1956,8 +1956,11 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);
final int[] userIds = mUserManager.getUserIds();
- mOverlayConfig = mInitAndSystemPackageHelper.initPackages(packageSettings,
- userIds, startTime);
+ PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
+ mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
+ startTime);
+ mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);
+ packageParser.close();
// Resolve the storage manager.
mStorageManagerPackage = getStorageManagerPackageName(computer);
@@ -7030,7 +7033,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
boolean isExpectingBetter(String packageName) {
- return mInitAndSystemPackageHelper.isExpectingBetter(packageName);
+ return mInitAppsHelper.isExpectingBetter(packageName);
}
int getDefParseFlags() {
@@ -7129,13 +7132,12 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
boolean isOverlayMutable(String packageName) {
- return (mOverlayConfig != null ? mOverlayConfig
- : OverlayConfig.getSystemInstance()).isMutable(packageName);
+ return mOverlayConfig.isMutable(packageName);
}
@ScanFlags int getSystemPackageScanFlags(File codePath) {
List<ScanPartition> dirsToScanAsSystem =
- mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+ mInitAppsHelper.getDirsToScanAsSystem();
@PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
ScanPartition partition = dirsToScanAsSystem.get(i);
@@ -7153,7 +7155,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
Pair<Integer, Integer> getSystemPackageRescanFlagsAndReparseFlags(File scanFile,
int systemScanFlags, int systemParseFlags) {
List<ScanPartition> dirsToScanAsSystem =
- mInitAndSystemPackageHelper.getDirsToScanAsSystem();
+ mInitAppsHelper.getDirsToScanAsSystem();
@ParsingPackageUtils.ParseFlags int reparseFlags = 0;
@PackageManagerService.ScanFlags int rescanFlags = 0;
for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 5bdda0b3c1d8..e466fe2c0e31 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -109,7 +109,7 @@ public final class PackageManagerServiceTestParams {
public AppDataHelper appDataHelper;
public InstallPackageHelper installPackageHelper;
public RemovePackageHelper removePackageHelper;
- public InitAndSystemPackageHelper initAndSystemPackageHelper;
+ public InitAppsHelper initAndSystemPackageHelper;
public DeletePackageHelper deletePackageHelper;
public PreferredActivityHelper preferredActivityHelper;
public ResolveIntentHelper resolveIntentHelper;
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 8921fee6c8e0..c8f809b6782f 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1827,9 +1827,9 @@ class ShortcutPackage extends ShortcutPackageItem {
ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras());
final Map<String, Map<String, List<String>>> capabilityBindings =
- si.getCapabilityBindings();
+ si.getCapabilityBindingsInternal();
if (capabilityBindings != null && !capabilityBindings.isEmpty()) {
- XmlUtils.writeMapXml(si.getCapabilityBindings(), NAME_CAPABILITY, out);
+ XmlUtils.writeMapXml(capabilityBindings, NAME_CAPABILITY, out);
}
}
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index df19d3e58bfd..a991ed3c4792 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -151,7 +151,7 @@ public final class StorageEventHelper extends StorageEventListener {
final AndroidPackage pkg;
try {
pkg = installPackageHelper.scanSystemPackageTracedLI(
- ps.getPath(), parseFlags, SCAN_INITIAL, 0, null);
+ ps.getPath(), parseFlags, SCAN_INITIAL, null);
loaded.add(pkg);
} catch (PackageManagerException e) {
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 9c74dd795d30..88a298a756d4 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -52,6 +52,9 @@
"options": [
{
"include-filter": "com.google.android.security.gts.PackageVerifierTest"
+ },
+ {
+ "exclude-filter": "com.google.android.security.gts.PackageVerifierTest#testAdbInstall_timeout_allowed"
}
]
},
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 34b7ad41e540..70053bdeb47e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -5409,6 +5409,21 @@ public class UserManagerService extends IUserManager.Stub {
(new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
}
+ private static final String PREFIX_HELP_COMMAND = " ";
+ private static final String PREFIX_HELP_DESCRIPTION = " ";
+ private static final String PREFIX_HELP_DESCRIPTION_EXTRA_LINES = " ";
+
+ private static final String CMD_HELP = "help";
+ private static final String CMD_LIST = "list";
+ private static final String CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS =
+ "report-system-user-package-whitelist-problems";
+
+ private static final String ARG_V = "-v";
+ private static final String ARG_VERBOSE = "--verbose";
+ private static final String ARG_ALL = "--all";
+ private static final String ARG_CRITICAL_ONLY = "--critical-only";
+ private static final String ARG_MODE = "--mode";
+
private int onShellCommand(Shell shell, String cmd) {
if (cmd == null) {
return shell.handleDefaultCommands(cmd);
@@ -5417,9 +5432,9 @@ public class UserManagerService extends IUserManager.Stub {
final PrintWriter pw = shell.getOutPrintWriter();
try {
switch(cmd) {
- case "list":
+ case CMD_LIST:
return runList(pw, shell);
- case "report-system-user-package-whitelist-problems":
+ case CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS:
return runReportPackageWhitelistProblems(pw, shell);
default:
return shell.handleDefaultCommands(cmd);
@@ -5436,10 +5451,10 @@ public class UserManagerService extends IUserManager.Stub {
String opt;
while ((opt = shell.getNextOption()) != null) {
switch (opt) {
- case "-v":
+ case ARG_V:
verbose = true;
break;
- case "--all":
+ case ARG_ALL:
all = true;
break;
default:
@@ -5520,14 +5535,14 @@ public class UserManagerService extends IUserManager.Stub {
String opt;
while ((opt = shell.getNextOption()) != null) {
switch (opt) {
- case "-v":
- case "--verbose":
+ case ARG_V:
+ case ARG_VERBOSE:
verbose = true;
break;
- case "--critical-only":
+ case ARG_CRITICAL_ONLY:
criticalOnly = true;
break;
- case "--mode":
+ case ARG_MODE:
mode = Integer.parseInt(shell.getNextArgRequired());
break;
default:
@@ -6248,20 +6263,28 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
- pw.println("User manager (user) commands:");
- pw.println(" help");
- pw.println(" Prints this help text.");
- pw.println("");
- pw.println(" list [-v] [-all]");
- pw.println(" Prints all users on the system.");
- pw.println(" report-system-user-package-whitelist-problems [-v | --verbose] "
- + "[--critical-only] [--mode MODE]");
- pw.println(" Reports all issues on user-type package whitelist XML files. Options:");
- pw.println(" -v | --verbose : shows extra info, like number of issues");
- pw.println(" --critical-only: show only critical issues, excluding warnings");
- pw.println(" --mode MODE: shows what errors would be if device used mode MODE (where"
- + " MODE is the whitelist mode integer as defined by "
- + "config_userTypePackageWhitelistMode)");
+ pw.printf("User manager (user) commands:\n");
+
+ pw.printf("%s%s\n", PREFIX_HELP_COMMAND, CMD_HELP);
+ pw.printf("%sPrints this help text.\n\n", PREFIX_HELP_DESCRIPTION);
+
+ pw.printf("%s%s [%s] [%s]\n", PREFIX_HELP_COMMAND, CMD_LIST, ARG_V, ARG_ALL);
+ pw.printf("%sPrints all users on the system.\n\n", PREFIX_HELP_DESCRIPTION);
+
+ pw.printf("%s%s [%s | %s] [%s] [%s MODE]\n", PREFIX_HELP_COMMAND,
+ CMD_REPORT_SYSTEM_USER_PACKAGE_ALLOWLIST_PROBLEMS,
+ ARG_V, ARG_VERBOSE, ARG_CRITICAL_ONLY, ARG_MODE);
+
+ pw.printf("%sReports all issues on user-type package allowlist XML files. Options:\n",
+ PREFIX_HELP_DESCRIPTION);
+ pw.printf("%s%s | %s: shows extra info, like number of issues\n",
+ PREFIX_HELP_DESCRIPTION, ARG_V, ARG_VERBOSE);
+ pw.printf("%s%s: show only critical issues, excluding warnings\n",
+ PREFIX_HELP_DESCRIPTION, ARG_CRITICAL_ONLY);
+ pw.printf("%s%s MODE: shows what errors would be if device used mode MODE\n"
+ + "%s(where MODE is the allowlist mode integer as defined by "
+ + "config_userTypePackageWhitelistMode)\n\n",
+ PREFIX_HELP_DESCRIPTION, ARG_MODE, PREFIX_HELP_DESCRIPTION_EXTRA_LINES);
}
}
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 46fde4b59d8b..60602337ba1a 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -272,6 +272,10 @@ public class OneTimePermissionUserManager {
mHandler.removeCallbacksAndMessages(mToken);
if (importance > IMPORTANCE_CACHED) {
+ if (mRevokeAfterKilledDelay == 0) {
+ onPackageInactiveLocked();
+ return;
+ }
// Delay revocation in case app is restarting
mHandler.postDelayed(() -> {
int imp = mActivityManager.getUidImportance(mUid);
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 71554eee3127..5a05134bed81 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -562,12 +562,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
- public void revokeOwnPermissionsOnKill(@NonNull String packageName,
- @NonNull List<String> permissions) {
- mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
- }
-
- @Override
public boolean shouldShowRequestPermissionRationale(String packageName, String permissionName,
int userId) {
return mPermissionManagerServiceImpl.shouldShowRequestPermissionRationale(packageName,
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 d0609307e6a8..009d155e96ef 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -1597,25 +1597,6 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
}
- @Override
- 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);
- if (targetPackageUid != callingUid) {
- throw new SecurityException("uid " + callingUid
- + " cannot revoke permissions for package " + packageName + " with uid "
- + targetPackageUid);
- }
- for (String permName : permissions) {
- if (!checkCallingOrSelfPermission(permName)) {
- throw new SecurityException("uid " + callingUid + " cannot revoke permission "
- + permName + " because it does not hold that permission");
- }
- }
- mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
- }
-
private boolean mayManageRolePermission(int uid) {
final PackageManager packageManager = mContext.getPackageManager();
final String[] packageNames = packageManager.getPackagesForUid(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 3e28320a2130..3771f030aefa 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -327,28 +327,6 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId);
/**
- * Triggers the revocation of one or more permissions for a package, under the following
- * conditions:
- * <ul>
- * <li>The package {@code packageName} must be under the same UID as the calling process
- * (typically, the target package is the calling package).
- * <li>Each permission in {@code permissions} must be granted to the package
- * {@code packageName}.
- * <li>Each permission in {@code permissions} must be a runtime permission.
- * </ul>
- * <p>
- * 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.
- */
- void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
-
- /**
* Get whether you should show UI with rationale for requesting a permission. You should do this
* only if you do not have the permission and the context in which the permission is requested
* does not clearly communicate to the user what would be the benefit from grating this
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index b3239486a75f..f255db4a9801 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -242,6 +242,11 @@ public class ParsingPackageUtils {
public static final int PARSE_CHATTY = 1 << 31;
+ /** The total maximum number of activities, services, providers and activity-aliases */
+ private static final int MAX_NUM_COMPONENTS = 30000;
+ private static final String MAX_NUM_COMPONENTS_ERR_MSG =
+ "Total number of components has exceeded the maximum number: " + MAX_NUM_COMPONENTS;
+
@IntDef(flag = true, prefix = { "PARSE_" }, value = {
PARSE_CHATTY,
PARSE_COLLECT_CERTIFICATES,
@@ -837,11 +842,20 @@ public class ParsingPackageUtils {
if (result.isError()) {
return input.error(result);
}
+
+ if (hasTooManyComponents(pkg)) {
+ return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
+ }
}
return input.success(pkg);
}
+ private static boolean hasTooManyComponents(ParsingPackage pkg) {
+ return pkg.getActivities().size() + pkg.getServices().size() + pkg.getProviders().size()
+ > MAX_NUM_COMPONENTS;
+ }
+
/**
* For parsing non-MainComponents. Main ones have an order and some special handling which is
* done directly in {@link #parseSplitApplication(ParseInput, ParsingPackage, Resources,
@@ -2145,6 +2159,9 @@ public class ParsingPackageUtils {
if (result.isError()) {
return input.error(result);
}
+ if (hasTooManyComponents(pkg)) {
+ return input.error(MAX_NUM_COMPONENTS_ERR_MSG);
+ }
}
if (TextUtils.isEmpty(pkg.getStaticSharedLibName()) && TextUtils.isEmpty(
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.java
new file mode 100644
index 000000000000..f3457f5a221b
--- /dev/null
+++ b/services/core/java/com/android/server/soundtrigger_middleware/AidlUtil.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 com.android.server.soundtrigger_middleware;
+
+import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseRecognitionExtra;
+import android.media.soundtrigger.RecognitionEvent;
+import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger.SoundModelType;
+
+/**
+ * Utilities for working with sound trigger related AIDL generated types.
+ */
+public class AidlUtil {
+ /**
+ * Initialize a new recognition event.
+ * @return The new event.
+ */
+ static RecognitionEvent newEmptyRecognitionEvent() {
+ RecognitionEvent result = new RecognitionEvent();
+ result.data = new byte[0];
+ return result;
+ }
+
+ /**
+ * Initialize a new phrase recognition event.
+ * @return The new event.
+ */
+ static PhraseRecognitionEvent newEmptyPhraseRecognitionEvent() {
+ PhraseRecognitionEvent result = new PhraseRecognitionEvent();
+ result.common = newEmptyRecognitionEvent();
+ result.phraseExtras = new PhraseRecognitionExtra[0];
+ return result;
+ }
+
+ /**
+ * Creates a new generic abort event.
+ * @return The new event.
+ */
+ static RecognitionEvent newAbortEvent() {
+ RecognitionEvent event = newEmptyRecognitionEvent();
+ event.type = SoundModelType.GENERIC;
+ event.status = RecognitionStatus.ABORTED;
+ return event;
+ }
+
+ /**
+ * Creates a new generic phrase event.
+ * @return The new event.
+ */
+ static PhraseRecognitionEvent newAbortPhraseEvent() {
+ PhraseRecognitionEvent event = newEmptyPhraseRecognitionEvent();
+ event.common.type = SoundModelType.KEYPHRASE;
+ event.common.status = RecognitionStatus.ABORTED;
+ return event;
+ }
+}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
index 1cc05391b497..c0ab65a3215c 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
@@ -20,12 +20,10 @@ import android.annotation.NonNull;
import android.media.permission.SafeCloseable;
import android.media.soundtrigger.ModelParameterRange;
import android.media.soundtrigger.PhraseRecognitionEvent;
-import android.media.soundtrigger.PhraseRecognitionExtra;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.RecognitionEvent;
-import android.media.soundtrigger.RecognitionStatus;
import android.media.soundtrigger.SoundModel;
import android.media.soundtrigger.SoundModelType;
import android.media.soundtrigger.Status;
@@ -392,21 +390,14 @@ public class SoundTriggerHalConcurrentCaptureHandler implements ISoundTriggerHal
/** Notify the client that recognition has been aborted. */
private static void notifyAbort(int modelHandle, LoadedModel model) {
switch (model.type) {
- case SoundModelType.GENERIC: {
- RecognitionEvent event = newEmptyRecognitionEvent();
- event.status = RecognitionStatus.ABORTED;
- event.type = SoundModelType.GENERIC;
- model.callback.recognitionCallback(modelHandle, event);
- }
- break;
-
- case SoundModelType.KEYPHRASE: {
- PhraseRecognitionEvent event = newEmptyPhraseRecognitionEvent();
- event.common.status = RecognitionStatus.ABORTED;
- event.common.type = SoundModelType.KEYPHRASE;
- model.callback.phraseRecognitionCallback(modelHandle, event);
- }
- break;
+ case SoundModelType.GENERIC:
+ model.callback.recognitionCallback(modelHandle, AidlUtil.newAbortEvent());
+ break;
+
+ case SoundModelType.KEYPHRASE:
+ model.callback.phraseRecognitionCallback(modelHandle,
+ AidlUtil.newAbortPhraseEvent());
+ break;
}
}
@@ -416,19 +407,6 @@ public class SoundTriggerHalConcurrentCaptureHandler implements ISoundTriggerHal
mNotifier.unregisterListener(this);
}
- private static PhraseRecognitionEvent newEmptyPhraseRecognitionEvent() {
- PhraseRecognitionEvent result = new PhraseRecognitionEvent();
- result.common = newEmptyRecognitionEvent();
- result.phraseExtras = new PhraseRecognitionExtra[0];
- return result;
- }
-
- private static RecognitionEvent newEmptyRecognitionEvent() {
- RecognitionEvent result = new RecognitionEvent();
- result.data = new byte[0];
- return result;
- }
-
////////////////////////////////////////////////////////////////////////////////////////////////
// All methods below do trivial delegation - no interesting logic.
@Override
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index 934b0e46ee95..fd8dee8416f6 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -25,6 +25,7 @@ import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
import android.media.soundtrigger.RecognitionEvent;
import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger.SoundModelType;
import android.media.soundtrigger.Status;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
@@ -305,9 +306,12 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
@Override
public void stopRecognition(int modelHandle) {
+ Model model;
synchronized (SoundTriggerModule.this) {
- mLoadedModels.get(modelHandle).stopRecognition();
+ checkValid();
+ model = mLoadedModels.get(modelHandle);
}
+ model.stopRecognition();
}
@Override
@@ -374,6 +378,7 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
private class Model implements ISoundTriggerHal.ModelCallback {
public int mHandle;
private ModelState mState = ModelState.INIT;
+ private int mType = SoundModelType.INVALID;
private SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession mSession;
private @NonNull
@@ -390,6 +395,7 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession) {
mSession = audioSession;
mHandle = mHalService.loadSoundModel(model, this);
+ mType = SoundModelType.GENERIC;
setState(ModelState.LOADED);
mLoadedModels.put(mHandle, this);
return mHandle;
@@ -399,7 +405,7 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
SoundTriggerMiddlewareImpl.AudioSessionProvider.AudioSession audioSession) {
mSession = audioSession;
mHandle = mHalService.loadPhraseSoundModel(model, this);
-
+ mType = SoundModelType.KEYPHRASE;
setState(ModelState.LOADED);
mLoadedModels.put(mHandle, this);
return mHandle;
@@ -422,12 +428,41 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
}
private void stopRecognition() {
- if (getState() == ModelState.LOADED) {
- // This call is idempotent in order to avoid races.
- return;
+ synchronized (SoundTriggerModule.this) {
+ if (getState() == ModelState.LOADED) {
+ // This call is idempotent in order to avoid races.
+ return;
+ }
}
+ // This must be invoked outside the lock.
mHalService.stopRecognition(mHandle);
- setState(ModelState.LOADED);
+
+ // No more callbacks for this model after this point.
+ synchronized (SoundTriggerModule.this) {
+ // Generate an abortion callback to the client if the model is still active.
+ if (getState() == ModelState.ACTIVE) {
+ if (mCallback != null) {
+ try {
+ switch (mType) {
+ case SoundModelType.GENERIC:
+ mCallback.onRecognition(mHandle, AidlUtil.newAbortEvent(),
+ mSession.mSessionHandle);
+ break;
+ case SoundModelType.KEYPHRASE:
+ mCallback.onPhraseRecognition(mHandle,
+ AidlUtil.newAbortPhraseEvent(),
+ mSession.mSessionHandle);
+ break;
+ default:
+ throw new RuntimeException(
+ "Unexpected model type: " + mType);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ setState(ModelState.LOADED);
+ }
+ }
}
/** Request a forced recognition event. Will do nothing if recognition is inactive. */
@@ -518,4 +553,5 @@ class SoundTriggerModule implements IBinder.DeathRecipient, ISoundTriggerHal.Glo
}
}
}
+
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 2e60f130bc4b..526dccb72e39 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1633,7 +1633,14 @@ public class StatsPullAtomService extends SystemService {
if (adapter != null) {
SynchronousResultReceiver bluetoothReceiver =
new SynchronousResultReceiver("bluetooth");
- adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
+ adapter.requestControllerActivityEnergyInfo(
+ Runnable::run,
+ info -> {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, info);
+ bluetoothReceiver.send(0, bundle);
+ }
+ );
return awaitControllerInfo(bluetoothReceiver);
} else {
Slog.e(TAG, "Failed to get bluetooth adapter!");
@@ -2338,51 +2345,25 @@ public class StatsPullAtomService extends SystemService {
}
int pullProcessDmabufMemory(int atomTag, List<StatsEvent> pulledData) {
- List<ProcessMemoryState> managedProcessList =
- LocalServices.getService(ActivityManagerInternal.class)
- .getMemoryStateForProcesses();
- for (ProcessMemoryState process : managedProcessList) {
- KernelAllocationStats.ProcessDmabuf proc =
- KernelAllocationStats.getDmabufAllocations(process.pid);
- if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
- continue;
- }
- pulledData.add(
- FrameworkStatsLog.buildStatsEvent(
- atomTag,
- process.uid,
- process.processName,
- process.oomScore,
- proc.retainedSizeKb,
- proc.retainedBuffersCount,
- proc.mappedSizeKb,
- proc.mappedBuffersCount));
+ KernelAllocationStats.ProcessDmabuf[] procBufs =
+ KernelAllocationStats.getDmabufAllocations();
+
+ if (procBufs == null) {
+ return StatsManager.PULL_SKIP;
}
- SparseArray<String> processCmdlines = getProcessCmdlines();
- managedProcessList.forEach(managedProcess -> processCmdlines.delete(managedProcess.pid));
- int size = processCmdlines.size();
- for (int i = 0; i < size; ++i) {
- int pid = processCmdlines.keyAt(i);
- int uid = getUidForPid(pid);
- // ignore root processes (unlikely to be interesting)
- if (uid <= 0) {
- continue;
- }
- KernelAllocationStats.ProcessDmabuf proc =
- KernelAllocationStats.getDmabufAllocations(pid);
- if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
- continue;
- }
- pulledData.add(
- FrameworkStatsLog.buildStatsEvent(
- atomTag,
- uid,
- processCmdlines.valueAt(i),
- -1001 /*Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.*/,
- proc.retainedSizeKb,
- proc.retainedBuffersCount,
- proc.mappedSizeKb,
- proc.mappedBuffersCount));
+ for (KernelAllocationStats.ProcessDmabuf procBuf : procBufs) {
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag,
+ procBuf.uid,
+ procBuf.processName,
+ procBuf.oomScore,
+ procBuf.retainedSizeKb,
+ procBuf.retainedBuffersCount,
+ 0, /* mapped_dmabuf_kb - deprecated */
+ 0, /* mapped_dmabuf_count - deprecated */
+ procBuf.surfaceFlingerSizeKb,
+ procBuf.surfaceFlingerCount
+ ));
}
return StatsManager.PULL_SUCCESS;
}
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 20cd8f5c12f8..adca21676f9d 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -198,6 +198,8 @@ public class TrustAgentWrapper {
// Fall through.
case MSG_REVOKE_TRUST:
mTrusted = false;
+ mTrustable = false;
+ mWaitingForTrustableDowngrade = false;
mDisplayTrustGrantedMessage = false;
mMessage = null;
mHandler.removeMessages(MSG_TRUST_TIMEOUT);
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index 53a9244837ed..672458bef4a7 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -42,8 +42,8 @@ import android.media.tv.interactive.ITvInteractiveAppService;
import android.media.tv.interactive.ITvInteractiveAppServiceCallback;
import android.media.tv.interactive.ITvInteractiveAppSession;
import android.media.tv.interactive.ITvInteractiveAppSessionCallback;
-import android.media.tv.interactive.TvInteractiveAppInfo;
import android.media.tv.interactive.TvInteractiveAppService;
+import android.media.tv.interactive.TvInteractiveAppServiceInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -130,7 +130,7 @@ public class TvInteractiveAppManagerService extends SystemService {
new Intent(TvInteractiveAppService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
userId);
- List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
+ List<TvInteractiveAppServiceInfo> iAppList = new ArrayList<>();
for (ResolveInfo ri : services) {
ServiceInfo si = ri.serviceInfo;
@@ -143,8 +143,8 @@ public class TvInteractiveAppManagerService extends SystemService {
ComponentName component = new ComponentName(si.packageName, si.name);
try {
- TvInteractiveAppInfo info =
- new TvInteractiveAppInfo(mContext, component);
+ TvInteractiveAppServiceInfo info =
+ new TvInteractiveAppServiceInfo(mContext, component);
iAppList.add(info);
} catch (Exception e) {
Slogf.e(TAG, "failed to load TV Interactive App service " + si.name, e);
@@ -154,10 +154,10 @@ public class TvInteractiveAppManagerService extends SystemService {
}
// sort the iApp list by iApp service id
- Collections.sort(iAppList, Comparator.comparing(TvInteractiveAppInfo::getId));
+ Collections.sort(iAppList, Comparator.comparing(TvInteractiveAppServiceInfo::getId));
Map<String, TvInteractiveAppState> iAppMap = new HashMap<>();
ArrayMap<String, Integer> tiasAppCount = new ArrayMap<>(iAppMap.size());
- for (TvInteractiveAppInfo info : iAppList) {
+ for (TvInteractiveAppServiceInfo info : iAppList) {
String iAppServiceId = info.getId();
if (DEBUG) {
Slogf.d(TAG, "add " + iAppServiceId);
@@ -195,7 +195,7 @@ public class TvInteractiveAppManagerService extends SystemService {
for (String iAppServiceId : userState.mIAppMap.keySet()) {
if (!iAppMap.containsKey(iAppServiceId)) {
- TvInteractiveAppInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
+ TvInteractiveAppServiceInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
ServiceState serviceState = userState.mServiceStateMap.get(info.getComponent());
if (serviceState != null) {
abortPendingCreateSessionRequestsLocked(serviceState, iAppServiceId, userId);
@@ -283,7 +283,7 @@ public class TvInteractiveAppManagerService extends SystemService {
userState.mCallbacks.finishBroadcast();
}
- private int getInteractiveAppUid(TvInteractiveAppInfo info) {
+ private int getInteractiveAppUid(TvInteractiveAppServiceInfo info) {
try {
return getContext().getPackageManager().getApplicationInfo(
info.getServiceInfo().packageName, 0).uid;
@@ -642,7 +642,7 @@ public class TvInteractiveAppManagerService extends SystemService {
private final class BinderService extends ITvInteractiveAppManager.Stub {
@Override
- public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId) {
+ public List<TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList(int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "getTvInteractiveAppServiceList");
final long identity = Binder.clearCallingIdentity();
@@ -653,7 +653,7 @@ public class TvInteractiveAppManagerService extends SystemService {
mGetServiceListCalled = true;
}
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
+ List<TvInteractiveAppServiceInfo> iAppList = new ArrayList<>();
for (TvInteractiveAppState state : userState.mIAppMap.values()) {
iAppList.add(state.mInfo);
}
@@ -665,42 +665,6 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
- public void prepare(String tiasId, int type, int userId) {
- // TODO: bind service
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, "prepare");
- final long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- TvInteractiveAppState iAppState = userState.mIAppMap.get(tiasId);
- if (iAppState == null) {
- Slogf.e(TAG, "failed to prepare TIAS - unknown TIAS id " + tiasId);
- return;
- }
- ComponentName componentName = iAppState.mInfo.getComponent();
- ServiceState serviceState = userState.mServiceStateMap.get(componentName);
- if (serviceState == null) {
- serviceState = new ServiceState(
- componentName, tiasId, resolvedUserId, true, type);
- userState.mServiceStateMap.put(componentName, serviceState);
- updateServiceConnectionLocked(componentName, resolvedUserId);
- } else if (serviceState.mService != null) {
- serviceState.mService.prepare(type);
- } else {
- serviceState.mPendingPrepare = true;
- serviceState.mPendingPrepareType = type;
- updateServiceConnectionLocked(componentName, resolvedUserId);
- }
- }
- } catch (RemoteException e) {
- Slogf.e(TAG, "error in prepare", e);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
public void registerAppLinkInfo(String tiasId, AppLinkInfo appLinkInfo, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "registerAppLinkInfo: " + appLinkInfo);
@@ -1360,6 +1324,32 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
+ public void sendSigningResult(
+ IBinder sessionToken, String signingId, byte[] result, int userId) {
+ if (DEBUG) {
+ Slogf.d(TAG, "sendSigningResult(signingId=%s)", signingId);
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "sendSigningResult");
+ SessionState sessionState = null;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ sessionState = getSessionStateLocked(sessionToken, callingUid,
+ resolvedUserId);
+ getSessionLocked(sessionState).sendSigningResult(signingId, result);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slogf.e(TAG, "error in sendSigningResult", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void setSurface(IBinder sessionToken, Surface surface, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
@@ -1679,7 +1669,6 @@ public class TvInteractiveAppManagerService extends SystemService {
}
boolean shouldBind = (!serviceState.mSessionTokens.isEmpty())
- || (serviceState.mPendingPrepare)
|| (!serviceState.mPendingAppLinkInfo.isEmpty())
|| (!serviceState.mPendingAppLinkCommand.isEmpty());
@@ -1738,7 +1727,7 @@ public class TvInteractiveAppManagerService extends SystemService {
private static final class TvInteractiveAppState {
private String mIAppServiceId;
private ComponentName mComponentName;
- private TvInteractiveAppInfo mInfo;
+ private TvInteractiveAppServiceInfo mInfo;
private int mUid;
private int mIAppNumber;
}
@@ -1831,22 +1820,13 @@ public class TvInteractiveAppManagerService extends SystemService {
private final List<Pair<AppLinkInfo, Boolean>> mPendingAppLinkInfo = new ArrayList<>();
private final List<Bundle> mPendingAppLinkCommand = new ArrayList<>();
- private boolean mPendingPrepare = false;
- private Integer mPendingPrepareType = null;
private ITvInteractiveAppService mService;
private ServiceCallback mCallback;
private boolean mBound;
private boolean mReconnecting;
private ServiceState(ComponentName component, String tias, int userId) {
- this(component, tias, userId, false, null);
- }
-
- private ServiceState(ComponentName component, String tias, int userId,
- boolean pendingPrepare, Integer prepareType) {
mComponent = component;
- mPendingPrepare = pendingPrepare;
- mPendingPrepareType = prepareType;
mConnection = new InteractiveAppServiceConnection(component, userId);
mIAppServiceId = tias;
}
@@ -1894,19 +1874,6 @@ public class TvInteractiveAppManagerService extends SystemService {
}
}
- if (serviceState.mPendingPrepare) {
- final long identity = Binder.clearCallingIdentity();
- try {
- serviceState.mService.prepare(serviceState.mPendingPrepareType);
- serviceState.mPendingPrepare = false;
- serviceState.mPendingPrepareType = null;
- } catch (RemoteException e) {
- Slogf.e(TAG, "error in prepare when onServiceConnected", e);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
if (!serviceState.mPendingAppLinkInfo.isEmpty()) {
for (Iterator<Pair<AppLinkInfo, Boolean>> it =
serviceState.mPendingAppLinkInfo.iterator();
@@ -2221,6 +2188,24 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
+ public void onRequestSigning(String id, String algorithm, String alias, byte[] data) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onRequestSigning");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onRequestSigning(
+ id, algorithm, alias, data, mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onRequestSigning", e);
+ }
+ }
+ }
+
+ @Override
public void onAdRequest(AdRequest request) {
synchronized (mLock) {
if (DEBUG) {
diff --git a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
index 397acfac2812..b45c962811ad 100644
--- a/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
+++ b/services/core/java/com/android/server/utils/TimingsTraceAndSlog.java
@@ -88,7 +88,7 @@ public final class TimingsTraceAndSlog extends TimingsTraceLog {
@Override
public void traceBegin(@NonNull String name) {
- Slog.i(mTag, name);
+ Slog.d(mTag, name);
super.traceBegin(name);
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index d4648a4f313c..11ddac6a9740 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -30,6 +30,7 @@ import android.os.IBinder;
import android.os.InputConfig;
import android.os.Looper;
import android.os.Message;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.IWindow;
@@ -94,8 +95,6 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
mService = service;
mAccessibilityController = accessibilityController;
mHandler = new MyHandler(mService.mH.getLooper());
-
- register();
}
/**
@@ -219,8 +218,10 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
}
mWindowsNotificationEnabled = register;
if (mWindowsNotificationEnabled) {
- populateVisibleWindowHandlesAndNotifyWindowsChangeIfNeeded();
+ Pair<InputWindowHandle[], DisplayInfo[]> info = register();
+ onWindowInfosChangedInternal(info.first, info.second);
} else {
+ unregister();
releaseResources();
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index c0cdec9ade7f..7f84f61a91ff 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -191,6 +191,35 @@ class ActivityMetricsLogger {
private long mCurrentTransitionStartTimeNs;
/** Non-null when a {@link TransitionInfo} is created for this state. */
private TransitionInfo mAssociatedTransitionInfo;
+ /** The sequence id for trace. It is used to map the traces before resolving intent. */
+ private static int sTraceSeqId;
+ /** The trace format is "launchingActivity#$seqId:$state(:$packageName)". */
+ final String mTraceName;
+
+ LaunchingState() {
+ if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ mTraceName = null;
+ return;
+ }
+ // Use an id because the launching app is not yet known before resolving intent.
+ sTraceSeqId++;
+ mTraceName = "launchingActivity#" + sTraceSeqId;
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
+ }
+
+ void stopTrace(boolean abort) {
+ if (mTraceName == null) return;
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
+ final String launchResult;
+ if (mAssociatedTransitionInfo == null) {
+ launchResult = ":failed";
+ } else {
+ launchResult = (abort ? ":canceled:" : ":completed:")
+ + mAssociatedTransitionInfo.mLastLaunchedActivity.packageName;
+ }
+ // Put a supplement trace as the description of the async trace with the same id.
+ Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName + launchResult);
+ }
@VisibleForTesting
boolean allDrawn() {
@@ -549,10 +578,10 @@ class ActivityMetricsLogger {
}
if (existingInfo == null) {
- // Only notify the observer for a new launching event.
- launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
final LaunchingState launchingState = new LaunchingState();
launchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
+ // Only notify the observer for a new launching event.
+ launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
return launchingState;
}
existingInfo.mLaunchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
@@ -574,7 +603,7 @@ class ActivityMetricsLogger {
@Nullable ActivityOptions options) {
if (launchedActivity == null) {
// The launch is aborted, e.g. intent not resolved, class not found.
- abort(null /* info */, "nothing launched");
+ abort(launchingState, "nothing launched");
return;
}
@@ -601,7 +630,7 @@ class ActivityMetricsLogger {
if (launchedActivity.isReportedDrawn() && launchedActivity.isVisible()) {
// Launched activity is already visible. We cannot measure windows drawn delay.
- abort(info, "launched activity already visible");
+ abort(launchingState, "launched activity already visible");
return;
}
@@ -633,7 +662,7 @@ class ActivityMetricsLogger {
final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
options, processRunning, processSwitch, newActivityCreated, resultCode);
if (newInfo == null) {
- abort(info, "unrecognized launch");
+ abort(launchingState, "unrecognized launch");
return;
}
@@ -874,23 +903,29 @@ class ActivityMetricsLogger {
}
}
+ private void abort(@NonNull LaunchingState state, String cause) {
+ if (state.mAssociatedTransitionInfo != null) {
+ abort(state.mAssociatedTransitionInfo, cause);
+ return;
+ }
+ if (DEBUG_METRICS) Slog.i(TAG, "abort launch cause=" + cause);
+ state.stopTrace(true /* abort */);
+ launchObserverNotifyIntentFailed();
+ }
+
/** Aborts tracking of current launch metrics. */
- private void abort(TransitionInfo info, String cause) {
+ private void abort(@NonNull TransitionInfo info, String cause) {
done(true /* abort */, info, cause, 0L /* timestampNs */);
}
/** Called when the given transition (info) is no longer active. */
- private void done(boolean abort, @Nullable TransitionInfo info, String cause,
+ private void done(boolean abort, @NonNull TransitionInfo info, String cause,
long timestampNs) {
if (DEBUG_METRICS) {
Slog.i(TAG, "done abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
+ " info=" + info);
}
- if (info == null) {
- launchObserverNotifyIntentFailed();
- return;
- }
-
+ info.mLaunchingState.stopTrace(abort);
stopLaunchTrace(info);
final Boolean isHibernating =
mLastHibernationStates.remove(info.mLastLaunchedActivity.packageName);
@@ -1457,7 +1492,7 @@ class ActivityMetricsLogger {
/** Starts trace for an activity is actually launching. */
private void startLaunchTrace(@NonNull TransitionInfo info) {
if (DEBUG_METRICS) Slog.i(TAG, "startLaunchTrace " + info);
- if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ if (info.mLaunchingState.mTraceName == null) {
return;
}
info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 883ce99d313d..bfe1f30f671a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5603,19 +5603,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
"makeInvisible", true /* beforeStopping */);
// Defer telling the client it is hidden if it can enter Pip and isn't current paused,
// stopped or stopping. This gives it a chance to enter Pip in onPause().
- // TODO: There is still a question surrounding activities in multi-window mode that want
- // to enter Pip after they are paused, but are still visible. I they should be okay to
- // enter Pip in those cases, but not "auto-Pip" which is what this condition covers and
- // the current contract for "auto-Pip" is that the app should enter it before onPause
- // returns. Just need to confirm this reasoning makes sense.
final boolean deferHidingClient = canEnterPictureInPicture
&& !isState(STARTED, STOPPING, STOPPED, PAUSED);
- if (!mTransitionController.isShellTransitionsEnabled()
- && deferHidingClient && pictureInPictureArgs.isAutoEnterEnabled()) {
- // Go ahead and just put the activity in pip if it supports auto-pip.
- mAtmService.enterPictureInPictureMode(this, pictureInPictureArgs);
- return;
- }
setDeferHidingClient(deferHidingClient);
setVisibility(false);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 7d2dfa071597..77ec67f31d50 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2730,10 +2730,11 @@ class ActivityStarter {
false /* includingParents */);
intentTask = intentTask.getParent().asTaskFragment().getTask();
}
- // If the task is in multi-windowing mode, the activity may already be on
+ // If the activity is visible in multi-windowing mode, it may already be on
// the top (visible to user but not the global top), then the result code
// should be START_DELIVERED_TO_TOP instead of START_TASK_TO_FRONT.
final boolean wasTopOfVisibleRootTask = intentActivity.mVisibleRequested
+ && intentActivity.inMultiWindowMode()
&& intentActivity == mTargetRootTask.topRunningActivity();
// We only want to move to the front, if we aren't going to launch on a
// different root task. If we launch on a different root task, we will put the
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 07a0c372778b..87523f44d4b6 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
+import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONTENT_RECORDING;
@@ -26,6 +27,7 @@ import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
+import android.provider.DeviceConfig;
import android.view.ContentRecordingSession;
import android.view.Display;
import android.view.SurfaceControl;
@@ -39,6 +41,11 @@ import com.android.internal.protolog.common.ProtoLog;
final class ContentRecorder {
/**
+ * The key for accessing the device config that controls if task recording is supported.
+ */
+ @VisibleForTesting static final String KEY_RECORD_TASK_FEATURE = "record_task_content";
+
+ /**
* The display content this class is handling recording for.
*/
@NonNull
@@ -48,7 +55,7 @@ final class ContentRecorder {
* The session for content recording, or null if this DisplayContent is not being used for
* recording.
*/
- @VisibleForTesting private ContentRecordingSession mContentRecordingSession = null;
+ private ContentRecordingSession mContentRecordingSession = null;
/**
* The WindowContainer for the level of the hierarchy to record.
@@ -187,6 +194,8 @@ final class ContentRecorder {
mDisplayContent.mWmService.mTransactionFactory.get().remove(mRecordedSurface).apply();
mRecordedSurface = null;
clearContentRecordingSession();
+ // Do not need to force remove the VirtualDisplay; this is handled by the media
+ // projection service.
}
}
@@ -215,46 +224,12 @@ final class ContentRecorder {
return;
}
- final int contentToRecord = mContentRecordingSession.getContentToRecord();
- if (contentToRecord != RECORD_CONTENT_DISPLAY) {
- // TODO(b/216625226) handle task-based recording
- // Not a valid region, or recording is disabled, so fall back to prior MediaProjection
- // approach.
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to start recording due to invalid region for display %d",
- mDisplayContent.getDisplayId());
- return;
- }
- // Given the WindowToken of the DisplayArea to record, retrieve the associated
- // SurfaceControl.
- IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
- if (tokenToRecord == null) {
- // Unexpectedly missing token. Fall back to prior MediaProjection approach.
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to start recording due to null token for display %d",
- mDisplayContent.getDisplayId());
- return;
- }
-
- final WindowContainer wc =
- mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
- tokenToRecord);
- if (wc == null) {
- // Un-set the window token to record for this VirtualDisplay. Fall back to the
- // original MediaProjection approach.
- mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
- mDisplayContent.getDisplayId(), false);
- clearContentRecordingSession();
- ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
- "Unable to retrieve window container to start recording for "
- + "display %d",
- mDisplayContent.getDisplayId());
+ mRecordedWindowContainer = retrieveRecordedWindowContainer();
+ if (mRecordedWindowContainer == null) {
+ // Either the token is missing, or the window associated with the token is missing.
+ // Error has already been handled, so just leave.
return;
}
- // TODO(206461622) Migrate to using the RootDisplayArea
- mRecordedWindowContainer = wc.getDisplayContent();
final Point surfaceSize = fetchSurfaceSizeIfPresent();
if (surfaceSize == null) {
@@ -296,6 +271,107 @@ final class ContentRecorder {
}
/**
+ * Retrieves the {@link WindowContainer} for the level of the hierarchy to start recording,
+ * indicated by the {@link #mContentRecordingSession}. Performs any error handling and state
+ * updates necessary if the {@link WindowContainer} could not be retrieved.
+ * {@link #mContentRecordingSession} must be non-null.
+ *
+ * @return a {@link WindowContainer} to record, or {@code null} if an error was encountered. The
+ * error is logged and any cleanup is handled.
+ */
+ @Nullable
+ private WindowContainer retrieveRecordedWindowContainer() {
+ final int contentToRecord = mContentRecordingSession.getContentToRecord();
+ // Given the WindowToken of the region to record, retrieve the associated
+ // SurfaceControl.
+ final IBinder tokenToRecord = mContentRecordingSession.getTokenToRecord();
+ if (tokenToRecord == null) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to start recording due to null token for display %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ switch (contentToRecord) {
+ case RECORD_CONTENT_DISPLAY:
+ final WindowContainer wc =
+ mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
+ tokenToRecord);
+ if (wc == null) {
+ // Un-set the window token to record for this VirtualDisplay. Fall back to
+ // Display stack capture for the entire display.
+ mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
+ mDisplayContent.getDisplayId(), false);
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to retrieve window container to start recording for "
+ + "display %d", mDisplayContent.getDisplayId());
+ return null;
+ }
+ // TODO(206461622) Migrate to using the RootDisplayArea
+ return wc.getDisplayContent();
+ case RECORD_CONTENT_TASK:
+ if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_RECORD_TASK_FEATURE, false)) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to record task since feature is disabled %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ Task taskToRecord = WindowContainer.fromBinder(tokenToRecord).asTask();
+ if (taskToRecord == null) {
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to retrieve task to start recording for "
+ + "display %d", mDisplayContent.getDisplayId());
+ }
+ return taskToRecord;
+ default:
+ // Not a valid region, or recording is disabled, so fall back to Display stack
+ // capture for the entire display.
+ handleStartRecordingFailed();
+ ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
+ "Unable to start recording due to invalid region for display %d",
+ mDisplayContent.getDisplayId());
+ return null;
+ }
+ }
+
+ /**
+ * Exit this recording session.
+ * <p>
+ * If this is a task session, tear down the recording entirely. Do not fall back
+ * to recording the entire display on the display stack; this would surprise the user
+ * given they selected task capture.
+ * </p><p>
+ * If this is a display session, just stop recording by layer mirroring. Fall back to recording
+ * from the display stack.
+ * </p>
+ */
+ private void handleStartRecordingFailed() {
+ final boolean shouldExitTaskRecording = mContentRecordingSession != null
+ && mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK;
+ if (shouldExitTaskRecording) {
+ // Clean up the cached session first, since tearing down the display will generate
+ // display
+ // events which will trickle back to here.
+ clearContentRecordingSession();
+ tearDownVirtualDisplay();
+ } else {
+ clearContentRecordingSession();
+ }
+ }
+
+ /**
+ * Ensure recording does not fall back to the display stack; ensure the recording is stopped
+ * and the client notified by tearing down the virtual display.
+ */
+ private void tearDownVirtualDisplay() {
+ // TODO(b/219761722) Clean up the VirtualDisplay if task mirroring fails
+ }
+
+ /**
* Apply transformations to the mirrored surface to ensure the captured contents are scaled to
* fit and centred in the output surface.
*
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 736732029510..f5ace6c78288 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -128,7 +128,6 @@ import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
import static com.android.server.wm.DisplayContentProto.SLEEP_TOKENS;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
@@ -5001,10 +5000,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// docked divider while keeping the app itself below the docked divider, so instead
// we will put the docked divider below the IME. @see #assignRelativeLayerForImeTargetChild
//
- // In the case the IME target is animating, the animation Z order may be different
- // than the WindowContainer Z order, so it's difficult to be sure we have the correct
- // IME target. In this case we just layer the IME over its parent surface.
- //
// In the case where we have no IME target we let its window parent to place it.
//
// Keep IME window in surface parent as long as app's starting window
@@ -5020,9 +5015,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// We don't need to set relative layer if the IME target in non-multi-window
// mode is the activity main window since updateImeParent will ensure the IME
// surface be attached on the fullscreen activity.
- && imeTarget.mAttrs.type != TYPE_BASE_APPLICATION
- && imeTarget.mToken.getActivity(app -> app.isAnimating(TRANSITION | PARENTS,
- ANIMATION_TYPE_ALL & ~ANIMATION_TYPE_RECENTS)) == null;
+ && imeTarget.mAttrs.type != TYPE_BASE_APPLICATION;
if (canImeTargetSetRelativeLayer) {
mImeWindowsContainer.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
// TODO: We need to use an extra level on the app surface to ensure
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 3951c567e89c..9844cb5fe8f8 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -344,7 +344,6 @@ class InsetsPolicy {
// Navigation bar doesn't get influenced by anything else
if (type == ITYPE_NAVIGATION_BAR || type == ITYPE_EXTRA_NAVIGATION_BAR) {
- state.removeSource(ITYPE_IME);
state.removeSource(ITYPE_STATUS_BAR);
state.removeSource(ITYPE_CLIMATE_BAR);
state.removeSource(ITYPE_CAPTION_BAR);
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index d187bd6f3dfd..2ac41a7c1c1d 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1459,7 +1459,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// next activity.
final boolean lastResumedCanPip = prev.checkEnterPictureInPictureState(
"shouldAutoPipWhilePausing", userLeaving);
- if (lastResumedCanPip && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
+ if (userLeaving && lastResumedCanPip
+ && prev.pictureInPictureArgs.isAutoEnterEnabled()) {
shouldAutoPip = true;
} else if (!lastResumedCanPip) {
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c50888b5a172..eb88b8b0ea97 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3278,7 +3278,7 @@ public class WindowManagerService extends IWindowManager.Stub
mContext.enforceCallingOrSelfPermission(
Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE,
Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE
- + " permission required to read keyguard visibility");
+ + " permission required to subscribe to keyguard locked state changes");
}
private void dispatchKeyguardLockedState() {
diff --git a/services/core/jni/gnss/MeasurementCorrections.cpp b/services/core/jni/gnss/MeasurementCorrections.cpp
index 8a3d84cbe9c6..07d0a45e9c40 100644
--- a/services/core/jni/gnss/MeasurementCorrections.cpp
+++ b/services/core/jni/gnss/MeasurementCorrections.cpp
@@ -44,6 +44,7 @@ using SingleSatCorrection_Aidl =
using ReflectingPlane_V1_0 =
android::hardware::gnss::measurement_corrections::V1_0::ReflectingPlane;
using ReflectingPlane_Aidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
+using ExcessPathInfo = SingleSatCorrection_Aidl::ExcessPathInfo;
using GnssConstellationType_V1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
using GnssConstellationType_V2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
using GnssConstellationType_Aidl = android::hardware::gnss::GnssConstellationType;
@@ -62,7 +63,7 @@ jmethodID method_correctionsHasEnvironmentBearing;
jmethodID method_correctionsGetEnvironmentBearingDegrees;
jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
jmethodID method_listSize;
-jmethodID method_correctionListGet;
+jmethodID method_listGet;
jmethodID method_correctionSatFlags;
jmethodID method_correctionSatConstType;
jmethodID method_correctionSatId;
@@ -71,10 +72,17 @@ jmethodID method_correctionSatIsLosProb;
jmethodID method_correctionSatEpl;
jmethodID method_correctionSatEplUnc;
jmethodID method_correctionSatRefPlane;
+jmethodID method_correctionSatAttenuation;
+jmethodID method_correctionSatExcessPathInfoList;
jmethodID method_correctionPlaneLatDeg;
jmethodID method_correctionPlaneLngDeg;
jmethodID method_correctionPlaneAltDeg;
jmethodID method_correctionPlaneAzimDeg;
+jmethodID method_excessPathInfoFlags;
+jmethodID method_excessPathInfoEpl;
+jmethodID method_excessPathInfoEplUnc;
+jmethodID method_excessPathInfoRefPlane;
+jmethodID method_excessPathInfoAttenuation;
} // anonymous namespace
void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
@@ -103,7 +111,7 @@ void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
jclass corrListClass = env->FindClass("java/util/List");
method_listSize = env->GetMethodID(corrListClass, "size", "()I");
- method_correctionListGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
+ method_listGet = env->GetMethodID(corrListClass, "get", "(I)Ljava/lang/Object;");
jclass singleSatCorrClass = env->FindClass("android/location/GnssSingleSatCorrection");
method_correctionSatFlags =
@@ -121,12 +129,27 @@ void MeasurementCorrections_class_init_once(JNIEnv* env, jclass clazz) {
env->GetMethodID(singleSatCorrClass, "getExcessPathLengthUncertaintyMeters", "()F");
method_correctionSatRefPlane = env->GetMethodID(singleSatCorrClass, "getReflectingPlane",
"()Landroid/location/GnssReflectingPlane;");
+ method_correctionSatAttenuation =
+ env->GetMethodID(singleSatCorrClass, "getCombinedAttenuationDb", "()F");
+ method_correctionSatExcessPathInfoList =
+ env->GetMethodID(singleSatCorrClass, "getGnssExcessPathInfoList", "()Ljava/util/List;");
jclass refPlaneClass = env->FindClass("android/location/GnssReflectingPlane");
method_correctionPlaneLatDeg = env->GetMethodID(refPlaneClass, "getLatitudeDegrees", "()D");
method_correctionPlaneLngDeg = env->GetMethodID(refPlaneClass, "getLongitudeDegrees", "()D");
method_correctionPlaneAltDeg = env->GetMethodID(refPlaneClass, "getAltitudeMeters", "()D");
method_correctionPlaneAzimDeg = env->GetMethodID(refPlaneClass, "getAzimuthDegrees", "()D");
+
+ jclass excessPathInfoClass = env->FindClass("android/location/GnssExcessPathInfo");
+ method_excessPathInfoFlags = env->GetMethodID(excessPathInfoClass, "getFlags", "()I");
+ method_excessPathInfoEpl =
+ env->GetMethodID(excessPathInfoClass, "getExcessPathLengthMeters", "()F");
+ method_excessPathInfoEplUnc =
+ env->GetMethodID(excessPathInfoClass, "getExcessPathLengthUncertaintyMeters", "()F");
+ method_excessPathInfoRefPlane = env->GetMethodID(excessPathInfoClass, "getReflectingPlane",
+ "()Landroid/location/GnssReflectingPlane;");
+ method_excessPathInfoAttenuation =
+ env->GetMethodID(excessPathInfoClass, "getAttenuationDb", "()F");
}
template <>
@@ -324,7 +347,8 @@ jboolean MeasurementCorrectionsIface_V1_1::setCallback(
SingleSatCorrection_V1_0
MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
JNIEnv* env, jobject singleSatCorrectionObj) {
- jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ uint16_t corrFlags = static_cast<uint16_t>(
+ env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
jfloat carrierFreqHz =
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -332,14 +356,16 @@ MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
- uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
ReflectingPlane_V1_0 reflectingPlane;
- if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0)
- MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_V1_0>(env,
- singleSatCorrectionObj,
+ if ((corrFlags & GnssSingleSatCorrectionFlags_V1_0::HAS_REFLECTING_PLANE) != 0) {
+ jobject reflectingPlaneObj =
+ env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
+ MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_V1_0>(env,
+ reflectingPlaneObj,
reflectingPlane);
-
+ env->DeleteLocalRef(reflectingPlaneObj);
+ }
SingleSatCorrection_V1_0 singleSatCorrection = {
.singleSatCorrectionFlags = corrFlags,
.svid = static_cast<uint16_t>(satId),
@@ -349,13 +375,14 @@ MeasurementCorrectionsUtil::getSingleSatCorrection_1_0_withoutConstellation(
.excessPathLengthUncertaintyMeters = eplUncMeters,
.reflectingPlane = reflectingPlane,
};
-
return singleSatCorrection;
}
SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl(
JNIEnv* env, jobject singleSatCorrectionObj) {
- jint correctionFlags = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags);
+ int32_t corrFlags = static_cast<int32_t>(
+ env->CallIntMethod(singleSatCorrectionObj, method_correctionSatFlags));
+ jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
jint satId = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatId);
jfloat carrierFreqHz =
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatCarrierFreq);
@@ -363,15 +390,10 @@ SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl
env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatIsLosProb);
jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
- int32_t corrFlags = static_cast<int32_t>(correctionFlags);
-
- ReflectingPlane_Aidl reflectingPlane;
- if ((corrFlags & SingleSatCorrection_Aidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE) != 0)
- MeasurementCorrectionsUtil::getReflectingPlane<ReflectingPlane_Aidl>(env,
- singleSatCorrectionObj,
- reflectingPlane);
-
- jint constType = env->CallIntMethod(singleSatCorrectionObj, method_correctionSatConstType);
+ jfloat attenuationDb =
+ env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatAttenuation);
+ std::vector<ExcessPathInfo> excessPathInfos =
+ MeasurementCorrectionsUtil::getExcessPathInfoList(env, singleSatCorrectionObj);
SingleSatCorrection_Aidl singleSatCorrection;
singleSatCorrection.singleSatCorrectionFlags = corrFlags;
@@ -379,9 +401,10 @@ SingleSatCorrection_Aidl MeasurementCorrectionsUtil::getSingleSatCorrection_Aidl
singleSatCorrection.svid = static_cast<int32_t>(satId);
singleSatCorrection.carrierFrequencyHz = carrierFreqHz;
singleSatCorrection.probSatIsLos = probSatIsLos;
- singleSatCorrection.excessPathLengthMeters = eplMeters;
- singleSatCorrection.excessPathLengthUncertaintyMeters = eplUncMeters;
- singleSatCorrection.reflectingPlane = reflectingPlane;
+ singleSatCorrection.combinedExcessPathLengthMeters = eplMeters;
+ singleSatCorrection.combinedExcessPathLengthUncertaintyMeters = eplUncMeters;
+ singleSatCorrection.combinedAttenuationDb = attenuationDb;
+ singleSatCorrection.excessPathInfos = excessPathInfos;
return singleSatCorrection;
}
@@ -391,8 +414,7 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_1_0(
hardware::hidl_vec<SingleSatCorrection_V1_0>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
-
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_V1_0 singleSatCorrection =
getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
@@ -410,7 +432,7 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_1_1(
hardware::hidl_vec<SingleSatCorrection_V1_1>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_V1_0 singleSatCorrection_1_0 =
getSingleSatCorrection_1_0_withoutConstellation(env, singleSatCorrectionObj);
@@ -431,7 +453,7 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_Aidl(
JNIEnv* env, jobject singleSatCorrectionList, std::vector<SingleSatCorrection_Aidl>& list) {
for (uint16_t i = 0; i < list.size(); ++i) {
jobject singleSatCorrectionObj =
- env->CallObjectMethod(singleSatCorrectionList, method_correctionListGet, i);
+ env->CallObjectMethod(singleSatCorrectionList, method_listGet, i);
SingleSatCorrection_Aidl singleSatCorrection_Aidl =
getSingleSatCorrection_Aidl(env, singleSatCorrectionObj);
@@ -441,4 +463,63 @@ void MeasurementCorrectionsUtil::getSingleSatCorrectionList_Aidl(
}
}
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_V1_0>(
+ ReflectingPlane_V1_0& reflectingPlane, double azimuthDegreeRefPlane) {
+ reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
+}
+
+template <>
+void MeasurementCorrectionsUtil::setReflectingPlaneAzimuthDegrees<ReflectingPlane_Aidl>(
+ ReflectingPlane_Aidl& reflectingPlane, double azimuthDegreeRefPlane) {
+ reflectingPlane.reflectingPlaneAzimuthDegrees = azimuthDegreeRefPlane;
+}
+
+std::vector<ExcessPathInfo> MeasurementCorrectionsUtil::getExcessPathInfoList(
+ JNIEnv* env, jobject singleSatCorrectionObj) {
+ jobject excessPathInfoListObj =
+ env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatExcessPathInfoList);
+
+ int len = env->CallIntMethod(excessPathInfoListObj, method_listSize);
+ std::vector<ExcessPathInfo> list(len);
+ for (int i = 0; i < len; ++i) {
+ jobject excessPathInfoObj = env->CallObjectMethod(excessPathInfoListObj, method_listGet, i);
+ list[i] = getExcessPathInfo(env, excessPathInfoObj);
+ env->DeleteLocalRef(excessPathInfoObj);
+ }
+ env->DeleteLocalRef(excessPathInfoListObj);
+ return list;
+}
+
+ExcessPathInfo MeasurementCorrectionsUtil::getExcessPathInfo(JNIEnv* env,
+ jobject excessPathInfoObj) {
+ ExcessPathInfo excessPathInfo;
+ jint flags = env->CallIntMethod(excessPathInfoObj, method_excessPathInfoFlags);
+ excessPathInfo.excessPathInfoFlags = flags;
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH) != 0) {
+ jfloat epl = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEpl);
+ excessPathInfo.excessPathLengthMeters = epl;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC) != 0) {
+ jfloat eplUnc = env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoEplUnc);
+ excessPathInfo.excessPathLengthUncertaintyMeters = eplUnc;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_REFLECTING_PLANE) != 0) {
+ ReflectingPlane_Aidl reflectingPlane;
+ jobject reflectingPlaneObj =
+ env->CallObjectMethod(excessPathInfoObj, method_excessPathInfoRefPlane);
+ MeasurementCorrectionsUtil::setReflectingPlane<ReflectingPlane_Aidl>(env,
+ reflectingPlaneObj,
+ reflectingPlane);
+ env->DeleteLocalRef(reflectingPlaneObj);
+ excessPathInfo.reflectingPlane = reflectingPlane;
+ }
+ if ((flags & ExcessPathInfo::EXCESS_PATH_INFO_HAS_ATTENUATION) != 0) {
+ jfloat attenuation =
+ env->CallFloatMethod(excessPathInfoObj, method_excessPathInfoAttenuation);
+ excessPathInfo.attenuationDb = attenuation;
+ }
+ return excessPathInfo;
+}
+
} // namespace android::gnss
diff --git a/services/core/jni/gnss/MeasurementCorrections.h b/services/core/jni/gnss/MeasurementCorrections.h
index a2e602714326..598ad48d6ac1 100644
--- a/services/core/jni/gnss/MeasurementCorrections.h
+++ b/services/core/jni/gnss/MeasurementCorrections.h
@@ -43,7 +43,7 @@ extern jmethodID method_correctionsHasEnvironmentBearing;
extern jmethodID method_correctionsGetEnvironmentBearingDegrees;
extern jmethodID method_correctionsGetEnvironmentBearingUncertaintyDegrees;
extern jmethodID method_listSize;
-extern jmethodID method_correctionListGet;
+extern jmethodID method_listGet;
extern jmethodID method_correctionSatFlags;
extern jmethodID method_correctionSatConstType;
extern jmethodID method_correctionSatId;
@@ -52,6 +52,7 @@ extern jmethodID method_correctionSatIsLosProb;
extern jmethodID method_correctionSatEpl;
extern jmethodID method_correctionSatEplUnc;
extern jmethodID method_correctionSatRefPlane;
+extern jmethodID method_correctionSatExcessPathInfos;
extern jmethodID method_correctionPlaneLatDeg;
extern jmethodID method_correctionPlaneLngDeg;
extern jmethodID method_correctionPlaneAltDeg;
@@ -130,14 +131,20 @@ struct MeasurementCorrectionsUtil {
static bool translateMeasurementCorrections(JNIEnv* env, jobject correctionsObj,
T& corrections);
template <class T>
- static void getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj, T& reflectingPlane);
+ static void setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj, T& reflectingPlane);
+ template <class T>
+ static void setReflectingPlaneAzimuthDegrees(T& reflectingPlane, double azimuthDegreeRefPlane);
+
+ static std::vector<
+ android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo>
+ getExcessPathInfoList(JNIEnv* env, jobject correctionsObj);
+ static android::hardware::gnss::measurement_corrections::SingleSatCorrection::ExcessPathInfo
+ getExcessPathInfo(JNIEnv* env, jobject correctionsObj);
};
template <class T>
-void MeasurementCorrectionsUtil::getReflectingPlane(JNIEnv* env, jobject singleSatCorrectionObj,
+void MeasurementCorrectionsUtil::setReflectingPlane(JNIEnv* env, jobject reflectingPlaneObj,
T& reflectingPlane) {
- jobject reflectingPlaneObj =
- env->CallObjectMethod(singleSatCorrectionObj, method_correctionSatRefPlane);
jdouble latitudeDegreesRefPlane =
env->CallDoubleMethod(reflectingPlaneObj, method_correctionPlaneLatDeg);
jdouble longitudeDegreesRefPlane =
@@ -149,8 +156,7 @@ void MeasurementCorrectionsUtil::getReflectingPlane(JNIEnv* env, jobject singleS
reflectingPlane.latitudeDegrees = latitudeDegreesRefPlane;
reflectingPlane.longitudeDegrees = longitudeDegreesRefPlane;
reflectingPlane.altitudeMeters = altitudeDegreesRefPlane;
- reflectingPlane.azimuthDegrees = azimuthDegreeRefPlane;
- env->DeleteLocalRef(reflectingPlaneObj);
+ setReflectingPlaneAzimuthDegrees<T>(reflectingPlane, azimuthDegreeRefPlane);
}
} // namespace android::gnss
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 2f5ab0b31332..48c40523e9c2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -1227,5 +1227,12 @@ class ActiveAdmin {
pw.print("mSsidDenylist=");
pw.println(mSsidDenylist);
+
+ if (mFactoryResetProtectionPolicy != null) {
+ pw.println("mFactoryResetProtectionPolicy:");
+ pw.increaseIndent();
+ mFactoryResetProtectionPolicy.dump(pw);
+ pw.decreaseIndent();
+ }
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index ba00beea47cc..edfd6ed5f63d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,6 +15,7 @@
*/
package com.android.server.devicepolicy;
+import android.accounts.Account;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyDrawableResource;
@@ -138,6 +139,11 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
return null;
}
+ public void finalizeWorkProfileProvisioning(
+ UserHandle managedProfileUser, Account migratedAccount) {
+
+ }
+
public void provisionFullyManagedDevice(
FullyManagedDeviceProvisioningParams provisioningParams, String callerPackage) {
}
@@ -171,7 +177,7 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables){}
@Override
- public void resetDrawables(@NonNull String[] drawableIds){}
+ public void resetDrawables(@NonNull List<String> drawableIds){}
@Override
public ParcelableResource getDrawable(
@@ -183,7 +189,7 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
public void setStrings(@NonNull List<DevicePolicyStringResource> strings){}
@Override
- public void resetStrings(String[] stringIds){}
+ public void resetStrings(@NonNull List<String> stringIds){}
@Override
public ParcelableResource getString(String stringId) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
index e70c071183ce..6f0330e97482 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
@@ -176,11 +176,11 @@ class DeviceManagementResourcesProvider {
/**
* Returns {@code false} if no resources were removed.
*/
- boolean removeDrawables(@NonNull String[] drawableIds) {
+ boolean removeDrawables(@NonNull List<String> drawableIds) {
synchronized (mLock) {
boolean removed = false;
- for (int i = 0; i < drawableIds.length; i++) {
- String drawableId = drawableIds[i];
+ for (int i = 0; i < drawableIds.size(); i++) {
+ String drawableId = drawableIds.get(i);
removed |= mUpdatedDrawablesForStyle.remove(drawableId) != null
|| mUpdatedDrawablesForSource.remove(drawableId) != null;
}
@@ -265,11 +265,11 @@ class DeviceManagementResourcesProvider {
/**
* Returns {@code false} if no resources were removed.
*/
- boolean removeStrings(@NonNull String[] stringIds) {
+ boolean removeStrings(@NonNull List<String> stringIds) {
synchronized (mLock) {
boolean removed = false;
- for (int i = 0; i < stringIds.length; i++) {
- String stringId = stringIds[i];
+ for (int i = 0; i < stringIds.size(); i++) {
+ String stringId = stringIds.get(i);
removed |= mUpdatedStrings.remove(stringId) != null;
}
if (!removed) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3a98e4e0babf..e6b57e052293 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -27,6 +27,7 @@ import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDG
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
+import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
@@ -45,6 +46,7 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_IDS;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_DRAWABLE;
@@ -2122,7 +2124,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
+ "profile: %d", doUserId, poUserId);
Slogf.i(LOG_TAG, "Giving the PO additional power...");
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId);
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId, true);
Slogf.i(LOG_TAG, "Migrating DO policies to PO...");
moveDoPoliciesToProfileParentAdminLocked(doAdmin, poAdmin.getParentActiveAdmin());
migratePersonalAppSuspensionLocked(doUserId, poUserId, poAdmin);
@@ -14772,7 +14774,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) {
+ public void setProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId,
+ boolean isProfileOwnerOnOrganizationOwnedDevice) {
if (!mHasFeature) {
return;
}
@@ -14804,13 +14807,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Grant access under lock.
synchronized (getLockObject()) {
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId);
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(who, userId,
+ isProfileOwnerOnOrganizationOwnedDevice);
}
}
@GuardedBy("getLockObject()")
- private void markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(
- ComponentName who, int userId) {
+ private void setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(
+ ComponentName who, int userId, boolean isProfileOwnerOnOrganizationOwnedDevice) {
// Make sure that the user has a profile owner and that the specified
// component is the profile owner of that user.
if (!isProfileOwner(who, userId)) {
@@ -14819,7 +14823,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
who.flattenToString(), userId));
}
- Slogf.i(LOG_TAG, "Marking %s as profile owner on organization-owned device for user %d",
+ Slogf.i(LOG_TAG, "%s %s as profile owner on organization-owned device for user %d",
+ isProfileOwnerOnOrganizationOwnedDevice ? "Marking" : "Unmarking",
who.flattenToString(), userId);
// First, set restriction on removing the profile.
@@ -14836,15 +14841,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
+ " on user %d", parentUser.getIdentifier()));
}
- mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, true,
+ mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+ isProfileOwnerOnOrganizationOwnedDevice,
parentUser);
- mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true,
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
+ isProfileOwnerOnOrganizationOwnedDevice,
parentUser);
});
- // markProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
+ // setProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
// data, no need to do it manually.
- mOwners.markProfileOwnerOfOrganizationOwnedDevice(userId);
+ mOwners.setProfileOwnerOfOrganizationOwnedDevice(userId,
+ isProfileOwnerOnOrganizationOwnedDevice);
}
private void pushMeteredDisabledPackagesLocked(int userId) {
@@ -17781,7 +17789,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (provisioningParams.isOrganizationOwnedProvisioning()) {
synchronized (getLockObject()) {
- markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id);
+ setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id,
+ true);
}
}
@@ -17808,6 +17817,35 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ @Override
+ public void finalizeWorkProfileProvisioning(UserHandle managedProfileUser,
+ Account migratedAccount) {
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+ if (!isManagedProfile(managedProfileUser.getIdentifier())) {
+ throw new IllegalStateException("Given user is not a managed profile");
+ }
+ ComponentName profileOwnerComponent =
+ mOwners.getProfileOwnerComponent(managedProfileUser.getIdentifier());
+ if (profileOwnerComponent == null) {
+ throw new IllegalStateException("There is no profile owner on the given profile");
+ }
+ Intent primaryProfileSuccessIntent = new Intent(ACTION_MANAGED_PROFILE_PROVISIONED);
+ primaryProfileSuccessIntent.setPackage(profileOwnerComponent.getPackageName());
+ primaryProfileSuccessIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ primaryProfileSuccessIntent.putExtra(Intent.EXTRA_USER, managedProfileUser);
+
+ if (migratedAccount != null) {
+ primaryProfileSuccessIntent.putExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE,
+ migratedAccount);
+ }
+
+ mContext.sendBroadcastAsUser(primaryProfileSuccessIntent,
+ UserHandle.of(getProfileParentId(managedProfileUser.getIdentifier())));
+ }
+
/**
* Callback called at the beginning of {@link #createAndProvisionManagedProfile(
* ManagedProfileProvisioningParams, String)} after the relevant prechecks have passed.
@@ -18384,14 +18422,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
} else {
preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT);
}
- List<Integer> allowedUids = Arrays.stream(
- preferentialNetworkServiceConfig.getIncludedUids()).boxed().collect(
- Collectors.toList());
- List<Integer> excludedUids = Arrays.stream(
- preferentialNetworkServiceConfig.getExcludedUids()).boxed().collect(
- Collectors.toList());
- preferenceBuilder.setIncludedUids(allowedUids);
- preferenceBuilder.setExcludedUids(excludedUids);
+ preferenceBuilder.setIncludedUids(preferentialNetworkServiceConfig.getIncludedUids());
+ preferenceBuilder.setExcludedUids(preferentialNetworkServiceConfig.getExcludedUids());
preferenceBuilder.setPreferenceEnterpriseId(
preferentialNetworkServiceConfig.getNetworkId());
@@ -18688,13 +18720,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderWithCleanCallingIdentity(() -> {
if (mDeviceManagementResourcesProvider.updateDrawables(drawables)) {
sendDrawableUpdatedBroadcast(
- drawables.stream().map(s -> s.getDrawableId()).toArray(String[]::new));
+ drawables.stream().map(s -> s.getDrawableId()).collect(
+ Collectors.toList()));
}
});
}
@Override
- public void resetDrawables(@NonNull String[] drawableIds) {
+ public void resetDrawables(@NonNull List<String> drawableIds) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
@@ -18715,7 +18748,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
drawableId, drawableStyle, drawableSource));
}
- private void sendDrawableUpdatedBroadcast(String[] drawableIds) {
+ private void sendDrawableUpdatedBroadcast(List<String> drawableIds) {
sendResourceUpdatedBroadcast(EXTRA_RESOURCE_TYPE_DRAWABLE, drawableIds);
}
@@ -18729,12 +18762,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderWithCleanCallingIdentity(() -> {
if (mDeviceManagementResourcesProvider.updateStrings(strings))
sendStringsUpdatedBroadcast(
- strings.stream().map(s -> s.getStringId()).toArray(String[]::new));
+ strings.stream().map(s -> s.getStringId()).collect(Collectors.toList()));
});
}
@Override
- public void resetStrings(String[] stringIds) {
+ public void resetStrings(@NonNull List<String> stringIds) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
@@ -18751,13 +18784,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mDeviceManagementResourcesProvider.getString(stringId));
}
- private void sendStringsUpdatedBroadcast(String[] stringIds) {
+ private void sendStringsUpdatedBroadcast(List<String> stringIds) {
sendResourceUpdatedBroadcast(EXTRA_RESOURCE_TYPE_STRING, stringIds);
}
- private void sendResourceUpdatedBroadcast(int resourceType, String[] resourceIds) {
+ private void sendResourceUpdatedBroadcast(int resourceType, List<String> resourceIds) {
final Intent intent = new Intent(ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
- intent.putExtra(EXTRA_RESOURCE_IDS, resourceIds);
+ intent.putExtra(EXTRA_RESOURCE_IDS, resourceIds.toArray(String[]::new));
intent.putExtra(EXTRA_RESOURCE_TYPE, resourceType);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index e1d720ca25c8..1fa2f53bea17 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -340,7 +340,7 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
private int runMarkProfileOwnerOnOrganizationOwnedDevice(PrintWriter pw) {
parseArgs(/* canHaveName= */ false);
- mService.markProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId);
+ mService.setProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId, true);
pw.printf("Success\n");
return 0;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index fe8f2235ed63..b0fdd723347f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -620,18 +620,15 @@ class Owners {
}
}
- /**
- * Sets the indicator that the profile owner manages an organization-owned device,
- * then write to file.
- */
- void markProfileOwnerOfOrganizationOwnedDevice(int userId) {
+ /** Set whether the profile owner manages an organization-owned device, then write to file. */
+ void setProfileOwnerOfOrganizationOwnedDevice(int userId, boolean isOrganizationOwnedDevice) {
synchronized (mLock) {
OwnerInfo profileOwner = mProfileOwners.get(userId);
if (profileOwner != null) {
- profileOwner.isOrganizationOwnedDevice = true;
+ profileOwner.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
} else {
Slog.e(TAG, String.format(
- "No profile owner for user %d to set as org-owned.", userId));
+ "No profile owner for user %d to set org-owned flag.", userId));
}
writeProfileOwner(userId);
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 8f81e930d0cd..7a9c41256d61 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -143,6 +143,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::getLogo,
AndroidPackage::getLocaleConfigRes,
AndroidPackage::getManageSpaceActivityName,
+ AndroidPackage::getMaxSdkVersion,
AndroidPackage::getMemtagMode,
AndroidPackage::getMinSdkVersion,
AndroidPackage::getNativeHeapZeroInitialized,
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index 053551309661..8bab6d68c20e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -119,6 +119,7 @@ import android.util.Pair;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import com.android.internal.app.IAppOpsService;
import com.android.server.AppStateTracker;
import com.android.server.DeviceIdleInternal;
import com.android.server.am.AppBatteryExemptionTracker.AppBatteryExemptionPolicy;
@@ -231,6 +232,7 @@ public final class BackgroundRestrictionTest {
@Mock private MediaSessionManager mMediaSessionManager;
@Mock private RoleManager mRoleManager;
@Mock private TelephonyManager mTelephonyManager;
+ @Mock private IAppOpsService mIAppOpsService;
private long mCurrentTimeMillis;
@@ -2748,6 +2750,11 @@ public final class BackgroundRestrictionTest {
RoleManager getRoleManager() {
return BackgroundRestrictionTest.this.mRoleManager;
}
+
+ @Override
+ IAppOpsService getIAppOpsService() {
+ return BackgroundRestrictionTest.this.mIAppOpsService;
+ }
}
private class TestAppBatteryTrackerInjector extends TestBaseTrackerInjector<AppBatteryPolicy> {
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 784f732ba3b1..8d6269c93764 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -118,6 +118,7 @@ public class LocalDisplayAdapterTest {
LocalServices.removeServiceForTest(LightsManager.class);
LocalServices.addService(LightsManager.class, mMockedLightsManager);
mInjector = new Injector();
+ when(mSurfaceControlProxy.getBootDisplayModeSupport()).thenReturn(true);
mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler,
mListener, mInjector);
spyOn(mAdapter);
@@ -904,7 +905,6 @@ public class LocalDisplayAdapterTest {
.thenReturn(display.dynamicInfo);
when(mSurfaceControlProxy.getDesiredDisplayModeSpecs(display.token))
.thenReturn(display.desiredDisplayModeSpecs);
- when(mSurfaceControlProxy.getBootDisplayModeSupport()).thenReturn(true);
}
private void updateAvailableDisplays() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 6f503c7dd941..444db9128662 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -19,7 +19,9 @@ package com.android.server.pm;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
@@ -36,23 +38,21 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.os.HandlerThread;
import android.os.PowerManager;
-import android.util.ArraySet;
import com.android.server.LocalServices;
import com.android.server.PinnerService;
import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DexoptOptions;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
@@ -66,9 +66,8 @@ public final class BackgroundDexOptServiceUnitTest {
private static final long TEST_WAIT_TIMEOUT_MS = 10_000;
- private static final ArraySet<String> DEFAULT_PACKAGE_LIST = new ArraySet<>(
- Arrays.asList("aaa", "bbb"));
- private static final ArraySet<String> EMPTY_PACKAGE_LIST = new ArraySet<>();
+ private static final List<String> DEFAULT_PACKAGE_LIST = List.of("aaa", "bbb");
+ private static final List<String> EMPTY_PACKAGE_LIST = List.of();
@Mock
private Context mContext;
@@ -116,9 +115,11 @@ public final class BackgroundDexOptServiceUnitTest {
when(mInjector.getDataDirStorageLowBytes()).thenReturn(STORAGE_LOW_BYTES);
when(mInjector.getDexOptThermalCutoff()).thenReturn(PowerManager.THERMAL_STATUS_CRITICAL);
when(mInjector.getCurrentThermalStatus()).thenReturn(PowerManager.THERMAL_STATUS_NONE);
+ when(mInjector.supportSecondaryDex()).thenReturn(true);
when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(DEFAULT_PACKAGE_LIST);
when(mDexOptHelper.performDexOptWithStatus(any())).thenReturn(
PackageDexOptimizer.DEX_OPT_PERFORMED);
+ when(mDexOptHelper.performDexOpt(any())).thenReturn(true);
mService = new BackgroundDexOptService(mInjector);
}
@@ -418,26 +419,16 @@ public final class BackgroundDexOptServiceUnitTest {
verifyPerformDexOpt(DEFAULT_PACKAGE_LIST, totalJobRuns);
}
- private void verifyPerformDexOpt(ArraySet<String> pkgs, int expectedRuns) {
- ArgumentCaptor<DexoptOptions> dexOptOptions = ArgumentCaptor.forClass(DexoptOptions.class);
- verify(mDexOptHelper, atLeastOnce()).performDexOptWithStatus(dexOptOptions.capture());
- HashMap<String, Integer> primaryPkgs = new HashMap<>(); // K: pkg, V: dexopt runs left
- for (String pkg : pkgs) {
- primaryPkgs.put(pkg, expectedRuns);
- }
-
- for (DexoptOptions opt : dexOptOptions.getAllValues()) {
- assertThat(pkgs).contains(opt.getPackageName());
- assertThat(opt.isDexoptOnlySecondaryDex()).isFalse();
- Integer count = primaryPkgs.get(opt.getPackageName());
- assertThat(count).isNotNull();
- if (count == 1) {
- primaryPkgs.remove(opt.getPackageName());
- } else {
- primaryPkgs.put(opt.getPackageName(), count - 1);
+ private void verifyPerformDexOpt(List<String> pkgs, int expectedRuns) {
+ InOrder inOrder = inOrder(mDexOptHelper);
+ for (int i = 0; i < expectedRuns; i++) {
+ for (String pkg : pkgs) {
+ inOrder.verify(mDexOptHelper, times(1)).performDexOptWithStatus(argThat((option) ->
+ option.getPackageName().equals(pkg) && !option.isDexoptOnlySecondaryDex()));
+ inOrder.verify(mDexOptHelper, times(1)).performDexOpt(argThat((option) ->
+ option.getPackageName().equals(pkg) && option.isDexoptOnlySecondaryDex()));
}
}
- assertThat(primaryPkgs).isEmpty();
}
private static class StartAndWaitThread extends Thread {
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
new file mode 100644
index 000000000000..52cd29cabb94
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/TimingsTraceAndSlogTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.utils;
+
+import static android.os.Trace.TRACE_TAG_APP;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.contains;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.matches;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import android.os.Trace;
+import android.util.Slog;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.MockedVoidMethod;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoSession;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link TimingsTraceAndSlog}.
+ *
+ * <p>Usage: {@code atest FrameworksMockingServicesTests:TimingsTraceAndSlogTest}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimingsTraceAndSlogTest {
+
+ private static final String TAG = "TEST";
+
+ private MockitoSession mSession;
+
+ @Before
+ public final void startMockSession() {
+ mSession = mockitoSession()
+ .spyStatic(Slog.class)
+ .spyStatic(Trace.class)
+ .startMocking();
+ }
+
+ @After
+ public final void finishMockSession() {
+ mSession.finishMocking();
+ }
+
+ @Test
+ public void testDifferentThreads() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ // Should be able to log on the same thread
+ log.traceBegin("test");
+ log.traceEnd();
+ final List<String> errors = new ArrayList<>();
+ // Calling from a different thread should fail
+ Thread t = new Thread(() -> {
+ try {
+ log.traceBegin("test");
+ errors.add("traceBegin should fail on a different thread");
+ } catch (IllegalStateException expected) {
+ }
+ try {
+ log.traceEnd();
+ errors.add("traceEnd should fail on a different thread");
+ } catch (IllegalStateException expected) {
+ }
+ // Verify that creating a new log will work
+ TimingsTraceAndSlog log2 = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log2.traceBegin("test");
+ log2.traceEnd();
+
+ });
+ t.start();
+ t.join();
+ assertThat(errors).isEmpty();
+ }
+
+ @Test
+ public void testGetUnfinishedTracesForDebug() {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+
+ log.traceBegin("One");
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+ log.traceBegin("Two");
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One", "Two").inOrder();
+
+ log.traceEnd();
+ assertThat(log.getUnfinishedTracesForDebug()).containsExactly("One").inOrder();
+
+ log.traceEnd();
+ assertThat(log.getUnfinishedTracesForDebug()).isEmpty();
+ }
+
+ @Test
+ public void testLogDuration() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.logDuration("logro", 42);
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), contains("logro took to complete: 42ms")));
+ }
+
+ @Test
+ public void testOneLevel() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceBegin("test");
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "test"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("test took to complete: \\dms")));
+ }
+
+ @Test
+ public void testMultipleLevels() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceBegin("L1");
+ log.traceBegin("L2");
+ log.traceEnd();
+ log.traceEnd();
+
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L1"));
+ verify((MockedVoidMethod) () -> Trace.traceBegin(TRACE_TAG_APP, "L2"));
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP), times(2)); // L1 and L2
+
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L2 took to complete: \\d+ms")));
+ verify((MockedVoidMethod) () -> Slog.v(eq(TAG), matches("L1 took to complete: \\d+ms")));
+ }
+
+ @Test
+ public void testEndNoBegin() throws Exception {
+ TimingsTraceAndSlog log = new TimingsTraceAndSlog(TAG, TRACE_TAG_APP);
+ log.traceEnd();
+ verify((MockedVoidMethod) () -> Trace.traceEnd(TRACE_TAG_APP));
+ verify((MockedVoidMethod) () -> Slog.d(eq(TAG), anyString()), never());
+ verify((MockedVoidMethod) () -> Slog.w(TAG, "traceEnd called more times than traceBegin"));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index f3a0b7fa1ea7..0780d219dc80 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -45,13 +46,16 @@ import android.content.IntentFilter;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.DisplayManagerInternal;
import android.os.Looper;
+import android.view.DisplayInfo;
import android.view.MagnificationSpec;
import android.view.accessibility.MagnificationAnimationCallback;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.wm.WindowManagerInternal;
@@ -113,6 +117,8 @@ public class FullScreenMagnificationControllerTest {
FullScreenMagnificationController mFullScreenMagnificationController;
+ public DisplayManagerInternal mDisplayManagerInternalMock = mock(DisplayManagerInternal.class);
+
@Before
public void setUp() {
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
@@ -125,6 +131,12 @@ public class FullScreenMagnificationControllerTest {
when(mMockControllerCtx.getAnimationDuration()).thenReturn(1000L);
initMockWindowManager();
+ final DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.logicalDensityDpi = 300;
+ doReturn(displayInfo).when(mDisplayManagerInternalMock).getDisplayInfo(anyInt());
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+
mFullScreenMagnificationController = new FullScreenMagnificationController(
mMockControllerCtx, new Object(), mRequestObserver, mScaleProvider);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
index eab96c09a00a..c17347320f52 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
@@ -72,9 +72,11 @@ public class BiometricSchedulerOperationTest {
@Mock
private ClientMonitorCallback mClientCallback;
@Mock
+ private ClientMonitorCallback mOnStartCallback;
+ @Mock
private FakeHal mHal;
@Captor
- ArgumentCaptor<ClientMonitorCallback> mStartCallback;
+ ArgumentCaptor<ClientMonitorCallback> mStartedCallbackCaptor;
private Handler mHandler;
private BiometricSchedulerOperation mOperation;
@@ -91,17 +93,17 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(cookie);
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- assertThat(mOperation.isReadyToStart()).isEqualTo(cookie);
+ assertThat(mOperation.isReadyToStart(mOnStartCallback)).isEqualTo(cookie);
assertThat(mOperation.isStarted()).isFalse();
assertThat(mOperation.isCanceling()).isFalse();
assertThat(mOperation.isFinished()).isFalse();
+ verify(mClientMonitor).waitForCookie(any());
- final boolean started = mOperation.startWithCookie(
- mock(ClientMonitorCallback.class), cookie);
+ final boolean started = mOperation.startWithCookie(mOnStartCallback, cookie);
assertThat(started).isTrue();
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
assertThat(mOperation.isStarted()).isTrue();
}
@@ -112,14 +114,15 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(goodCookie);
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- assertThat(mOperation.isReadyToStart()).isEqualTo(goodCookie);
- final boolean started = mOperation.startWithCookie(
- mock(ClientMonitorCallback.class), badCookie);
+ assertThat(mOperation.isReadyToStart(mOnStartCallback)).isEqualTo(goodCookie);
+ final boolean started = mOperation.startWithCookie(mOnStartCallback, badCookie);
assertThat(started).isFalse();
assertThat(mOperation.isStarted()).isFalse();
assertThat(mOperation.isCanceling()).isFalse();
assertThat(mOperation.isFinished()).isFalse();
+ verify(mClientMonitor).waitForCookie(any());
+ verify(mClientMonitor, never()).start(any());
}
@Test
@@ -127,26 +130,25 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(0);
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
- mOperation.start(cb);
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
+ mOperation.start(mOnStartCallback);
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
assertThat(mOperation.isStarted()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
assertThat(mOperation.isFinished()).isFalse();
verify(mClientCallback).onClientStarted(eq(mClientMonitor));
- verify(cb).onClientStarted(eq(mClientMonitor));
+ verify(mOnStartCallback).onClientStarted(eq(mClientMonitor));
verify(mClientCallback, never()).onClientFinished(any(), anyBoolean());
- verify(cb, never()).onClientFinished(any(), anyBoolean());
+ verify(mOnStartCallback, never()).onClientFinished(any(), anyBoolean());
- mStartCallback.getValue().onClientFinished(mClientMonitor, true);
+ mStartedCallbackCaptor.getValue().onClientFinished(mClientMonitor, true);
assertThat(mOperation.isFinished()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
verify(mClientMonitor).destroy();
- verify(cb).onClientFinished(eq(mClientMonitor), eq(true));
+ verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(true));
}
@Test
@@ -154,8 +156,7 @@ public class BiometricSchedulerOperationTest {
when(mClientMonitor.getCookie()).thenReturn(0);
when(mClientMonitor.getFreshDaemon()).thenReturn(null);
- final ClientMonitorCallback cb = mock(ClientMonitorCallback.class);
- mOperation.start(cb);
+ mOperation.start(mOnStartCallback);
verify(mClientMonitor, never()).start(any());
assertThat(mOperation.isStarted()).isFalse();
@@ -163,9 +164,9 @@ public class BiometricSchedulerOperationTest {
assertThat(mOperation.isFinished()).isTrue();
verify(mClientCallback, never()).onClientStarted(eq(mClientMonitor));
- verify(cb, never()).onClientStarted(eq(mClientMonitor));
+ verify(mOnStartCallback, never()).onClientStarted(eq(mClientMonitor));
verify(mClientCallback).onClientFinished(eq(mClientMonitor), eq(false));
- verify(cb).onClientFinished(eq(mClientMonitor), eq(false));
+ verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
}
@Test
@@ -179,7 +180,7 @@ public class BiometricSchedulerOperationTest {
public void cannotRestart() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- mOperation.start(mock(ClientMonitorCallback.class));
+ mOperation.start(mOnStartCallback);
assertThrows(IllegalStateException.class,
() -> mOperation.start(mock(ClientMonitorCallback.class)));
@@ -202,7 +203,7 @@ public class BiometricSchedulerOperationTest {
public void cannotAbortRunning() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- mOperation.start(mock(ClientMonitorCallback.class));
+ mOperation.start(mOnStartCallback);
assertThrows(IllegalStateException.class, () -> mOperation.abort());
}
@@ -211,11 +212,10 @@ public class BiometricSchedulerOperationTest {
public void cancel() {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final ClientMonitorCallback startCb = mock(ClientMonitorCallback.class);
final ClientMonitorCallback cancelCb = mock(ClientMonitorCallback.class);
- mOperation.start(startCb);
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
+ mOperation.start(mOnStartCallback);
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
mOperation.cancel(mHandler, cancelCb);
assertThat(mOperation.isCanceling()).isTrue();
@@ -223,7 +223,7 @@ public class BiometricSchedulerOperationTest {
verify(mClientMonitor, never()).cancelWithoutStarting(any());
verify(mClientMonitor, never()).destroy();
- mStartCallback.getValue().onClientFinished(mClientMonitor, true);
+ mStartedCallbackCaptor.getValue().onClientFinished(mClientMonitor, true);
assertThat(mOperation.isFinished()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
@@ -315,12 +315,10 @@ public class BiometricSchedulerOperationTest {
private void cancelWatchdog(boolean start) {
when(mClientMonitor.getFreshDaemon()).thenReturn(mHal);
- final ClientMonitorCallback opStartCallback = mock(ClientMonitorCallback.class);
- mOperation.start(opStartCallback);
+ mOperation.start(mOnStartCallback);
if (start) {
- verify(mClientMonitor).start(mStartCallback.capture());
- mStartCallback.getValue().onClientStarted(mClientMonitor);
- verify(opStartCallback).onClientStarted(eq(mClientMonitor));
+ verify(mClientMonitor).start(mStartedCallbackCaptor.capture());
+ mStartedCallbackCaptor.getValue().onClientStarted(mClientMonitor);
}
mOperation.cancel(mHandler, mock(ClientMonitorCallback.class));
@@ -331,7 +329,7 @@ public class BiometricSchedulerOperationTest {
assertThat(mOperation.isFinished()).isTrue();
assertThat(mOperation.isCanceling()).isFalse();
- verify(opStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
+ verify(mOnStartCallback).onClientFinished(eq(mClientMonitor), eq(false));
verify(mClientMonitor).destroy();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 0fa2b41e8b32..45e3b4373266 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -196,7 +196,8 @@ public class BiometricSchedulerTest {
// Schedule a BiometricPrompt authentication request
mScheduler.scheduleClientMonitor(client1, callback1);
- assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart());
+ assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart(
+ mock(ClientMonitorCallback.class)));
assertEquals(client1, mScheduler.mCurrentOperation.getClientMonitor());
assertEquals(0, mScheduler.mPendingOperations.size());
@@ -436,7 +437,8 @@ public class BiometricSchedulerTest {
if (started || isEnroll) { // prep'd auth clients and enroll clients
assertTrue(mScheduler.mCurrentOperation.isStarted());
} else {
- assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart());
+ assertNotEquals(0, mScheduler.mCurrentOperation.isReadyToStart(
+ mock(ClientMonitorCallback.class)));
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
index dc39b6d573db..5012335b533f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.hardware.biometrics.BiometricOverlayConstants;
import android.hardware.fingerprint.ISidefpsController;
@@ -29,6 +30,7 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
@@ -43,6 +45,7 @@ import java.util.List;
public class SensorOverlaysTest {
private static final int SENSOR_ID = 11;
+ private static final long REQUEST_ID = 8;
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
@@ -50,6 +53,12 @@ public class SensorOverlaysTest {
@Mock private ISidefpsController mSidefpsController;
@Mock private AcquisitionClient<?> mAcquisitionClient;
+ @Before
+ public void setup() {
+ when(mAcquisitionClient.getRequestId()).thenReturn(REQUEST_ID);
+ when(mAcquisitionClient.hasRequestId()).thenReturn(true);
+ }
+
@Test
public void noopWhenBothNull() {
final SensorOverlays useless = new SensorOverlays(null, null);
@@ -92,7 +101,8 @@ public class SensorOverlaysTest {
sensorOverlays.show(SENSOR_ID, reason, mAcquisitionClient);
if (udfps != null) {
- verify(mUdfpsOverlayController).showUdfpsOverlay(eq(SENSOR_ID), eq(reason), any());
+ verify(mUdfpsOverlayController).showUdfpsOverlay(
+ eq(REQUEST_ID), eq(SENSOR_ID), eq(reason), any());
}
if (sidefps != null) {
verify(mSidefpsController).show(eq(SENSOR_ID), eq(reason));
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
index 52eee9a55cc7..8391914a0bb6 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
@@ -18,9 +18,8 @@ package com.android.server.biometrics.sensors;
import static android.testing.TestableLooper.RunWithLooper;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -45,11 +44,15 @@ import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Supplier;
@Presubmit
@@ -61,9 +64,12 @@ public class UserAwareBiometricSchedulerTest {
private static final String TAG = "UserAwareBiometricSchedulerTest";
private static final int TEST_SENSOR_ID = 0;
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
private Handler mHandler;
private UserAwareBiometricScheduler mScheduler;
- private IBinder mToken = new Binder();
+ private final IBinder mToken = new Binder();
@Mock
private Context mContext;
@@ -74,15 +80,14 @@ public class UserAwareBiometricSchedulerTest {
@Mock
private BiometricContext mBiometricContext;
- private TestUserStartedCallback mUserStartedCallback = new TestUserStartedCallback();
- private TestUserStoppedCallback mUserStoppedCallback = new TestUserStoppedCallback();
+ private final TestUserStartedCallback mUserStartedCallback = new TestUserStartedCallback();
+ private final TestUserStoppedCallback mUserStoppedCallback = new TestUserStoppedCallback();
private int mCurrentUserId = UserHandle.USER_NULL;
private boolean mStartOperationsFinish = true;
private int mStartUserClientCount = 0;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
mHandler = new Handler(TestableLooper.get(this).getLooper());
mScheduler = new UserAwareBiometricScheduler(TAG,
mHandler,
@@ -121,8 +126,8 @@ public class UserAwareBiometricSchedulerTest {
mScheduler.scheduleClientMonitor(nextClient);
waitForIdle();
- assertEquals(0, mUserStoppedCallback.numInvocations);
- assertEquals(1, mUserStartedCallback.numInvocations);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+ assertThat(mUserStartedCallback.mStartedUsers).containsExactly(0);
verify(nextClient).start(any());
}
@@ -142,9 +147,9 @@ public class UserAwareBiometricSchedulerTest {
waitForIdle();
}
- assertEquals(0, mUserStoppedCallback.numInvocations);
- assertEquals(0, mUserStartedCallback.numInvocations);
- assertEquals(1, mStartUserClientCount);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+ assertThat(mUserStartedCallback.mStartedUsers).isEmpty();
+ assertThat(mStartUserClientCount).isEqualTo(1);
for (BaseClientMonitor client : nextClients) {
verify(client, never()).start(any());
}
@@ -163,13 +168,13 @@ public class UserAwareBiometricSchedulerTest {
final TestStartUserClient startUserClient =
(TestStartUserClient) mScheduler.mCurrentOperation.getClientMonitor();
mScheduler.reset();
- assertNull(mScheduler.mCurrentOperation);
+ assertThat(mScheduler.mCurrentOperation).isNull();
final BiometricSchedulerOperation fakeOperation = new BiometricSchedulerOperation(
mock(BaseClientMonitor.class), new ClientMonitorCallback() {});
mScheduler.mCurrentOperation = fakeOperation;
startUserClient.mCallback.onClientFinished(startUserClient, true);
- assertSame(fakeOperation, mScheduler.mCurrentOperation);
+ assertThat(fakeOperation).isSameInstanceAs(mScheduler.mCurrentOperation);
}
@Test
@@ -184,8 +189,8 @@ public class UserAwareBiometricSchedulerTest {
waitForIdle();
verify(nextClient).start(any());
- assertEquals(0, mUserStoppedCallback.numInvocations);
- assertEquals(0, mUserStartedCallback.numInvocations);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(0);
+ assertThat(mUserStartedCallback.mStartedUsers).isEmpty();
}
@Test
@@ -199,36 +204,67 @@ public class UserAwareBiometricSchedulerTest {
mScheduler.scheduleClientMonitor(nextClient);
waitForIdle();
- assertEquals(1, mUserStoppedCallback.numInvocations);
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(1);
waitForIdle();
- assertEquals(1, mUserStartedCallback.numInvocations);
+ assertThat(mUserStartedCallback.mStartedUsers).containsExactly(nextUserId);
waitForIdle();
verify(nextClient).start(any());
}
+ @Test
+ public void testStartUser_alwaysStartsNextOperation() {
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(10);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+
+ // finish first operation
+ mScheduler.getInternalCallback().onClientFinished(nextClient, true /* success */);
+ waitForIdle();
+
+ // schedule second operation but swap out the current operation
+ // before it runs so that it's not current when it's completion callback runs
+ nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(11);
+ mUserStartedCallback.mAfterStart = () -> mScheduler.mCurrentOperation = null;
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+ assertThat(mUserStartedCallback.mStartedUsers).containsExactly(10, 11).inOrder();
+ assertThat(mUserStoppedCallback.mNumInvocations).isEqualTo(1);
+ }
+
private void waitForIdle() {
TestableLooper.get(this).processAllMessages();
}
private class TestUserStoppedCallback implements StopUserClient.UserStoppedCallback {
- int numInvocations;
+ int mNumInvocations;
@Override
public void onUserStopped() {
- numInvocations++;
+ mNumInvocations++;
mCurrentUserId = UserHandle.USER_NULL;
}
}
private class TestUserStartedCallback implements StartUserClient.UserStartedCallback<Object> {
- int numInvocations;
+ final List<Integer> mStartedUsers = new ArrayList<>();
+ Runnable mAfterStart = null;
@Override
public void onUserStarted(int newUserId, Object newObject, int halInterfaceVersion) {
- numInvocations++;
+ mStartedUsers.add(newUserId);
mCurrentUserId = newUserId;
+ if (mAfterStart != null) {
+ mAfterStart.run();
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index de0f038e8ec5..6c50ca35be79 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -71,6 +71,7 @@ public class FingerprintAuthenticationClientTest {
private static final int USER_ID = 8;
private static final long OP_ID = 7;
+ private static final long REQUEST_ID = 88;
private static final int POINTER_ID = 0;
private static final int TOUCH_X = 8;
private static final int TOUCH_Y = 20;
@@ -259,7 +260,7 @@ public class FingerprintAuthenticationClientTest {
client.start(mCallback);
- verify(mUdfpsOverlayController).showUdfpsOverlay(anyInt(), anyInt(), any());
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
verify(mSideFpsController).show(anyInt(), anyInt());
block.accept(client);
@@ -277,7 +278,7 @@ public class FingerprintAuthenticationClientTest {
final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
return new FingerprintAuthenticationClient(mContext, () -> aidl, mToken,
- 2 /* requestId */, mClientMonitorCallbackConverter, 5 /* targetUserId */, OP_ID,
+ REQUEST_ID, mClientMonitorCallbackConverter, 5 /* targetUserId */, OP_ID,
false /* restricted */, "test-owner", 4 /* cookie */, false /* requireConfirmation */,
9 /* sensorId */, mBiometricLogger, mBiometricContext,
true /* isStrongBiometric */,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index 5a96f5cca52a..f77eb0bcc59f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -72,6 +72,7 @@ public class FingerprintEnrollClientTest {
private static final byte[] HAT = new byte[69];
private static final int USER_ID = 8;
+ private static final long REQUEST_ID = 9;
private static final int POINTER_ID = 0;
private static final int TOUCH_X = 8;
private static final int TOUCH_Y = 20;
@@ -256,7 +257,7 @@ public class FingerprintEnrollClientTest {
client.start(mCallback);
- verify(mUdfpsOverlayController).showUdfpsOverlay(anyInt(), anyInt(), any());
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
verify(mSideFpsController).show(anyInt(), anyInt());
block.accept(client);
@@ -273,7 +274,7 @@ public class FingerprintEnrollClientTest {
when(mHal.getInterfaceVersion()).thenReturn(version);
final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
- return new FingerprintEnrollClient(mContext, () -> aidl, mToken, 6 /* requestId */,
+ return new FingerprintEnrollClient(mContext, () -> aidl, mToken, REQUEST_ID,
mClientMonitorCallbackConverter, 0 /* userId */,
HAT, "owner", mBiometricUtils, 8 /* sensorId */,
mBiometricLogger, mBiometricContext, mSensorProps, mUdfpsOverlayController,
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 1ebcbe10fae6..a2409b8bef0f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4260,14 +4260,11 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
.isEnabled()).isTrue();
- List<Integer> includedList = new ArrayList<>();
- includedList.add(1);
- includedList.add(2);
ProfileNetworkPreference preferenceDetails =
new ProfileNetworkPreference.Builder()
.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
- .setIncludedUids(includedList)
+ .setIncludedUids(new int[]{1, 2})
.build();
List<ProfileNetworkPreference> preferences = new ArrayList<>();
preferences.add(preferenceDetails);
@@ -4295,14 +4292,11 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
.isEnabled()).isTrue();
- List<Integer> excludedUids = new ArrayList<>();
- excludedUids.add(1);
- excludedUids.add(2);
ProfileNetworkPreference preferenceDetails =
new ProfileNetworkPreference.Builder()
.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK)
.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1)
- .setExcludedUids(excludedUids)
+ .setExcludedUids(new int[]{1, 2})
.build();
List<ProfileNetworkPreference> preferences = new ArrayList<>();
preferences.clear();
@@ -6671,7 +6665,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mContext, false);
assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin2));
+ () -> dpm.setProfileOwnerOnOrganizationOwnedDevice(admin2, true));
}
@Test
@@ -6680,7 +6674,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mContext, false);
assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1));
+ () -> dpm.setProfileOwnerOnOrganizationOwnedDevice(admin1, true));
}
@Test
@@ -6715,7 +6709,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
DpmMockContext.CALLER_MANAGED_PROVISIONING_UID);
try {
runAsCaller(mServiceContext, dpms, dpm -> {
- dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1);
+ dpm.setProfileOwnerOnOrganizationOwnedDevice(admin1, true);
});
} finally {
mServiceContext.binder.restoreCallingIdentity(ident);
@@ -7050,7 +7044,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mServiceContext, true);
runAsCaller(mServiceContext, dpms, dpm -> {
- dpm.markProfileOwnerOnOrganizationOwnedDevice(who);
+ dpm.setProfileOwnerOnOrganizationOwnedDevice(who, true);
});
mServiceContext.binder.restoreCallingIdentity(ident);
}
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
new file mode 100644
index 000000000000..26a83a23de33
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/ColorFadeTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.display;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManagerInternal;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ColorFadeTest {
+ private static final int DISPLAY_ID = 123;
+
+ private Context mContext;
+
+ @Mock private DisplayManagerInternal mDisplayManagerInternalMock;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
+ mContext = getInstrumentation().getTargetContext();
+ }
+
+ @After
+ public void tearDown() {
+ LocalServices.removeServiceForTest(DisplayManagerInternal.class);
+ }
+
+ @Test
+ public void testPrepareColorFadeForInvalidDisplay() {
+ when(mDisplayManagerInternalMock.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(null);
+ ColorFade colorFade = new ColorFade(DISPLAY_ID);
+ assertFalse(colorFade.prepare(mContext, ColorFade.MODE_FADE));
+ }
+
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 99edecfeed30..c78678431dac 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -16,7 +16,6 @@
package com.android.server.pm;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundlesEqual;
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertEmpty;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
@@ -37,6 +36,8 @@ import android.app.Person;
import android.content.ComponentName;
import android.content.Intent;
import android.content.LocusId;
+import android.content.pm.Capability;
+import android.content.pm.CapabilityParams;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
@@ -258,10 +259,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
.setLongLived(true)
.setExtras(pb)
.setStartingTheme(android.R.style.Theme_Black_NoTitleBar_Fullscreen)
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.type", list("running", "jogging"))
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.duration", list("10m"))
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging")
+ .build())
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m")
+ .build())
.build();
si.addFlags(ShortcutInfo.FLAG_PINNED);
si.setBitmapPath("abc");
@@ -299,13 +305,14 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertEquals(null, si.getDisabledMessageResName());
assertEquals("android:style/Theme.Black.NoTitleBar.Fullscreen",
si.getStartingThemeResName());
- assertTrue(si.hasCapability("action.intent.START_EXERCISE"));
- assertFalse(si.hasCapability(""));
- assertFalse(si.hasCapability("random"));
- assertEquals(list("running", "jogging"), si.getCapabilityParameterValues(
- "action.intent.START_EXERCISE", "exercise.type"));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", ""));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", "random"));
+ assertEquals(list(new Capability.Builder("action.intent.START_EXERCISE").build()),
+ si.getCapabilities());
+ assertEquals(list(
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m").build()),
+ si.getCapabilityParams(
+ new Capability.Builder("action.intent.START_EXERCISE").build()));
}
public void testShortcutInfoParcel_resId() {
@@ -959,10 +966,15 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
.setRank(123)
.setExtras(pb)
.setLocusId(new LocusId("1.2.3.4.5"))
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.type", list("running", "jogging"))
- .addCapabilityBinding("action.intent.START_EXERCISE",
- "exercise.duration", list("10m"))
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging")
+ .build())
+ .addCapabilityBinding(
+ new Capability.Builder("action.intent.START_EXERCISE").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m")
+ .build())
.build();
sorig.setTimestamp(mInjectedCurrentTimeMillis);
@@ -1024,13 +1036,14 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
assertNull(si.getIconUri());
assertTrue(si.getLastChangedTimestamp() < now);
- assertTrue(si.hasCapability("action.intent.START_EXERCISE"));
- assertFalse(si.hasCapability(""));
- assertFalse(si.hasCapability("random"));
- assertEquals(list("running", "jogging"), si.getCapabilityParameterValues(
- "action.intent.START_EXERCISE", "exercise.type"));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", ""));
- assertEmpty(si.getCapabilityParameterValues("action.intent.START_EXERCISE", "random"));
+ assertEquals(list(new Capability.Builder("action.intent.START_EXERCISE").build()),
+ si.getCapabilities());
+ assertEquals(list(
+ new CapabilityParams.Builder("exercise.type", "running")
+ .addAlias("jogging").build(),
+ new CapabilityParams.Builder("exercise.duration", "10m").build()),
+ si.getCapabilityParams(
+ new Capability.Builder("action.intent.START_EXERCISE").build()));
// Make sure ranks are saved too. Because of the auto-adjusting, we need two shortcuts
// to test it.
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index 0eba6a335d00..0187e34cbc5f 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -224,6 +224,11 @@ public class SoundTriggerMiddlewareImplTest {
// Stop the recognition.
stopRecognition(module, handle, hwHandle);
+ ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+ RecognitionEvent.class);
+ verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
+ assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
+
// Unload the model.
unloadModel(module, handle, hwHandle);
module.detach();
@@ -268,6 +273,11 @@ public class SoundTriggerMiddlewareImplTest {
// Stop the recognition.
stopRecognition(module, handle, hwHandle);
+ ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
+ PhraseRecognitionEvent.class);
+ verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
+ assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
+
// Unload the model.
unloadModel(module, handle, hwHandle);
module.detach();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index f9aa4b17bc2c..9902e83c3648 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -500,6 +500,23 @@ public class ActivityStarterTests extends WindowTestsBase {
return Pair.create(splitPrimaryActivity, splitSecondActivity);
}
+ @Test
+ public void testMoveVisibleTaskToFront() {
+ final ActivityRecord activity = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true).build().getTopMostActivity();
+ final ActivityRecord translucentActivity = new TaskBuilder(mSupervisor)
+ .setCreateActivity(true).build().getTopMostActivity();
+ assertTrue(activity.mVisibleRequested);
+
+ final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+ false /* mockGetRootTask */);
+ starter.getIntent().setComponent(activity.mActivityComponent);
+ final int result = starter.setReason("testMoveVisibleTaskToFront").execute();
+
+ assertEquals(START_TASK_TO_FRONT, result);
+ assertEquals(1, activity.compareTo(translucentActivity));
+ }
+
/**
* Tests activity is cleaned up properly in a task mode violation.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 50eefa066a45..c5117bb83976 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -19,12 +19,12 @@ package com.android.server.wm;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
-import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.ContentRecorder.KEY_RECORD_TASK_FEATURE;
import static com.google.common.truth.Truth.assertThat;
@@ -40,17 +40,22 @@ import android.hardware.display.VirtualDisplay;
import android.os.Binder;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
import android.util.DisplayMetrics;
import android.view.ContentRecordingSession;
import android.view.Surface;
import android.view.SurfaceControl;
+import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.CountDownLatch;
+
/**
* Tests for the {@link ContentRecorder} class.
*
@@ -62,17 +67,18 @@ import org.junit.runner.RunWith;
@RunWith(WindowTestRunner.class)
public class ContentRecorderTests extends WindowTestsBase {
private static final IBinder TEST_TOKEN = new RecordingTestToken();
- private final ContentRecordingSession mDefaultSession =
+ private static IBinder sTaskWindowContainerToken;
+ private final ContentRecordingSession mDisplaySession =
ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+ private ContentRecordingSession mTaskSession;
private static Point sSurfaceSize;
private ContentRecorder mContentRecorder;
private SurfaceControl mRecordedSurface;
+ // Handle feature flag.
+ private ConfigListener mConfigListener;
+ private CountDownLatch mLatch;
@Before public void setUp() {
- // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
- // mirror.
- setUpDefaultTaskDisplayAreaWindowToken();
-
// GIVEN SurfaceControl can successfully mirror the provided surface.
sSurfaceSize = new Point(
mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
@@ -84,12 +90,32 @@ public class ContentRecorderTests extends WindowTestsBase {
sSurfaceSize.x, sSurfaceSize.y,
DisplayMetrics.DENSITY_140, new Surface(), VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
final int displayId = virtualDisplay.getDisplay().getDisplayId();
- mDefaultSession.setDisplayId(displayId);
-
mWm.mRoot.onDisplayAdded(displayId);
- final DisplayContent mVirtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
- mContentRecorder = new ContentRecorder(mVirtualDisplayContent);
- spyOn(mVirtualDisplayContent);
+ final DisplayContent virtualDisplayContent = mWm.mRoot.getDisplayContent(displayId);
+ mContentRecorder = new ContentRecorder(virtualDisplayContent);
+ spyOn(virtualDisplayContent);
+
+ // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+ // record.
+ setUpDefaultTaskDisplayAreaWindowToken();
+ mDisplaySession.setDisplayId(displayId);
+
+ // GIVEN there is a window token associated with a task to record.
+ sTaskWindowContainerToken = setUpTaskWindowContainerToken(virtualDisplayContent);
+ mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
+ mTaskSession.setDisplayId(displayId);
+
+ mConfigListener = new ConfigListener();
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ mContext.getMainExecutor(), mConfigListener);
+ mLatch = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+ "true", true);
+ }
+
+ @After
+ public void teardown() {
+ DeviceConfig.removeOnPropertiesChangedListener(mConfigListener);
}
@Test
@@ -102,37 +128,79 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testUpdateRecording_display() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
}
@Test
- public void testUpdateRecording_task() {
- mDefaultSession.setContentToRecord(RECORD_CONTENT_TASK);
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ public void testUpdateRecording_display_nullToken() {
+ ContentRecordingSession session = ContentRecordingSession.createDisplaySession(TEST_TOKEN);
+ session.setDisplayId(mDisplaySession.getDisplayId());
+ session.setTokenToRecord(null);
+ mContentRecorder.setContentRecordingSession(session);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
}
@Test
- public void testUpdateRecording_wasPaused() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ public void testUpdateRecording_display_noWindowContainer() {
+ doReturn(null).when(
+ mWm.mWindowContextListenerController).getContainer(any());
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
- mContentRecorder.pauseRecording();
+ @Test
+ public void testUpdateRecording_task_featureDisabled() {
+ mLatch = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, KEY_RECORD_TASK_FEATURE,
+ "false", false);
+ mContentRecorder.setContentRecordingSession(mTaskSession);
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ }
+
+ @Test
+ public void testUpdateRecording_task_featureEnabled() {
+ // Feature already enabled; don't need to again.
+ mContentRecorder.setContentRecordingSession(mTaskSession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
}
@Test
- public void testUpdateRecording_wasStopped() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ public void testUpdateRecording_task_nullToken() {
+ ContentRecordingSession session = ContentRecordingSession.createTaskSession(
+ sTaskWindowContainerToken);
+ session.setDisplayId(mDisplaySession.getDisplayId());
+ session.setTokenToRecord(null);
+ mContentRecorder.setContentRecordingSession(session);
mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+ }
- mContentRecorder.remove();
+ @Test
+ public void testUpdateRecording_task_noWindowContainer() {
+ // Use the window container token of the DisplayContent, rather than task.
+ ContentRecordingSession invalidTaskSession = ContentRecordingSession.createTaskSession(
+ new WindowContainer.RemoteToken(mDisplayContent));
+ mContentRecorder.setContentRecordingSession(invalidTaskSession);
mContentRecorder.updateRecording();
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
+ // TODO(b/219761722) validate VirtualDisplay is torn down when can't set up task recording.
+ }
+
+ @Test
+ public void testUpdateRecording_wasPaused() {
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
+ mContentRecorder.updateRecording();
+
+ mContentRecorder.pauseRecording();
+ mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
}
@Test
@@ -146,7 +214,7 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testOnConfigurationChanged_resizesSurface() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
@@ -158,7 +226,7 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testPauseRecording_pausesRecording() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.pauseRecording();
@@ -173,7 +241,7 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testRemove_stopsRecording() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
mContentRecorder.remove();
@@ -188,8 +256,9 @@ public class ContentRecorderTests extends WindowTestsBase {
@Test
public void testUpdateMirroredSurface_capturedAreaResized() {
- mContentRecorder.setContentRecordingSession(mDefaultSession);
+ mContentRecorder.setContentRecordingSession(mDisplaySession);
mContentRecorder.updateRecording();
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// WHEN attempting to mirror on the virtual display, and the captured content is resized.
float xScale = 0.7f;
@@ -197,13 +266,14 @@ public class ContentRecorderTests extends WindowTestsBase {
Rect displayAreaBounds = new Rect(0, 0, Math.round(sSurfaceSize.x * xScale),
Math.round(sSurfaceSize.y * yScale));
mContentRecorder.updateMirroredSurface(mTransaction, displayAreaBounds, sSurfaceSize);
+ assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
// THEN content in the captured DisplayArea is scaled to fit the surface size.
verify(mTransaction, atLeastOnce()).setMatrix(mRecordedSurface, 1.0f / yScale, 0, 0,
1.0f / yScale);
// THEN captured content is positioned in the centre of the output surface.
- float scaledWidth = displayAreaBounds.width() / xScale;
- float xInset = (sSurfaceSize.x - scaledWidth) / 2;
+ int scaledWidth = Math.round((float) displayAreaBounds.width() / xScale);
+ int xInset = (sSurfaceSize.x - scaledWidth) / 2;
verify(mTransaction, atLeastOnce()).setPosition(mRecordedSurface, xInset, 0);
}
@@ -222,6 +292,18 @@ public class ContentRecorderTests extends WindowTestsBase {
}
/**
+ * Creates a {@link android.window.WindowContainerToken} associated with a task, in order for
+ * that task to be recorded.
+ */
+ private IBinder setUpTaskWindowContainerToken(DisplayContent displayContent) {
+ final Task rootTask = createTask(displayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+ // Ensure the task is not empty.
+ createActivityRecord(displayContent, task);
+ return task.getTaskInfo().token.asBinder();
+ }
+
+ /**
* SurfaceControl successfully creates a mirrored surface of the given size.
*/
private SurfaceControl surfaceControlMirrors(Point surfaceSize) {
@@ -236,4 +318,13 @@ public class ContentRecorderTests extends WindowTestsBase {
anyInt());
return mirroredSurface;
}
+
+ private class ConfigListener implements DeviceConfig.OnPropertiesChangedListener {
+ @Override
+ public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+ if (mLatch != null && properties.getKeyset().contains(KEY_RECORD_TASK_FEATURE)) {
+ mLatch.countDown();
+ }
+ }
+ }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index b9abbf09e74d..93c03865dc3f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2015,7 +2015,7 @@ public class UsageStatsService extends SystemService implements
== PackageManager.PERMISSION_GRANTED;
}
- private boolean hasPermissions(String callingPackage, String... permissions) {
+ private boolean hasPermissions(String... permissions) {
final int callingUid = Binder.getCallingUid();
if (callingUid == Process.SYSTEM_UID) {
// Caller is the system, so proceed.
@@ -2578,7 +2578,7 @@ public class UsageStatsService extends SystemService implements
String callingPackage) {
final int callingUid = Binder.getCallingUid();
final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
- if (!hasPermissions(callingPackage,
+ if (!hasPermissions(
Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
&& (dpmInternal == null || !dpmInternal.isActiveSupervisionApp(callingUid))) {
throw new SecurityException("Caller must be the active supervision app or "
@@ -2605,7 +2605,7 @@ public class UsageStatsService extends SystemService implements
public void unregisterAppUsageLimitObserver(int observerId, String callingPackage) {
final int callingUid = Binder.getCallingUid();
final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
- if (!hasPermissions(callingPackage,
+ if (!hasPermissions(
Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)
&& (dpmInternal == null || !dpmInternal.isActiveSupervisionApp(callingUid))) {
throw new SecurityException("Caller must be the active supervision app or "
@@ -2703,8 +2703,7 @@ public class UsageStatsService extends SystemService implements
@Override
public long getLastTimeAnyComponentUsed(String packageName, String callingPackage) {
- if (!hasPermissions(
- callingPackage, android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+ if (!hasPermissions(android.Manifest.permission.INTERACT_ACROSS_USERS)) {
throw new SecurityException("Caller doesn't have INTERACT_ACROSS_USERS permission");
}
if (!hasPermission(callingPackage)) {
@@ -2787,6 +2786,17 @@ public class UsageStatsService extends SystemService implements
"clearBroadcastResponseStats" /* name */, callingPackage);
mResponseStatsTracker.clearBroadcastEvents(callingUid, userId);
}
+
+ @Override
+ @Nullable
+ public String getAppStandbyConstant(@NonNull String key) {
+ Objects.requireNonNull(key);
+
+ if (!hasPermissions(Manifest.permission.READ_DEVICE_CONFIG)) {
+ throw new SecurityException("Caller doesn't have READ_DEVICE_CONFIG permission");
+ }
+ return mAppStandby.getAppStandbyConstant(key);
+ }
}
void registerAppUsageObserver(int callingUid, int observerId, String[] packages,
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 24ce7e76a49c..c8bcb83cae74 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -84,6 +84,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private static final int INVALID_VALUE = Integer.MIN_VALUE;
+ /** Maximum time to wait for a model stop confirmation before giving up. */
+ private static final long STOP_TIMEOUT_MS = 5000;
+
/** The {@link ModuleProperties} for the system, or null if none exists. */
final ModuleProperties mModuleProperties;
@@ -831,7 +834,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
if (!event.recognitionStillActive) {
- model.setStopped();
+ model.setStoppedLocked();
}
try {
@@ -918,7 +921,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
MetricsLogger.count(mContext, "sth_recognition_aborted", 1);
ModelData modelData = getModelDataForLocked(event.soundModelHandle);
if (modelData != null && modelData.isModelStarted()) {
- modelData.setStopped();
+ modelData.setStoppedLocked();
try {
modelData.getCallback().onRecognitionPaused();
} catch (DeadObjectException e) {
@@ -972,7 +975,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
if (!event.recognitionStillActive) {
- modelData.setStopped();
+ modelData.setStoppedLocked();
}
try {
@@ -1200,7 +1203,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
if (modelData.isModelStarted()) {
Slog.d(TAG, "Stopping previously started dangling model " + modelData.getHandle());
if (mModule.stopRecognition(modelData.getHandle()) == STATUS_OK) {
- modelData.setStopped();
+ modelData.setStoppedLocked();
modelData.setRequested(false);
} else {
Slog.e(TAG, "Failed to stop model " + modelData.getHandle());
@@ -1249,7 +1252,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private ModelData getOrCreateGenericModelDataLocked(UUID modelId) {
ModelData modelData = mModelDataMap.get(modelId);
if (modelData == null) {
- modelData = ModelData.createGenericModelData(modelId);
+ modelData = createGenericModelData(modelId);
mModelDataMap.put(modelId, modelData);
} else if (!modelData.isGenericModel()) {
Slog.e(TAG, "UUID already used for non-generic model.");
@@ -1281,7 +1284,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mKeyphraseUuidMap.remove(keyphraseId);
mModelDataMap.remove(modelId);
mKeyphraseUuidMap.put(keyphraseId, modelId);
- ModelData modelData = ModelData.createKeyphraseModelData(modelId);
+ ModelData modelData = createKeyphraseModelData(modelId);
mModelDataMap.put(modelId, modelData);
return modelData;
}
@@ -1413,18 +1416,26 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
Slog.w(TAG, "RemoteException in onError", e);
}
}
- } else {
- modelData.setStopped();
- MetricsLogger.count(mContext, "sth_stop_recognition_success", 1);
- // Notify of pause if needed.
- if (notify) {
- try {
- callback.onRecognitionPaused();
- } catch (DeadObjectException e) {
- forceStopAndUnloadModelLocked(modelData, e);
- } catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
- }
+ return status;
+ }
+
+ // Wait for model to be stopped.
+ try {
+ modelData.waitStoppedLocked(STOP_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Didn't receive model stop callback");
+ return SoundTrigger.STATUS_ERROR;
+ }
+
+ MetricsLogger.count(mContext, "sth_stop_recognition_success", 1);
+ // Notify of pause if needed.
+ if (notify) {
+ try {
+ callback.onRecognitionPaused();
+ } catch (DeadObjectException e) {
+ forceStopAndUnloadModelLocked(modelData, e);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in onRecognitionPaused", e);
}
}
if (DBG) {
@@ -1459,7 +1470,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// This class encapsulates the callbacks, state, handles and any other information that
// represents a model.
- private static class ModelData {
+ private class ModelData {
// Model not loaded (and hence not started).
static final int MODEL_NOTLOADED = 0;
@@ -1516,17 +1527,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mModelType = modelType;
}
- static ModelData createKeyphraseModelData(UUID modelId) {
- return new ModelData(modelId, SoundModel.TYPE_KEYPHRASE);
- }
-
- static ModelData createGenericModelData(UUID modelId) {
- return new ModelData(modelId, SoundModel.TYPE_GENERIC_SOUND);
- }
-
// Note that most of the functionality in this Java class will not work for
// SoundModel.TYPE_UNKNOWN nevertheless we have it since lower layers support it.
- static ModelData createModelDataOfUnknownType(UUID modelId) {
+ ModelData createModelDataOfUnknownType(UUID modelId) {
return new ModelData(modelId, SoundModel.TYPE_UNKNOWN);
}
@@ -1550,8 +1553,20 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mModelState = MODEL_STARTED;
}
- synchronized void setStopped() {
+ synchronized void setStoppedLocked() {
mModelState = MODEL_LOADED;
+ mLock.notifyAll();
+ }
+
+ void waitStoppedLocked(long timeoutMs) throws InterruptedException {
+ long deadline = System.currentTimeMillis() + timeoutMs;
+ while (mModelState == MODEL_STARTED) {
+ long waitTime = deadline - System.currentTimeMillis();
+ if (waitTime <= 0) {
+ throw new InterruptedException();
+ }
+ mLock.wait(waitTime);
+ }
}
synchronized void setLoaded() {
@@ -1571,6 +1586,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mRecognitionConfig = null;
mRequested = false;
mCallback = null;
+ notifyAll();
}
synchronized void clearCallback() {
@@ -1675,4 +1691,12 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return "Model type: " + type + "\n";
}
}
+
+ ModelData createKeyphraseModelData(UUID modelId) {
+ return new ModelData(modelId, SoundModel.TYPE_KEYPHRASE);
+ }
+
+ ModelData createGenericModelData(UUID modelId) {
+ return new ModelData(modelId, SoundModel.TYPE_GENERIC_SOUND);
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 398889213ce5..d527a230a97b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
import static android.Manifest.permission.RECORD_AUDIO;
import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_EXTERNAL;
import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_MICROPHONE;
+import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_SUCCESS;
import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_UNKNOWN;
import static android.service.voice.HotwordDetectionService.KEY_INITIALIZATION_STATUS;
@@ -330,15 +331,16 @@ final class HotwordDetectionConnection {
return new Pair<>(INITIALIZATION_STATUS_UNKNOWN, METRICS_INIT_UNKNOWN_NO_VALUE);
}
int status = bundle.getInt(KEY_INITIALIZATION_STATUS, INITIALIZATION_STATUS_UNKNOWN);
- if (status > HotwordDetectionService.getMaxCustomInitializationStatus()
- && status != INITIALIZATION_STATUS_UNKNOWN) {
+ if (status > HotwordDetectionService.getMaxCustomInitializationStatus()) {
return new Pair<>(INITIALIZATION_STATUS_UNKNOWN,
- METRICS_INIT_UNKNOWN_OVER_MAX_CUSTOM_VALUE);
+ status == INITIALIZATION_STATUS_UNKNOWN
+ ? METRICS_INIT_UNKNOWN_NO_VALUE
+ : METRICS_INIT_UNKNOWN_OVER_MAX_CUSTOM_VALUE);
}
// TODO: should guard against negative here
- int metricsResult = status == INITIALIZATION_STATUS_UNKNOWN
- ? METRICS_INIT_CALLBACK_STATE_ERROR
- : METRICS_INIT_CALLBACK_STATE_SUCCESS;
+ int metricsResult = status == INITIALIZATION_STATUS_SUCCESS
+ ? METRICS_INIT_CALLBACK_STATE_SUCCESS
+ : METRICS_INIT_CALLBACK_STATE_ERROR;
return new Pair<>(status, metricsResult);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3f430ab77df4..f3139a70eade 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9815,15 +9815,7 @@ public class TelephonyManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @Nullable String getCarrierServicePackageName() {
- // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the
- // value instead of re-querying every time.
- List<String> carrierServicePackages =
- getCarrierPackageNamesForIntent(
- new Intent(CarrierService.CARRIER_SERVICE_INTERFACE));
- if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) {
- return carrierServicePackages.get(0);
- }
- return null;
+ return getCarrierServicePackageNameForLogicalSlot(getPhoneId());
}
/**
@@ -9840,13 +9832,15 @@ public class TelephonyManager {
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @Nullable String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) {
- // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the
- // value instead of re-querying every time.
- List<String> carrierServicePackages =
- getCarrierPackageNamesForIntentAndPhone(
- new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), logicalSlotIndex);
- if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) {
- return carrierServicePackages.get(0);
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getCarrierServicePackageNameForLogicalSlot(logicalSlotIndex);
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getCarrierServicePackageNameForLogicalSlot RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "getCarrierServicePackageNameForLogicalSlot NPE", ex);
}
return null;
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 532679cb6c43..8143da5ad431 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -549,7 +549,6 @@ public class ApnSetting implements Parcelable {
* Returns the profile id to which the APN saved in modem.
*
* @return the profile id of the APN
- * @hide
*/
public int getProfileId() {
return mProfileId;
@@ -558,8 +557,7 @@ public class ApnSetting implements Parcelable {
/**
* Returns if the APN setting is persistent on the modem.
*
- * @return is the APN setting to be set in modem
- * @hide
+ * @return {@code true} if the APN setting is persistent on the modem.
*/
public boolean isPersistent() {
return mPersistent;
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a5e2c1f83939..e3ebb9a23950 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2541,4 +2541,15 @@ interface ITelephony {
* PhoneAccount#CAPABILITY_VOICE_CALLING_AVAILABLE.
*/
void setVoiceServiceStateOverride(int subId, boolean hasService, String callingPackage);
+
+ /**
+ * Returns the package name that provides the {@link CarrierService} implementation for the
+ * specified {@code logicalSlotIndex}, or {@code null} if no package with carrier privileges
+ * declares one.
+ *
+ * @param logicalSlotIndex The slot index to fetch the {@link CarrierService} package for
+ * @return The system-selected package that provides the {@link CarrierService} implementation
+ * for the slot, or {@code null} if none is resolved
+ */
+ String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex);
}
diff --git a/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
index 35f1e585931b..644d450a7a88 100644
--- a/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
+++ b/tests/BandwidthTests/src/com/android/tests/bandwidthenforcement/BandwidthEnforcementTestService.java
@@ -24,6 +24,8 @@ import android.net.SntpClient;
import android.os.Environment;
import android.util.Log;
+import libcore.io.Streams;
+
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -37,8 +39,6 @@ import java.net.InetAddress;
import java.net.URL;
import java.util.Random;
-import libcore.io.Streams;
-
/*
* Test Service that tries to connect to the web via different methods and outputs the results to
* the log and a output file.
@@ -146,7 +146,7 @@ public class BandwidthEnforcementTestService extends IntentService {
final ConnectivityManager mCM = context.getSystemService(ConnectivityManager.class);
final Network network = mCM.getActiveNetwork();
- if (client.requestTime("0.pool.ntp.org", 10000, network)) {
+ if (client.requestTime("0.pool.ntp.org", SntpClient.STANDARD_NTP_PORT, 10000, network)) {
return true;
}
return false;
diff --git a/tests/TrustTests/AndroidManifest.xml b/tests/TrustTests/AndroidManifest.xml
index 68bc1f69628f..8b4cbfd0e44b 100644
--- a/tests/TrustTests/AndroidManifest.xml
+++ b/tests/TrustTests/AndroidManifest.xml
@@ -68,6 +68,16 @@
<action android:name="android.service.trust.TrustAgentService" />
</intent-filter>
</service>
+
+ <service
+ android:name=".TemporaryAndRenewableTrustAgent"
+ android:exported="true"
+ android:label="Test Agent"
+ android:permission="android.permission.BIND_TRUST_AGENT">
+ <intent-filter>
+ <action android:name="android.service.trust.TrustAgentService" />
+ </intent-filter>
+ </service>
</application>
<!-- self-instrumenting test package. -->
diff --git a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
index 790afd389152..af7a98c22ad1 100644
--- a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
+++ b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
@@ -60,7 +60,6 @@ class GrantAndRevokeTrustTest {
@Test
fun sleepingDeviceWithoutGrantLocksDevice() {
uiDevice.sleep()
- await()
lockStateTrackingRule.assertLocked()
}
@@ -69,7 +68,6 @@ class GrantAndRevokeTrustTest {
fun grantKeepsDeviceUnlocked() {
trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0)
uiDevice.sleep()
- await()
lockStateTrackingRule.assertUnlocked()
}
@@ -80,7 +78,6 @@ class GrantAndRevokeTrustTest {
await()
uiDevice.sleep()
trustAgentRule.agent.revokeTrust()
- await()
lockStateTrackingRule.assertLocked()
}
diff --git a/tests/TrustTests/src/android/trust/test/LockUserTest.kt b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
index 8f200a64450e..a7dd41ad2e98 100644
--- a/tests/TrustTests/src/android/trust/test/LockUserTest.kt
+++ b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
@@ -24,7 +24,6 @@ import android.trust.test.lib.TrustAgentRule
import android.util.Log
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
@@ -52,9 +51,8 @@ class LockUserTest {
fun lockUser_locksTheDevice() {
Log.i(TAG, "Locking user")
trustAgentRule.agent.lockUser()
- await()
- assertThat(lockStateTrackingRule.lockState.locked).isTrue()
+ lockStateTrackingRule.assertLocked()
}
companion object {
diff --git a/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
new file mode 100644
index 000000000000..14c227b1f678
--- /dev/null
+++ b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.trust.test
+
+import android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
+import android.trust.BaseTrustAgentService
+import android.trust.TrustTestActivity
+import android.trust.test.lib.LockStateTrackingRule
+import android.trust.test.lib.ScreenLockRule
+import android.trust.test.lib.TrustAgentRule
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import androidx.test.uiautomator.UiDevice
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.runner.RunWith
+
+/**
+ * Test for testing revokeTrust & grantTrust for renewable trust.
+ *
+ * atest TrustTests:TemporaryAndRenewableTrustTest
+ */
+@RunWith(AndroidJUnit4::class)
+class TemporaryAndRenewableTrustTest {
+ private val uiDevice = UiDevice.getInstance(getInstrumentation())
+ private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java)
+ private val lockStateTrackingRule = LockStateTrackingRule()
+ private val trustAgentRule = TrustAgentRule<TemporaryAndRenewableTrustAgent>()
+
+ @get:Rule
+ val rule: RuleChain = RuleChain
+ .outerRule(activityScenarioRule)
+ .around(ScreenLockRule())
+ .around(lockStateTrackingRule)
+ .around(trustAgentRule)
+
+ @Before
+ fun manageTrust() {
+ trustAgentRule.agent.setManagingTrust(true)
+ }
+
+ // This test serves a baseline for Grant tests, verifying that the default behavior of the
+ // device is to lock when put to sleep
+ @Test
+ fun sleepingDeviceWithoutGrantLocksDevice() {
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ fun grantTrustLockedDevice_deviceStaysLocked() {
+ uiDevice.sleep()
+ lockStateTrackingRule.assertLocked()
+
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ uiDevice.wakeUp()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ fun grantTrustUnlockedDevice_deviceLocksOnScreenOff() {
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ @Test
+ fun grantTrustLockedDevice_grantTrustOnLockedDeviceUnlocksDevice() {
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ uiDevice.wakeUp()
+
+ lockStateTrackingRule.assertUnlocked()
+ }
+
+ @Test
+ fun grantTrustLockedDevice_revokeTrustPreventsSubsequentUnlock() {
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+ uiDevice.sleep()
+
+ lockStateTrackingRule.assertLocked()
+
+ trustAgentRule.agent.revokeTrust()
+ await(500)
+ uiDevice.wakeUp()
+ await(500)
+
+ trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE)
+
+ lockStateTrackingRule.assertLocked()
+ }
+
+ companion object {
+ private const val TAG = "TemporaryAndRenewableTrustTest"
+ private const val GRANT_MESSAGE = "granted by test"
+ private fun await(millis: Long) = Thread.sleep(millis)
+ }
+}
+
+class TemporaryAndRenewableTrustAgent : BaseTrustAgentService()
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
index 0023af8893e2..834f2122a21b 100644
--- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -52,8 +52,29 @@ class LockStateTrackingRule : TestRule {
}
}
- fun assertLocked() = assertThat(lockState.locked).isTrue()
- fun assertUnlocked() = assertThat(lockState.locked).isFalse()
+ fun assertLocked() {
+ val maxWaits = 50
+ var waitCount = 0
+
+ while ((lockState.locked == false) && waitCount < maxWaits) {
+ Log.i(TAG, "phone still locked, wait 50ms more ($waitCount)")
+ Thread.sleep(50)
+ waitCount++
+ }
+ assertThat(lockState.locked).isTrue()
+ }
+
+ fun assertUnlocked() {
+ val maxWaits = 50
+ var waitCount = 0
+
+ while ((lockState.locked == true) && waitCount < maxWaits) {
+ Log.i(TAG, "phone still unlocked, wait 50ms more ($waitCount)")
+ Thread.sleep(50)
+ waitCount++
+ }
+ assertThat(lockState.locked).isFalse()
+ }
inner class Listener : TrustListener {
override fun onTrustChanged(