summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Android.bp1
-rw-r--r--Android.mk10
-rw-r--r--api/current.txt270
-rw-r--r--api/system-current.txt45
-rw-r--r--config/hiddenapi-greylist-max-p.txt (renamed from config/hiddenapi-max-sdk-p-blacklist.txt)0
-rw-r--r--config/hiddenapi-greylist.txt (renamed from config/hiddenapi-light-greylist.txt)247
-rw-r--r--config/hiddenapi-vendor-list.txt247
-rw-r--r--core/java/android/app/ContextImpl.java7
-rw-r--r--core/java/android/app/LoadedApk.java53
-rw-r--r--core/java/android/app/Notification.java4
-rw-r--r--core/java/android/app/StatsManager.java6
-rw-r--r--core/java/android/app/SystemServiceRegistry.java9
-rw-r--r--core/java/android/app/WindowConfiguration.java35
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java31
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java14
-rw-r--r--core/java/android/content/ContentProvider.java9
-rw-r--r--core/java/android/content/Context.java16
-rw-r--r--core/java/android/content/Intent.java5
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java2
-rw-r--r--core/java/android/content/pm/PackageItemInfo.java10
-rw-r--r--core/java/android/content/pm/permission/RuntimePermissionPresenter.java174
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java2
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java30
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java11
-rw-r--r--core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java21
-rw-r--r--core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java7
-rw-r--r--core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java26
-rw-r--r--core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java43
-rw-r--r--core/java/android/hardware/camera2/params/SessionConfiguration.java110
-rw-r--r--core/java/android/hardware/display/ColorDisplayManager.java61
-rw-r--r--core/java/android/hardware/display/IColorDisplayManager.aidl22
-rw-r--r--core/java/android/os/Binder.java24
-rw-r--r--core/java/android/os/GraphicsEnvironment.java2
-rw-r--r--core/java/android/os/PowerManager.java162
-rw-r--r--core/java/android/os/Temperature.java4
-rw-r--r--core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java80
-rw-r--r--core/java/android/provider/DocumentsContract.java17
-rw-r--r--core/java/android/provider/DocumentsProvider.java1
-rw-r--r--core/java/android/provider/MediaStore.java25
-rw-r--r--core/java/android/provider/Settings.java25
-rw-r--r--core/java/android/service/intelligence/FillCallback.java8
-rw-r--r--core/java/android/service/intelligence/FillRequest.java9
-rw-r--r--core/java/android/service/intelligence/FillWindow.java38
-rw-r--r--core/java/android/service/intelligence/IIntelligenceService.aidl4
-rw-r--r--core/java/android/service/intelligence/SmartSuggestionsService.java104
-rw-r--r--core/java/android/view/GestureDetector.java7
-rw-r--r--core/java/android/view/KeyEvent.java47
-rw-r--r--core/java/android/view/View.java242
-rw-r--r--core/java/android/view/textclassifier/ActionsSuggestionsHelper.java6
-rw-r--r--core/java/android/webkit/TokenBindingService.java86
-rw-r--r--core/java/android/webkit/WebViewFactoryProvider.java3
-rw-r--r--core/java/android/widget/Editor.java15
-rw-r--r--core/java/android/widget/RemoteViews.java154
-rw-r--r--core/java/android/widget/RemoteViewsAdapter.java13
-rw-r--r--core/java/android/widget/RemoteViewsListAdapter.java2
-rw-r--r--core/java/android/widget/RemoteViewsService.java2
-rw-r--r--core/java/android/widget/TextView.java57
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java43
-rw-r--r--core/java/com/android/internal/os/CachedDeviceState.java96
-rw-r--r--core/java/com/android/internal/os/LooperStats.java19
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl41
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl3
-rw-r--r--core/java/com/android/internal/widget/ImageMessageConsumer.java28
-rw-r--r--core/java/com/android/internal/widget/ImageResolver.java32
-rw-r--r--core/java/com/android/internal/widget/LocalImageResolver.java1
-rw-r--r--core/java/com/android/internal/widget/MessagingImageMessage.java16
-rw-r--r--core/java/com/android/internal/widget/MessagingLayout.java12
-rw-r--r--core/java/com/android/internal/widget/MessagingMessage.java4
-rw-r--r--core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp4
-rw-r--r--core/jni/android/graphics/Paint.cpp4
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp40
-rw-r--r--core/proto/android/app/settings_enums.proto6
-rw-r--r--core/proto/android/providers/settings/global.proto11
-rw-r--r--core/proto/android/server/activitymanagerservice.proto1
-rw-r--r--core/proto/android/server/jobscheduler.proto95
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/layout/notification_material_reply_text.xml6
-rw-r--r--core/res/res/layout/notification_template_ambient_header.xml2
-rw-r--r--core/res/res/layout/notification_template_header.xml2
-rw-r--r--core/res/res/layout/notification_template_material_ambient.xml7
-rw-r--r--core/res/res/layout/notification_template_material_big_text.xml2
-rw-r--r--core/res/res/layout/notification_template_material_inbox.xml14
-rw-r--r--core/res/res/layout/notification_template_messaging_group.xml2
-rw-r--r--core/res/res/layout/notification_template_messaging_text_message.xml2
-rw-r--r--core/res/res/layout/notification_template_part_line1.xml4
-rw-r--r--core/res/res/layout/notification_template_text.xml2
-rw-r--r--core/res/res/values/config.xml8
-rw-r--r--core/res/res/values/styles_device_defaults.xml19
-rw-r--r--core/res/res/values/styles_material.xml1
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/values/themes_device_defaults.xml6
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java2
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java50
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java25
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java14
-rw-r--r--libs/androidfw/LoadedArsc.cpp58
-rw-r--r--libs/androidfw/ResourceTypes.cpp14
-rw-r--r--libs/androidfw/include/androidfw/Chunk.h4
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h18
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h51
-rw-r--r--libs/androidfw/tests/LoadedArsc_test.cpp49
-rw-r--r--libs/androidfw/tests/data/overlay/overlay.apkbin5211 -> 5211 bytes
-rw-r--r--libs/androidfw/tests/data/overlayable/AndroidManifest.xml21
-rw-r--r--libs/androidfw/tests/data/overlayable/R.h42
-rwxr-xr-xlibs/androidfw/tests/data/overlayable/build22
-rw-r--r--libs/androidfw/tests/data/overlayable/overlayable.apkbin0 -> 1387 bytes
-rw-r--r--libs/androidfw/tests/data/overlayable/res/values/overlayable.xml41
-rw-r--r--libs/androidfw/tests/data/overlayable/res/values/public.xml23
-rw-r--r--libs/androidfw/tests/data/overlayable/res/values/values.xml23
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/Properties.cpp27
-rw-r--r--libs/hwui/Properties.h32
-rw-r--r--libs/hwui/SkiaCanvas.cpp4
-rw-r--r--libs/hwui/hwui/MinikinSkia.cpp2
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp3
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.cpp84
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.h66
-rw-r--r--libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp2
-rw-r--r--libs/hwui/private/hwui/DrawVkInfo.h107
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp2
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp4
-rw-r--r--media/OWNERS7
-rw-r--r--media/java/android/media/CallbackDataSourceDesc.java1
-rw-r--r--media/java/android/media/DataSourceCallback.java1
-rw-r--r--media/java/android/media/DataSourceDesc.java7
-rw-r--r--media/java/android/media/FileDataSourceDesc.java1
-rw-r--r--media/java/android/media/MediaFormat.java51
-rw-r--r--media/java/android/media/MediaPlayer2.java165
-rw-r--r--media/java/android/media/MediaScanner.java6
-rw-r--r--media/java/android/media/SubtitleData.java83
-rw-r--r--media/java/android/media/TimedMetaData.java76
-rw-r--r--media/java/android/media/UriDataSourceDesc.java1
-rw-r--r--media/java/android/media/VideoSize.java4
-rw-r--r--media/java/android/media/session/MediaSessionManager.java10
-rw-r--r--media/jni/android_media_MediaPlayer2.cpp12
-rw-r--r--native/webview/plat_support/Android.bp3
-rw-r--r--native/webview/plat_support/draw_gl_functor.cpp27
-rw-r--r--native/webview/plat_support/draw_vk.h125
-rw-r--r--native/webview/plat_support/draw_vk_functor.cpp141
-rw-r--r--native/webview/plat_support/functor_utils.cpp45
-rw-r--r--native/webview/plat_support/functor_utils.h25
-rw-r--r--packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_down.xml (renamed from packages/SystemUI/res/anim/car_arrow_fade_in_rotate_down.xml)0
-rw-r--r--packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_up.xml (renamed from packages/SystemUI/res/anim/car_arrow_fade_in_rotate_up.xml)0
-rw-r--r--packages/CarSystemUI/res/anim/car_arrow_fade_out.xml (renamed from packages/SystemUI/res/anim/car_arrow_fade_out.xml)0
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_close_animation.xml (renamed from packages/SystemUI/res/anim/car_user_switcher_close_animation.xml)2
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_close_icon_animation.xml (renamed from packages/SystemUI/res/anim/car_user_switcher_close_icon_animation.xml)2
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_close_name_animation.xml (renamed from packages/SystemUI/res/anim/car_user_switcher_close_name_animation.xml)2
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_close_pages_animation.xml (renamed from packages/SystemUI/res/anim/car_user_switcher_close_pages_animation.xml)2
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_close_pod_animation.xml (renamed from packages/SystemUI/res/anim/car_user_switcher_close_pod_animation.xml)2
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_open_animation.xml (renamed from packages/SystemUI/res/anim/car_user_switcher_open_animation.xml)2
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_open_icon_animation.xml (renamed from packages/SystemUI/res/anim/car_user_switcher_open_icon_animation.xml)2
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_open_name_animation.xml (renamed from packages/SystemUI/res/anim/car_user_switcher_open_name_animation.xml)2
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_open_pages_animation.xml (renamed from packages/SystemUI/res/anim/car_user_switcher_open_pages_animation.xml)2
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_open_pod_animation.xml (renamed from packages/SystemUI/res/anim/car_user_switcher_open_pod_animation.xml)2
-rw-r--r--packages/CarSystemUI/res/drawable/car_add_circle_round.xml (renamed from packages/SystemUI/res/drawable/car_add_circle_round.xml)0
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_add_white.xml (renamed from packages/SystemUI/res/drawable/car_ic_add_white.xml)0
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_arrow.xml (renamed from packages/SystemUI/res/drawable/car_ic_arrow.xml)2
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_arrow_drop_up.xml (renamed from packages/SystemUI/res/drawable/car_ic_arrow_drop_up.xml)2
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_hvac.xml (renamed from packages/SystemUI/res/drawable/car_ic_hvac.xml)0
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_keyboard_arrow_down.xml (renamed from packages/SystemUI/res/drawable/car_ic_keyboard_arrow_down.xml)0
-rw-r--r--packages/CarSystemUI/res/drawable/car_rounded_bg_bottom.xml (renamed from packages/SystemUI/res/drawable/car_ic_navigation.xml)23
-rw-r--r--packages/CarSystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml28
-rw-r--r--packages/CarSystemUI/res/drawable/ic_mic_white.xml16
-rw-r--r--packages/CarSystemUI/res/layout/car_facet_button.xml (renamed from packages/SystemUI/res/layout/car_facet_button.xml)2
-rw-r--r--packages/CarSystemUI/res/layout/car_fullscreen_user_pod.xml (renamed from packages/SystemUI/res/layout/car_fullscreen_user_pod.xml)2
-rw-r--r--packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml (renamed from packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml)2
-rw-r--r--packages/CarSystemUI/res/layout/car_left_navigation_bar.xml (renamed from packages/SystemUI/res/layout/car_left_navigation_bar.xml)2
-rw-r--r--packages/CarSystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml (renamed from packages/SystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml)0
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_button.xml (renamed from packages/SystemUI/res/layout/car_navigation_button.xml)2
-rw-r--r--packages/CarSystemUI/res/layout/car_qs_footer.xml (renamed from packages/SystemUI/res/layout/car_qs_footer.xml)2
-rw-r--r--packages/CarSystemUI/res/layout/car_qs_panel.xml (renamed from packages/SystemUI/res/layout/car_qs_panel.xml)2
-rw-r--r--packages/CarSystemUI/res/layout/car_right_navigation_bar.xml (renamed from packages/SystemUI/res/layout/car_right_navigation_bar.xml)4
-rw-r--r--packages/CarSystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml (renamed from packages/SystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml)0
-rw-r--r--packages/CarSystemUI/res/values/colors_car.xml (renamed from packages/SystemUI/res/values/colors_car.xml)2
-rw-r--r--packages/CarSystemUI/res/values/dimens_car.xml (renamed from packages/SystemUI/res/values/dimens_car.xml)2
-rw-r--r--packages/CarSystemUI/res/values/ids_car.xml (renamed from packages/SystemUI/res/values/ids_car.xml)0
-rw-r--r--packages/CarSystemUI/res/values/integers_car.xml (renamed from packages/SystemUI/res/values/integers_car.xml)2
-rw-r--r--packages/CarSystemUI/res/values/strings_car.xml (renamed from packages/SystemUI/res/values/strings_car.xml)2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java (renamed from packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java)5
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFooter.java (renamed from packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java)17
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java (renamed from packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java)19
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java (renamed from packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java)17
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java)53
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java)26
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java)0
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java)16
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java)11
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java)20
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java)51
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java)2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java)10
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/SwitchToGuestTimer.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/SwitchToGuestTimer.java)0
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java)38
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java)129
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java)3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java)0
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java36
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java602
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/Assistant.java5
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java9
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/res/drawable/car_ic_music.xml30
-rw-r--r--packages/SystemUI/res/drawable/car_ic_notification.xml28
-rw-r--r--packages/SystemUI/res/drawable/car_ic_overview.xml28
-rw-r--r--packages/SystemUI/res/drawable/car_rounded_bg_bottom.xml11
-rw-r--r--packages/SystemUI/res/layout/car_navigation_bar.xml98
-rw-r--r--packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml61
-rw-r--r--packages/SystemUI/res/layout/car_status_bar_header.xml43
-rw-r--r--packages/SystemUI/res/layout/car_top_navigation_bar.xml38
-rw-r--r--packages/SystemUI/res/layout/car_volume_dialog.xml31
-rw-r--r--packages/SystemUI/res/layout/super_status_bar.xml5
-rw-r--r--packages/SystemUI/res/values/dimens.xml1
-rw-r--r--packages/SystemUI/res/xml/car_volume_items.xml68
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipUI.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java186
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java97
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java197
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/Assert.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/Utils.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java605
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java5
-rw-r--r--packages/SystemUI/tests/Android.mk2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java89
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java51
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java11
-rw-r--r--packages/overlays/AccentColorBlackOverlay/Android.mk30
-rw-r--r--packages/overlays/AccentColorBlackOverlay/AndroidManifest.xml25
-rw-r--r--packages/overlays/AccentColorBlackOverlay/res/values/colors_device_defaults.xml22
-rw-r--r--packages/overlays/AccentColorBlackOverlay/res/values/strings.xml23
-rw-r--r--packages/overlays/AccentColorGreenOverlay/Android.mk30
-rw-r--r--packages/overlays/AccentColorGreenOverlay/AndroidManifest.xml25
-rw-r--r--packages/overlays/AccentColorGreenOverlay/res/values/colors_device_defaults.xml22
-rw-r--r--packages/overlays/AccentColorGreenOverlay/res/values/strings.xml23
-rw-r--r--packages/overlays/AccentColorPurpleOverlay/Android.mk30
-rw-r--r--packages/overlays/AccentColorPurpleOverlay/AndroidManifest.xml25
-rw-r--r--packages/overlays/AccentColorPurpleOverlay/res/values/colors_device_defaults.xml22
-rw-r--r--packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml23
-rw-r--r--packages/overlays/AdaptiveIconChangeOverlay/Android.mk30
-rw-r--r--packages/overlays/AdaptiveIconChangeOverlay/AndroidManifest.xml27
-rw-r--r--packages/overlays/AdaptiveIconChangeOverlay/res/values/config.xml (renamed from packages/SystemUI/res/values/arrays_car.xml)22
-rw-r--r--packages/overlays/AdaptiveIconChangeOverlay/res/values/strings.xml23
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java9
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteFillService.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java6
-rw-r--r--services/backup/java/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKey.java117
-rw-r--r--services/backup/java/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManager.java119
-rw-r--r--services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyGenerator.java47
-rw-r--r--services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyRotationTracker.java113
-rw-r--r--services/core/java/com/android/server/BinderCallsStatsService.java145
-rw-r--r--services/core/java/com/android/server/IpSecService.java7
-rw-r--r--services/core/java/com/android/server/LooperStatsService.java2
-rw-r--r--services/core/java/com/android/server/RuntimeService.java2
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java10
-rw-r--r--services/core/java/com/android/server/am/ActiveInstrumentation.java2
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java31
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java43
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java326
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java27
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java19
-rw-r--r--services/core/java/com/android/server/am/UserController.java2
-rw-r--r--services/core/java/com/android/server/display/ColorDisplayService.java40
-rw-r--r--services/core/java/com/android/server/display/DisplayTransformManager.java34
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java2
-rw-r--r--services/core/java/com/android/server/infra/AbstractMasterSystemService.java (renamed from services/core/java/com/android/server/AbstractMasterSystemService.java)65
-rw-r--r--services/core/java/com/android/server/infra/AbstractMultiplePendingRequestsRemoteService.java (renamed from services/core/java/com/android/server/AbstractMultiplePendingRequestsRemoteService.java)2
-rw-r--r--services/core/java/com/android/server/infra/AbstractPerUserSystemService.java (renamed from services/core/java/com/android/server/AbstractPerUserSystemService.java)127
-rw-r--r--services/core/java/com/android/server/infra/AbstractRemoteService.java (renamed from services/core/java/com/android/server/AbstractRemoteService.java)3
-rw-r--r--services/core/java/com/android/server/infra/AbstractSinglePendingRequestRemoteService.java (renamed from services/core/java/com/android/server/AbstractSinglePendingRequestRemoteService.java)2
-rw-r--r--services/core/java/com/android/server/infra/package.html6
-rw-r--r--services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java6
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java264
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java70
-rw-r--r--services/core/java/com/android/server/job/controllers/QuotaController.java1299
-rw-r--r--services/core/java/com/android/server/job/controllers/StateController.java9
-rw-r--r--services/core/java/com/android/server/notification/NotificationComparator.java20
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java113
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java22
-rw-r--r--services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java28
-rw-r--r--services/core/java/com/android/server/signedconfig/SignedConfigService.java105
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java330
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java44
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java7
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java12
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java26
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java10
-rw-r--r--services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java24
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java31
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java17
-rw-r--r--services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java10
-rw-r--r--services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java21
-rw-r--r--services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java34
-rw-r--r--services/intelligence/java/com/android/server/intelligence/IntelligenceServiceShellCommand.java22
-rw-r--r--services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java16
-rw-r--r--services/java/com/android/server/SystemServer.java54
-rw-r--r--services/robotests/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManagerTest.java148
-rw-r--r--services/robotests/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyTest.java163
-rw-r--r--services/robotests/src/com/android/server/backup/encryption/keys/TertiaryKeyGeneratorTest.java73
-rw-r--r--services/robotests/src/com/android/server/backup/encryption/keys/TertiaryKeyRotationTrackerTest.java137
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowInternalRecoveryServiceException.java43
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowRecoveryController.java152
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java842
-rw-r--r--services/tests/servicestests/AndroidManifest.xml1
-rw-r--r--services/tests/servicestests/src/com/android/server/BinderCallsStatsServiceTest.java125
-rw-r--r--services/tests/servicestests/src/com/android/server/CachedDeviceStateServiceTest.java43
-rw-r--r--services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java38
-rw-r--r--services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java2
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java25
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java67
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java26
-rw-r--r--telecomm/java/android/telecom/Call.java11
-rw-r--r--telecomm/java/android/telecom/CallScreeningService.java25
-rw-r--r--telephony/java/android/telephony/ServiceState.java16
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java38
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java31
-rw-r--r--telephony/java/android/telephony/euicc/EuiccCardManager.java44
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl13
-rw-r--r--tests/net/java/com/android/server/IpSecServiceParameterizedTest.java4
-rw-r--r--tests/net/java/com/android/server/IpSecServiceTest.java6
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.cpp96
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.h1
-rw-r--r--tools/aapt2/format/binary/TableFlattener.cpp104
-rw-r--r--tools/aapt2/format/binary/TableFlattener_test.cpp106
-rw-r--r--tools/aapt2/link/ReferenceLinker.cpp11
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java16
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java26
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pManager.java2
-rw-r--r--wifi/tests/src/android/net/wifi/WifiScannerTest.java27
430 files changed, 11794 insertions, 3615 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000000..45884c46ffea
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/.idea
+*.iml
diff --git a/Android.bp b/Android.bp
index b3a2ef895d0a..c568d3676916 100644
--- a/Android.bp
+++ b/Android.bp
@@ -162,6 +162,7 @@ java_defaults {
"core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl",
"core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl",
"core/java/android/hardware/biometrics/IBiometricServiceLockoutResetCallback.aidl",
+ "core/java/android/hardware/display/IColorDisplayManager.aidl",
"core/java/android/hardware/display/IDisplayManager.aidl",
"core/java/android/hardware/display/IDisplayManagerCallback.aidl",
"core/java/android/hardware/display/IVirtualDisplayCallback.aidl",
diff --git a/Android.mk b/Android.mk
index b7dda9a45ed8..92e33e988249 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,10 +76,9 @@ $(OUT_DOCS)/offline-sdk-timestamp: $(OUT_DOCS)/offline-sdk-docs-docs.zip
.KATI_RESTAT: $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS)
$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS): \
frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
- frameworks/base/config/hiddenapi-light-greylist.txt \
- frameworks/base/config/hiddenapi-vendor-list.txt \
+ frameworks/base/config/hiddenapi-greylist.txt \
+ frameworks/base/config/hiddenapi-greylist-max-p.txt \
frameworks/base/config/hiddenapi-greylist-max-o.txt \
- frameworks/base/config/hiddenapi-max-sdk-p-blacklist.txt \
frameworks/base/config/hiddenapi-force-blacklist.txt \
$(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
$(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
@@ -88,10 +87,9 @@ $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS): \
--public $(INTERNAL_PLATFORM_HIDDENAPI_PUBLIC_LIST) \
--private $(INTERNAL_PLATFORM_HIDDENAPI_PRIVATE_LIST) \
--csv $(PRIVATE_FLAGS_INPUTS) \
- --greylist \
- frameworks/base/config/hiddenapi-light-greylist.txt \
- frameworks/base/config/hiddenapi-vendor-list.txt \
+ --greylist frameworks/base/config/hiddenapi-greylist.txt \
--greylist-ignore-conflicts $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE) \
+ --greylist-max-p frameworks/base/config/hiddenapi-greylist-max-p.txt \
--greylist-max-o-ignore-conflicts \
frameworks/base/config/hiddenapi-greylist-max-o.txt \
--blacklist frameworks/base/config/hiddenapi-force-blacklist.txt \
diff --git a/api/current.txt b/api/current.txt
index 1786a5ef22ac..802e50e5abaf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7692,6 +7692,7 @@ package android.appwidget {
method protected void prepareView(android.view.View);
method public void setAppWidget(int, android.appwidget.AppWidgetProviderInfo);
method public void setExecutor(java.util.concurrent.Executor);
+ method public void setOnLightBackground(boolean);
method public void updateAppWidget(android.widget.RemoteViews);
method public void updateAppWidgetOptions(android.os.Bundle);
method public void updateAppWidgetSize(android.os.Bundle, int, int, int, int);
@@ -16498,6 +16499,7 @@ package android.hardware.camera2 {
method public abstract void createReprocessableCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void createReprocessableCaptureSessionByConfigurations(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract java.lang.String getId();
+ method public boolean isSessionConfigurationSupported(android.hardware.camera2.params.SessionConfiguration) throws android.hardware.camera2.CameraAccessException;
field public static final int TEMPLATE_MANUAL = 6; // 0x6
field public static final int TEMPLATE_PREVIEW = 1; // 0x1
field public static final int TEMPLATE_RECORD = 3; // 0x3
@@ -17095,8 +17097,9 @@ package android.hardware.camera2.params {
field public static final int RED = 0; // 0x0
}
- public final class SessionConfiguration {
+ public final class SessionConfiguration implements android.os.Parcelable {
ctor public SessionConfiguration(int, java.util.List<android.hardware.camera2.params.OutputConfiguration>, java.util.concurrent.Executor, android.hardware.camera2.CameraCaptureSession.StateCallback);
+ method public int describeContents();
method public java.util.concurrent.Executor getExecutor();
method public android.hardware.camera2.params.InputConfiguration getInputConfiguration();
method public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
@@ -17105,6 +17108,8 @@ package android.hardware.camera2.params {
method public android.hardware.camera2.CameraCaptureSession.StateCallback getStateCallback();
method public void setInputConfiguration(android.hardware.camera2.params.InputConfiguration);
method public void setSessionParameters(android.hardware.camera2.CaptureRequest);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.hardware.camera2.params.SessionConfiguration> CREATOR;
field public static final int SESSION_HIGH_SPEED = 1; // 0x1
field public static final int SESSION_REGULAR = 0; // 0x0
}
@@ -23436,6 +23441,17 @@ package android.media {
method public void onTearDown(android.media.AudioTrack);
}
+ public class CallbackDataSourceDesc extends android.media.DataSourceDesc {
+ method public android.media.DataSourceCallback getDataSourceCallback();
+ }
+
+ public static class CallbackDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase {
+ ctor public CallbackDataSourceDesc.Builder();
+ ctor public CallbackDataSourceDesc.Builder(android.media.CallbackDataSourceDesc);
+ method public android.media.CallbackDataSourceDesc build();
+ method public android.media.CallbackDataSourceDesc.Builder setDataSource(android.media.DataSourceCallback);
+ }
+
public class CamcorderProfile {
method public static android.media.CamcorderProfile get(int);
method public static android.media.CamcorderProfile get(int, int);
@@ -23488,6 +23504,26 @@ package android.media {
field public static final int QUALITY_MEDIUM = 1; // 0x1
}
+ public abstract class DataSourceCallback implements java.io.Closeable {
+ ctor public DataSourceCallback();
+ method public abstract long getSize() throws java.io.IOException;
+ method public abstract int readAt(long, byte[], int, int) throws java.io.IOException;
+ }
+
+ public class DataSourceDesc {
+ method public long getEndPosition();
+ method public java.lang.String getMediaId();
+ method public long getStartPosition();
+ field public static final long LONG_MAX_TIME_MS = 576460752303423L; // 0x20c49ba5e353fL
+ field public static final long POSITION_UNKNOWN = 576460752303423L; // 0x20c49ba5e353fL
+ }
+
+ protected static class DataSourceDesc.BuilderBase<T extends android.media.DataSourceDesc.BuilderBase> {
+ method public T setEndPosition(long);
+ method public T setMediaId(java.lang.String);
+ method public T setStartPosition(long);
+ }
+
public final class DeniedByServerException extends android.media.MediaDrmException {
ctor public DeniedByServerException(java.lang.String);
}
@@ -23688,6 +23724,21 @@ package android.media {
field public static final int EULER_Z = 2; // 0x2
}
+ public class FileDataSourceDesc extends android.media.DataSourceDesc {
+ method public long getLength();
+ method public long getOffset();
+ method public android.os.ParcelFileDescriptor getParcelFileDescriptor();
+ field public static final long FD_LENGTH_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL
+ }
+
+ public static class FileDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase {
+ ctor public FileDataSourceDesc.Builder();
+ ctor public FileDataSourceDesc.Builder(android.media.FileDataSourceDesc);
+ method public android.media.FileDataSourceDesc build();
+ method public android.media.FileDataSourceDesc.Builder setDataSource(android.os.ParcelFileDescriptor);
+ method public android.media.FileDataSourceDesc.Builder setDataSource(android.os.ParcelFileDescriptor, long, long);
+ }
+
public abstract class Image implements java.lang.AutoCloseable {
method public abstract void close();
method public android.graphics.Rect getCropRect();
@@ -25075,6 +25126,166 @@ package android.media {
field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1
}
+ public class MediaPlayer2 implements android.media.AudioRouting java.lang.AutoCloseable {
+ ctor public MediaPlayer2(android.content.Context);
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
+ method public java.lang.Object attachAuxEffect(int);
+ method public boolean cancelCommand(java.lang.Object);
+ method public java.lang.Object clearNextDataSources();
+ method public void clearPendingCommands();
+ method public void close();
+ method public java.lang.Object deselectTrack(int);
+ method public android.media.AudioAttributes getAudioAttributes();
+ method public int getAudioSessionId();
+ method public long getBufferedPosition();
+ method public android.media.DataSourceDesc getCurrentDataSource();
+ method public long getCurrentPosition();
+ method public long getDuration();
+ method public float getMaxPlayerVolume();
+ method public android.os.PersistableBundle getMetrics();
+ method public android.media.PlaybackParams getPlaybackParams();
+ method public float getPlayerVolume();
+ method public android.media.AudioDeviceInfo getPreferredDevice();
+ method public android.media.AudioDeviceInfo getRoutedDevice();
+ method public int getSelectedTrack(int);
+ method public int getState();
+ method public android.media.SyncParams getSyncParams();
+ method public android.media.MediaTimestamp getTimestamp();
+ method public java.util.List<android.media.MediaPlayer2.TrackInfo> getTrackInfo();
+ method public android.media.VideoSize getVideoSize();
+ method public boolean isLooping();
+ method public java.lang.Object loopCurrent(boolean);
+ method public java.lang.Object notifyWhenCommandLabelReached(java.lang.Object);
+ method public java.lang.Object pause();
+ method public java.lang.Object play();
+ method public java.lang.Object prepare();
+ method public void registerEventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.EventCallback);
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
+ method public void reset();
+ method public java.lang.Object seekTo(long);
+ method public java.lang.Object seekTo(long, int);
+ method public java.lang.Object selectTrack(int);
+ method public java.lang.Object setAudioAttributes(android.media.AudioAttributes);
+ method public java.lang.Object setAudioSessionId(int);
+ method public java.lang.Object setAuxEffectSendLevel(float);
+ method public java.lang.Object setDataSource(android.media.DataSourceDesc);
+ method public java.lang.Object setDisplay(android.view.SurfaceHolder);
+ method public java.lang.Object setNextDataSource(android.media.DataSourceDesc);
+ method public java.lang.Object setNextDataSources(java.util.List<android.media.DataSourceDesc>);
+ method public java.lang.Object setPlaybackParams(android.media.PlaybackParams);
+ method public java.lang.Object setPlayerVolume(float);
+ method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
+ method public java.lang.Object setScreenOnWhilePlaying(boolean);
+ method public java.lang.Object setSurface(android.view.Surface);
+ method public java.lang.Object setSyncParams(android.media.SyncParams);
+ method public java.lang.Object setWakeLock(android.os.PowerManager.WakeLock);
+ method public java.lang.Object skipToNext();
+ method public void unregisterEventCallback(android.media.MediaPlayer2.EventCallback);
+ field public static final int CALL_COMPLETED_ATTACH_AUX_EFFECT = 1; // 0x1
+ field public static final int CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES = 30; // 0x1e
+ field public static final int CALL_COMPLETED_DESELECT_TRACK = 2; // 0x2
+ field public static final int CALL_COMPLETED_LOOP_CURRENT = 3; // 0x3
+ field public static final int CALL_COMPLETED_PAUSE = 4; // 0x4
+ field public static final int CALL_COMPLETED_PLAY = 5; // 0x5
+ field public static final int CALL_COMPLETED_PREPARE = 6; // 0x6
+ field public static final int CALL_COMPLETED_SEEK_TO = 14; // 0xe
+ field public static final int CALL_COMPLETED_SELECT_TRACK = 15; // 0xf
+ field public static final int CALL_COMPLETED_SET_AUDIO_ATTRIBUTES = 16; // 0x10
+ field public static final int CALL_COMPLETED_SET_AUDIO_SESSION_ID = 17; // 0x11
+ field public static final int CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL = 18; // 0x12
+ field public static final int CALL_COMPLETED_SET_DATA_SOURCE = 19; // 0x13
+ field public static final int CALL_COMPLETED_SET_DISPLAY = 33; // 0x21
+ field public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCE = 22; // 0x16
+ field public static final int CALL_COMPLETED_SET_NEXT_DATA_SOURCES = 23; // 0x17
+ field public static final int CALL_COMPLETED_SET_PLAYBACK_PARAMS = 24; // 0x18
+ field public static final int CALL_COMPLETED_SET_PLAYER_VOLUME = 26; // 0x1a
+ field public static final int CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING = 35; // 0x23
+ field public static final int CALL_COMPLETED_SET_SURFACE = 27; // 0x1b
+ field public static final int CALL_COMPLETED_SET_SYNC_PARAMS = 28; // 0x1c
+ field public static final int CALL_COMPLETED_SET_WAKE_LOCK = 34; // 0x22
+ field public static final int CALL_COMPLETED_SKIP_TO_NEXT = 29; // 0x1d
+ field public static final int CALL_STATUS_BAD_VALUE = 2; // 0x2
+ field public static final int CALL_STATUS_ERROR_IO = 4; // 0x4
+ field public static final int CALL_STATUS_ERROR_UNKNOWN = -2147483648; // 0x80000000
+ field public static final int CALL_STATUS_INVALID_OPERATION = 1; // 0x1
+ field public static final int CALL_STATUS_NO_DRM_SCHEME = 6; // 0x6
+ field public static final int CALL_STATUS_NO_ERROR = 0; // 0x0
+ field public static final int CALL_STATUS_PERMISSION_DENIED = 3; // 0x3
+ field public static final int CALL_STATUS_SKIPPED = 5; // 0x5
+ field public static final int MEDIA_ERROR_IO = -1004; // 0xfffffc14
+ field public static final int MEDIA_ERROR_MALFORMED = -1007; // 0xfffffc11
+ field public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200; // 0xc8
+ field public static final int MEDIA_ERROR_TIMED_OUT = -110; // 0xffffff92
+ field public static final int MEDIA_ERROR_UNKNOWN = 1; // 0x1
+ field public static final int MEDIA_ERROR_UNSUPPORTED = -1010; // 0xfffffc0e
+ field public static final int MEDIA_INFO_AUDIO_NOT_PLAYING = 804; // 0x324
+ field public static final int MEDIA_INFO_AUDIO_RENDERING_START = 4; // 0x4
+ field public static final int MEDIA_INFO_BAD_INTERLEAVING = 800; // 0x320
+ field public static final int MEDIA_INFO_BUFFERING_END = 702; // 0x2be
+ field public static final int MEDIA_INFO_BUFFERING_START = 701; // 0x2bd
+ field public static final int MEDIA_INFO_BUFFERING_UPDATE = 704; // 0x2c0
+ field public static final int MEDIA_INFO_DATA_SOURCE_END = 5; // 0x5
+ field public static final int MEDIA_INFO_DATA_SOURCE_LIST_END = 6; // 0x6
+ field public static final int MEDIA_INFO_DATA_SOURCE_REPEAT = 7; // 0x7
+ field public static final int MEDIA_INFO_DATA_SOURCE_START = 2; // 0x2
+ field public static final int MEDIA_INFO_METADATA_UPDATE = 802; // 0x322
+ field public static final int MEDIA_INFO_NOT_SEEKABLE = 801; // 0x321
+ field public static final int MEDIA_INFO_PREPARED = 100; // 0x64
+ field public static final int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902; // 0x386
+ field public static final int MEDIA_INFO_UNKNOWN = 1; // 0x1
+ field public static final int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901; // 0x385
+ field public static final int MEDIA_INFO_VIDEO_NOT_PLAYING = 805; // 0x325
+ field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
+ field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
+ field public static final int PLAYER_STATE_ERROR = 1005; // 0x3ed
+ field public static final int PLAYER_STATE_IDLE = 1001; // 0x3e9
+ field public static final int PLAYER_STATE_PAUSED = 1003; // 0x3eb
+ field public static final int PLAYER_STATE_PLAYING = 1004; // 0x3ec
+ field public static final int PLAYER_STATE_PREPARED = 1002; // 0x3ea
+ field public static final int SEEK_CLOSEST = 3; // 0x3
+ field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
+ field public static final int SEEK_NEXT_SYNC = 1; // 0x1
+ field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
+ }
+
+ public static class MediaPlayer2.EventCallback {
+ ctor public MediaPlayer2.EventCallback();
+ method public void onCallCompleted(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
+ method public void onCommandLabelReached(android.media.MediaPlayer2, java.lang.Object);
+ method public void onError(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
+ method public void onInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
+ method public void onMediaTimeDiscontinuity(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaTimestamp);
+ method public void onSubtitleData(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.SubtitleData);
+ method public void onTimedMetaDataAvailable(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.TimedMetaData);
+ method public void onVideoSizeChanged(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.VideoSize);
+ }
+
+ public static final class MediaPlayer2.MetricsConstants {
+ field public static final java.lang.String CODEC_AUDIO = "android.media.mediaplayer.audio.codec";
+ field public static final java.lang.String CODEC_VIDEO = "android.media.mediaplayer.video.codec";
+ field public static final java.lang.String DURATION = "android.media.mediaplayer.durationMs";
+ field public static final java.lang.String ERRORS = "android.media.mediaplayer.err";
+ field public static final java.lang.String ERROR_CODE = "android.media.mediaplayer.errcode";
+ field public static final java.lang.String FRAMES = "android.media.mediaplayer.frames";
+ field public static final java.lang.String FRAMES_DROPPED = "android.media.mediaplayer.dropped";
+ field public static final java.lang.String HEIGHT = "android.media.mediaplayer.height";
+ field public static final java.lang.String MIME_TYPE_AUDIO = "android.media.mediaplayer.audio.mime";
+ field public static final java.lang.String MIME_TYPE_VIDEO = "android.media.mediaplayer.video.mime";
+ field public static final java.lang.String PLAYING = "android.media.mediaplayer.playingMs";
+ field public static final java.lang.String WIDTH = "android.media.mediaplayer.width";
+ }
+
+ public static class MediaPlayer2.TrackInfo {
+ method public android.media.MediaFormat getFormat();
+ method public java.lang.String getLanguage();
+ method public int getTrackType();
+ field public static final int MEDIA_TRACK_TYPE_AUDIO = 2; // 0x2
+ field public static final int MEDIA_TRACK_TYPE_METADATA = 5; // 0x5
+ field public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4; // 0x4
+ field public static final int MEDIA_TRACK_TYPE_UNKNOWN = 0; // 0x0
+ field public static final int MEDIA_TRACK_TYPE_VIDEO = 1; // 0x1
+ }
+
public class MediaRecorder implements android.media.AudioRouting {
ctor public MediaRecorder();
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
@@ -25817,6 +26028,26 @@ package android.media {
ctor public UnsupportedSchemeException(java.lang.String);
}
+ public class UriDataSourceDesc extends android.media.DataSourceDesc {
+ method public android.content.Context getContext();
+ method public java.util.List<java.net.HttpCookie> getCookies();
+ method public java.util.Map<java.lang.String, java.lang.String> getHeaders();
+ method public android.net.Uri getUri();
+ }
+
+ public static class UriDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase {
+ ctor public UriDataSourceDesc.Builder();
+ ctor public UriDataSourceDesc.Builder(android.media.UriDataSourceDesc);
+ method public android.media.UriDataSourceDesc build();
+ method public android.media.UriDataSourceDesc.Builder setDataSource(android.content.Context, android.net.Uri);
+ method public android.media.UriDataSourceDesc.Builder setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>, java.util.List<java.net.HttpCookie>);
+ }
+
+ public final class VideoSize {
+ method public int getHeight();
+ method public int getWidth();
+ }
+
public abstract interface VolumeAutomation {
method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
}
@@ -29138,10 +29369,11 @@ package android.net.wifi {
field public static final java.lang.String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
field public static final java.lang.String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
field public static final java.lang.String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
- field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 2; // 0x2
- field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 3; // 0x3
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3; // 0x3
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4; // 0x4
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED = 2; // 0x2
field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1; // 0x1
- field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 4; // 0x4
+ field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5; // 0x5
field public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0; // 0x0
field public static final deprecated java.lang.String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
field public static final deprecated java.lang.String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
@@ -34069,6 +34301,7 @@ package android.os {
}
public final class PowerManager {
+ method public int getCurrentThermalStatus();
method public int getLocationPowerSaveMode();
method public boolean isDeviceIdleMode();
method public boolean isIgnoringBatteryOptimizations(java.lang.String);
@@ -34079,6 +34312,8 @@ package android.os {
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
method public void reboot(java.lang.String);
+ method public void registerThermalStatusCallback(android.os.PowerManager.ThermalStatusCallback, java.util.concurrent.Executor);
+ method public void unregisterThermalStatusCallback(android.os.PowerManager.ThermalStatusCallback);
field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
field public static final java.lang.String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
field public static final java.lang.String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED";
@@ -34093,6 +34328,18 @@ package android.os {
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
+ field public static final int THERMAL_STATUS_CRITICAL = 4; // 0x4
+ field public static final int THERMAL_STATUS_EMERGENCY = 5; // 0x5
+ field public static final int THERMAL_STATUS_LIGHT = 1; // 0x1
+ field public static final int THERMAL_STATUS_MODERATE = 2; // 0x2
+ field public static final int THERMAL_STATUS_NONE = 0; // 0x0
+ field public static final int THERMAL_STATUS_SEVERE = 3; // 0x3
+ field public static final int THERMAL_STATUS_SHUTDOWN = 6; // 0x6
+ }
+
+ public static abstract class PowerManager.ThermalStatusCallback {
+ ctor public PowerManager.ThermalStatusCallback();
+ method public void onStatusChange(int);
}
public final class PowerManager.WakeLock {
@@ -37536,8 +37783,8 @@ package android.provider {
field public static final java.lang.String DATE_TAKEN = "datetaken";
field public static final java.lang.String DESCRIPTION = "description";
field public static final java.lang.String IS_PRIVATE = "isprivate";
- field public static final java.lang.String LATITUDE = "latitude";
- field public static final java.lang.String LONGITUDE = "longitude";
+ field public static final deprecated java.lang.String LATITUDE = "latitude";
+ field public static final deprecated java.lang.String LONGITUDE = "longitude";
field public static final deprecated java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
field public static final java.lang.String ORIENTATION = "orientation";
field public static final deprecated java.lang.String PICASA_ID = "picasa_id";
@@ -37661,8 +37908,8 @@ package android.provider {
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String IS_PRIVATE = "isprivate";
field public static final java.lang.String LANGUAGE = "language";
- field public static final java.lang.String LATITUDE = "latitude";
- field public static final java.lang.String LONGITUDE = "longitude";
+ field public static final deprecated java.lang.String LATITUDE = "latitude";
+ field public static final deprecated java.lang.String LONGITUDE = "longitude";
field public static final deprecated java.lang.String MINI_THUMB_MAGIC = "mini_thumb_magic";
field public static final java.lang.String RESOLUTION = "resolution";
field public static final java.lang.String TAGS = "tags";
@@ -45886,8 +46133,8 @@ package android.text.style {
method public deprecated java.lang.String getLocale();
method public java.util.Locale getLocaleObject();
method public int getSpanTypeId();
- method public int getUnderlineColor();
method public java.lang.String[] getSuggestions();
+ method public int getUnderlineColor();
method public void setFlags(int);
method public void updateDrawState(android.text.TextPaint);
method public void writeToParcel(android.os.Parcel, int);
@@ -47888,6 +48135,7 @@ package android.view {
method public final boolean isFunctionPressed();
method public static final boolean isGamepadButton(int);
method public final boolean isLongPress();
+ method public static final boolean isMediaSessionKey(int);
method public final boolean isMetaPressed();
method public static boolean isModifierKey(int);
method public final boolean isNumLockOn();
@@ -55080,6 +55328,7 @@ package android.widget {
method public void setInt(int, java.lang.String, int);
method public void setIntent(int, java.lang.String, android.content.Intent);
method public void setLabelFor(int, int);
+ method public void setLightBackgroundLayoutId(int);
method public void setLong(int, java.lang.String, long);
method public void setOnClickFillInIntent(int, android.content.Intent);
method public void setOnClickPendingIntent(int, android.app.PendingIntent);
@@ -55711,6 +55960,7 @@ package android.widget {
method public java.lang.CharSequence getText();
method public android.view.textclassifier.TextClassifier getTextClassifier();
method public final android.content.res.ColorStateList getTextColors();
+ method public android.graphics.drawable.Drawable getTextCursorDrawable();
method public android.text.TextDirectionHeuristic getTextDirectionHeuristic();
method public java.util.Locale getTextLocale();
method public android.os.LocaleList getTextLocales();
@@ -55841,6 +56091,8 @@ package android.widget {
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
method public void setTextColor(int);
method public void setTextColor(android.content.res.ColorStateList);
+ method public void setTextCursorDrawable(android.graphics.drawable.Drawable);
+ method public void setTextCursorDrawable(int);
method public void setTextIsSelectable(boolean);
method public final void setTextKeepState(java.lang.CharSequence);
method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType);
diff --git a/api/system-current.txt b/api/system-current.txt
index 0f054841c669..0b2871325e13 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -57,6 +57,7 @@ package android {
field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
field public static final java.lang.String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
field public static final java.lang.String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
+ field public static final java.lang.String CONTROL_DISPLAY_COLOR_TRANSFORMS = "android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS";
field public static final java.lang.String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
field public static final java.lang.String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
field public static final java.lang.String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS";
@@ -2927,6 +2928,20 @@ package android.media {
method public void stop();
}
+ public static class SubtitleData.Builder {
+ ctor public SubtitleData.Builder();
+ ctor public SubtitleData.Builder(android.media.SubtitleData);
+ method public android.media.SubtitleData build();
+ method public android.media.SubtitleData.Builder setSubtitleData(int, long, long, byte[]);
+ }
+
+ public static class TimedMetaData.Builder {
+ ctor public TimedMetaData.Builder();
+ ctor public TimedMetaData.Builder(android.media.TimedMetaData);
+ method public android.media.TimedMetaData build();
+ method public android.media.TimedMetaData.Builder setTimedMetaData(int, byte[]);
+ }
+
}
package android.media.audiopolicy {
@@ -3014,6 +3029,7 @@ package android.media.audiopolicy {
package android.media.session {
public final class MediaSessionManager {
+ method public android.media.session.ISession createSession(android.media.session.MediaSession.CallbackStub, java.lang.String, int);
method public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, android.os.Handler);
method public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, android.os.Handler);
}
@@ -3890,14 +3906,6 @@ package android.net.wifi.aware {
}
-package android.net.wifi.p2p {
-
- public class WifiP2pManager {
- method public void factoryReset(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
- }
-
-}
-
package android.net.wifi.rtt {
public static final class RangingRequest.Builder {
@@ -4998,6 +5006,7 @@ package android.service.intelligence {
}
public final class FillRequest {
+ method public android.view.autofill.AutofillValue getFocusedAutofillValue();
method public android.view.autofill.AutofillId getFocusedId();
method public android.service.intelligence.PresentationParams getPresentationParams();
method public android.service.intelligence.InteractionSessionId getSessionId();
@@ -5786,6 +5795,8 @@ package android.telephony {
method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList();
method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
method public void requestEmbeddedSubscriptionInfoListRefresh();
+ method public void setDefaultDataSubId(int);
+ method public void setDefaultSmsSubId(int);
method public void setSubscriptionOverrideCongested(int, boolean, long);
method public void setSubscriptionOverrideUnmetered(int, boolean, long);
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
@@ -7360,22 +7371,8 @@ package android.webkit {
ctor public SslErrorHandler();
}
- public abstract class TokenBindingService {
+ public abstract deprecated class TokenBindingService {
ctor public TokenBindingService();
- method public abstract void deleteAllKeys(android.webkit.ValueCallback<java.lang.Boolean>);
- method public abstract void deleteKey(android.net.Uri, android.webkit.ValueCallback<java.lang.Boolean>);
- method public abstract void enableTokenBinding();
- method public static android.webkit.TokenBindingService getInstance();
- method public abstract void getKey(android.net.Uri, java.lang.String[], android.webkit.ValueCallback<android.webkit.TokenBindingService.TokenBindingKey>);
- field public static final java.lang.String KEY_ALGORITHM_ECDSAP256 = "ECDSAP256";
- field public static final java.lang.String KEY_ALGORITHM_RSA2048_PKCS_1_5 = "RSA2048_PKCS_1.5";
- field public static final java.lang.String KEY_ALGORITHM_RSA2048_PSS = "RSA2048PSS";
- }
-
- public static abstract class TokenBindingService.TokenBindingKey {
- ctor public TokenBindingService.TokenBindingKey();
- method public abstract java.lang.String getAlgorithm();
- method public abstract java.security.KeyPair getKeyPair();
}
public class WebChromeClient {
@@ -7505,7 +7502,7 @@ package android.webkit {
method public abstract android.webkit.GeolocationPermissions getGeolocationPermissions();
method public abstract android.webkit.ServiceWorkerController getServiceWorkerController();
method public abstract android.webkit.WebViewFactoryProvider.Statics getStatics();
- method public abstract android.webkit.TokenBindingService getTokenBindingService();
+ method public abstract deprecated android.webkit.TokenBindingService getTokenBindingService();
method public abstract android.webkit.TracingController getTracingController();
method public abstract android.webkit.WebIconDatabase getWebIconDatabase();
method public abstract android.webkit.WebStorage getWebStorage();
diff --git a/config/hiddenapi-max-sdk-p-blacklist.txt b/config/hiddenapi-greylist-max-p.txt
index e69de29bb2d1..e69de29bb2d1 100644
--- a/config/hiddenapi-max-sdk-p-blacklist.txt
+++ b/config/hiddenapi-greylist-max-p.txt
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-greylist.txt
index e10f72913d22..579ef938fb1d 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -51,6 +51,7 @@ Landroid/app/backup/IBackupManager;->setBackupEnabled(Z)V
Landroid/app/backup/IFullBackupRestoreObserver$Stub;-><init>()V
Landroid/app/backup/IRestoreObserver$Stub;-><init>()V
Landroid/app/DownloadManager;->restartDownload([J)V
+Landroid/app/IActivityController$Stub;-><init>()V
Landroid/app/IActivityManager$Stub$Proxy;->getConfiguration()Landroid/content/res/Configuration;
Landroid/app/IActivityManager$Stub$Proxy;->getLaunchedFromUid(Landroid/os/IBinder;)I
Landroid/app/IActivityManager$Stub$Proxy;->getProcessLimit()I
@@ -62,25 +63,35 @@ Landroid/app/IActivityManager$Stub$Proxy;->updatePersistentConfiguration(Landroi
Landroid/app/IActivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/IActivityManager;->bindService(Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/content/Intent;Ljava/lang/String;Landroid/app/IServiceConnection;ILjava/lang/String;I)I
Landroid/app/IActivityManager;->broadcastIntent(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;Landroid/content/IIntentReceiver;ILjava/lang/String;Landroid/os/Bundle;[Ljava/lang/String;ILandroid/os/Bundle;ZZI)I
+Landroid/app/IActivityManager;->cancelRecentsAnimation(Z)V
+Landroid/app/IActivityManager;->cancelTaskWindowTransition(I)V
Landroid/app/IActivityManager;->checkPermission(Ljava/lang/String;II)I
+Landroid/app/IActivityManager;->closeSystemDialogs(Ljava/lang/String;)V
Landroid/app/IActivityManager;->finishActivity(Landroid/os/IBinder;ILandroid/content/Intent;I)Z
Landroid/app/IActivityManager;->finishHeavyWeightApp()V
Landroid/app/IActivityManager;->finishReceiver(Landroid/os/IBinder;ILjava/lang/String;Landroid/os/Bundle;ZI)V
Landroid/app/IActivityManager;->forceStopPackage(Ljava/lang/String;I)V
Landroid/app/IActivityManager;->getAllStackInfos()Ljava/util/List;
Landroid/app/IActivityManager;->getConfiguration()Landroid/content/res/Configuration;
+Landroid/app/IActivityManager;->getCurrentUser()Landroid/content/pm/UserInfo;
+Landroid/app/IActivityManager;->getFilteredTasks(III)Ljava/util/List;
Landroid/app/IActivityManager;->getIntentForIntentSender(Landroid/content/IIntentSender;)Landroid/content/Intent;
Landroid/app/IActivityManager;->getIntentSender(ILjava/lang/String;Landroid/os/IBinder;Ljava/lang/String;I[Landroid/content/Intent;[Ljava/lang/String;ILandroid/os/Bundle;I)Landroid/content/IIntentSender;
Landroid/app/IActivityManager;->getLaunchedFromPackage(Landroid/os/IBinder;)Ljava/lang/String;
Landroid/app/IActivityManager;->getLaunchedFromUid(Landroid/os/IBinder;)I
+Landroid/app/IActivityManager;->getLockTaskModeState()I
Landroid/app/IActivityManager;->getMemoryInfo(Landroid/app/ActivityManager$MemoryInfo;)V
Landroid/app/IActivityManager;->getPackageProcessState(Ljava/lang/String;Ljava/lang/String;)I
Landroid/app/IActivityManager;->getProcessLimit()I
+Landroid/app/IActivityManager;->getProcessMemoryInfo([I)[Landroid/os/Debug$MemoryInfo;
Landroid/app/IActivityManager;->getProcessPss([I)[J
Landroid/app/IActivityManager;->getProviderMimeType(Landroid/net/Uri;I)Ljava/lang/String;
+Landroid/app/IActivityManager;->getRecentTasks(III)Landroid/content/pm/ParceledListSlice;
+Landroid/app/IActivityManager;->getRunningAppProcesses()Ljava/util/List;
Landroid/app/IActivityManager;->getServices(II)Ljava/util/List;
Landroid/app/IActivityManager;->getTaskBounds(I)Landroid/graphics/Rect;
Landroid/app/IActivityManager;->getTaskForActivity(Landroid/os/IBinder;Z)I
+Landroid/app/IActivityManager;->getTaskSnapshot(IZ)Landroid/app/ActivityManager$TaskSnapshot;
Landroid/app/IActivityManager;->handleApplicationStrictModeViolation(Landroid/os/IBinder;ILandroid/os/StrictMode$ViolationInfo;)V
Landroid/app/IActivityManager;->hang(Landroid/os/IBinder;Z)V
Landroid/app/IActivityManager;->isInLockTaskMode()Z
@@ -98,9 +109,11 @@ Landroid/app/IActivityManager;->profileControl(Ljava/lang/String;IZLandroid/app/
Landroid/app/IActivityManager;->publishContentProviders(Landroid/app/IApplicationThread;Ljava/util/List;)V
Landroid/app/IActivityManager;->registerProcessObserver(Landroid/app/IProcessObserver;)V
Landroid/app/IActivityManager;->registerReceiver(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/IIntentReceiver;Landroid/content/IntentFilter;Ljava/lang/String;II)Landroid/content/Intent;
+Landroid/app/IActivityManager;->registerTaskStackListener(Landroid/app/ITaskStackListener;)V
Landroid/app/IActivityManager;->registerUserSwitchObserver(Landroid/app/IUserSwitchObserver;Ljava/lang/String;)V
Landroid/app/IActivityManager;->removeContentProviderExternal(Ljava/lang/String;Landroid/os/IBinder;)V
Landroid/app/IActivityManager;->removeStack(I)V
+Landroid/app/IActivityManager;->removeTask(I)Z
Landroid/app/IActivityManager;->requestBugReport(I)V
Landroid/app/IActivityManager;->resizeDockedStack(Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;)V
Landroid/app/IActivityManager;->resizeStack(ILandroid/graphics/Rect;ZZZI)V
@@ -120,8 +133,12 @@ Landroid/app/IActivityManager;->setProcessMemoryTrimLevel(Ljava/lang/String;II)Z
Landroid/app/IActivityManager;->setRequestedOrientation(Landroid/os/IBinder;I)V
Landroid/app/IActivityManager;->setTaskResizeable(II)V
Landroid/app/IActivityManager;->shutdown(I)Z
+Landroid/app/IActivityManager;->startActivity(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;)I
+Landroid/app/IActivityManager;->startActivityAsUser(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;I)I
+Landroid/app/IActivityManager;->startActivityFromRecents(ILandroid/os/Bundle;)I
Landroid/app/IActivityManager;->startBinderTracking()Z
Landroid/app/IActivityManager;->startInstrumentation(Landroid/content/ComponentName;Ljava/lang/String;ILandroid/os/Bundle;Landroid/app/IInstrumentationWatcher;Landroid/app/IUiAutomationConnection;ILjava/lang/String;)Z
+Landroid/app/IActivityManager;->startRecentsActivity(Landroid/content/Intent;Landroid/app/IAssistDataReceiver;Landroid/view/IRecentsAnimationRunner;)V
Landroid/app/IActivityManager;->startSystemLockTaskMode(I)V
Landroid/app/IActivityManager;->startUserInBackground(I)Z
Landroid/app/IActivityManager;->stopAppSwitches()V
@@ -144,12 +161,16 @@ Landroid/app/IAlarmManager$Stub;->TRANSACTION_remove:I
Landroid/app/IAlarmManager$Stub;->TRANSACTION_set:I
Landroid/app/IAlarmManager;->getNextAlarmClock(I)Landroid/app/AlarmManager$AlarmClockInfo;
Landroid/app/IAlarmManager;->set(Ljava/lang/String;IJJJILandroid/app/PendingIntent;Landroid/app/IAlarmListener;Ljava/lang/String;Landroid/os/WorkSource;Landroid/app/AlarmManager$AlarmClockInfo;)V
+Landroid/app/IAlarmManager;->setTime(J)Z
Landroid/app/IApplicationThread;->scheduleBindService(Landroid/os/IBinder;Landroid/content/Intent;ZI)V
Landroid/app/IApplicationThread;->scheduleCreateService(Landroid/os/IBinder;Landroid/content/pm/ServiceInfo;Landroid/content/res/CompatibilityInfo;I)V
Landroid/app/IApplicationThread;->scheduleStopService(Landroid/os/IBinder;)V
Landroid/app/IApplicationThread;->scheduleTrimMemory(I)V
Landroid/app/IApplicationThread;->scheduleUnbindService(Landroid/os/IBinder;Landroid/content/Intent;)V
Landroid/app/IAppTask;->getTaskInfo()Landroid/app/ActivityManager$RecentTaskInfo;
+Landroid/app/IAssistDataReceiver$Stub;-><init>()V
+Landroid/app/IAssistDataReceiver;->onHandleAssistData(Landroid/os/Bundle;)V
+Landroid/app/IAssistDataReceiver;->onHandleAssistScreenshot(Landroid/graphics/Bitmap;)V
Landroid/app/IInputForwarder;->forwardEvent(Landroid/view/InputEvent;)Z
Landroid/app/IInstrumentationWatcher$Stub;-><init>()V
Landroid/app/IInstrumentationWatcher$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IInstrumentationWatcher;
@@ -236,6 +257,7 @@ Landroid/bluetooth/IBluetooth;->fetchRemoteUuids(Landroid/bluetooth/BluetoothDev
Landroid/bluetooth/IBluetooth;->getAddress()Ljava/lang/String;
Landroid/bluetooth/IBluetooth;->getRemoteAlias(Landroid/bluetooth/BluetoothDevice;)Ljava/lang/String;
Landroid/bluetooth/IBluetooth;->isEnabled()Z
+Landroid/bluetooth/IBluetooth;->sendConnectionStateChange(Landroid/bluetooth/BluetoothDevice;III)V
Landroid/bluetooth/IBluetoothA2dp$Stub;-><init>()V
Landroid/bluetooth/IBluetoothA2dp$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothA2dp;
Landroid/bluetooth/IBluetoothA2dp;->connect(Landroid/bluetooth/BluetoothDevice;)Z
@@ -266,6 +288,10 @@ Landroid/bluetooth/IBluetoothManager;->unregisterStateChangeCallback(Landroid/bl
Landroid/bluetooth/IBluetoothManagerCallback$Stub;-><init>()V
Landroid/bluetooth/IBluetoothPbap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbap;
Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;-><init>()V
+Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V
+Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelected(Ljava/lang/String;ILjava/lang/String;)V
+Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelectionCancel()V
+Landroid/companion/IFindDeviceCallback;->onSuccess(Landroid/app/PendingIntent;)V
Landroid/content/ContentProviderProxy;->mRemote:Landroid/os/IBinder;
Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
@@ -312,11 +338,13 @@ Landroid/content/om/IOverlayManager;->getOverlayInfo(Ljava/lang/String;I)Landroi
Landroid/content/pm/IPackageDataObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/pm/IPackageDataObserver$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Landroid/content/pm/IPackageDataObserver$Stub$Proxy;->onRemoveCompleted(Ljava/lang/String;Z)V
+Landroid/content/pm/IPackageDataObserver$Stub;-><init>()V
Landroid/content/pm/IPackageDataObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDataObserver;
Landroid/content/pm/IPackageDataObserver$Stub;->DESCRIPTOR:Ljava/lang/String;
Landroid/content/pm/IPackageDataObserver$Stub;->TRANSACTION_onRemoveCompleted:I
Landroid/content/pm/IPackageDataObserver;->onRemoveCompleted(Ljava/lang/String;Z)V
Landroid/content/pm/IPackageDeleteObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/content/pm/IPackageDeleteObserver$Stub;-><init>()V
Landroid/content/pm/IPackageDeleteObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDeleteObserver;
Landroid/content/pm/IPackageDeleteObserver$Stub;->DESCRIPTOR:Ljava/lang/String;
Landroid/content/pm/IPackageDeleteObserver$Stub;->TRANSACTION_packageDeleted:I
@@ -325,6 +353,7 @@ Landroid/content/pm/IPackageDeleteObserver2$Stub$Proxy;->mRemote:Landroid/os/IBi
Landroid/content/pm/IPackageDeleteObserver2$Stub;-><init>()V
Landroid/content/pm/IPackageDeleteObserver2$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDeleteObserver2;
Landroid/content/pm/IPackageDeleteObserver2;->onPackageDeleted(Ljava/lang/String;ILjava/lang/String;)V
+Landroid/content/pm/IPackageDeleteObserver;->packageDeleted(Ljava/lang/String;I)V
Landroid/content/pm/IPackageInstaller;->uninstall(Landroid/content/pm/VersionedPackage;Ljava/lang/String;ILandroid/content/IntentSender;I)V
Landroid/content/pm/IPackageInstallerCallback$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/pm/IPackageInstallerCallback$Stub$Proxy;->mRemote:Landroid/os/IBinder;
@@ -364,11 +393,14 @@ Landroid/content/pm/IPackageManager;->checkUidSignatures(II)I
Landroid/content/pm/IPackageManager;->clearPackagePreferredActivities(Ljava/lang/String;)V
Landroid/content/pm/IPackageManager;->currentToCanonicalPackageNames([Ljava/lang/String;)[Ljava/lang/String;
Landroid/content/pm/IPackageManager;->deleteApplicationCacheFiles(Ljava/lang/String;Landroid/content/pm/IPackageDataObserver;)V
+Landroid/content/pm/IPackageManager;->getActivityInfo(Landroid/content/ComponentName;II)Landroid/content/pm/ActivityInfo;
Landroid/content/pm/IPackageManager;->getApplicationEnabledSetting(Ljava/lang/String;I)I
+Landroid/content/pm/IPackageManager;->getApplicationInfo(Ljava/lang/String;II)Landroid/content/pm/ApplicationInfo;
Landroid/content/pm/IPackageManager;->getAppOpPermissionPackages(Ljava/lang/String;)[Ljava/lang/String;
Landroid/content/pm/IPackageManager;->getBlockUninstallForUser(Ljava/lang/String;I)Z
Landroid/content/pm/IPackageManager;->getComponentEnabledSetting(Landroid/content/ComponentName;I)I
Landroid/content/pm/IPackageManager;->getFlagsForUid(I)I
+Landroid/content/pm/IPackageManager;->getHomeActivities(Ljava/util/List;)Landroid/content/ComponentName;
Landroid/content/pm/IPackageManager;->getInstalledApplications(II)Landroid/content/pm/ParceledListSlice;
Landroid/content/pm/IPackageManager;->getInstalledPackages(II)Landroid/content/pm/ParceledListSlice;
Landroid/content/pm/IPackageManager;->getInstallerPackageName(Ljava/lang/String;)Ljava/lang/String;
@@ -376,6 +408,7 @@ Landroid/content/pm/IPackageManager;->getInstallLocation()I
Landroid/content/pm/IPackageManager;->getInstrumentationInfo(Landroid/content/ComponentName;I)Landroid/content/pm/InstrumentationInfo;
Landroid/content/pm/IPackageManager;->getLastChosenActivity(Landroid/content/Intent;Ljava/lang/String;I)Landroid/content/pm/ResolveInfo;
Landroid/content/pm/IPackageManager;->getNameForUid(I)Ljava/lang/String;
+Landroid/content/pm/IPackageManager;->getPackageInfo(Ljava/lang/String;II)Landroid/content/pm/PackageInfo;
Landroid/content/pm/IPackageManager;->getPackageInstaller()Landroid/content/pm/IPackageInstaller;
Landroid/content/pm/IPackageManager;->getPackagesForUid(I)[Ljava/lang/String;
Landroid/content/pm/IPackageManager;->getPackageUid(Ljava/lang/String;II)I
@@ -415,6 +448,7 @@ Landroid/content/pm/IPackageStatsObserver$Stub;-><init>()V
Landroid/content/pm/IPackageStatsObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageStatsObserver;
Landroid/content/pm/IPackageStatsObserver$Stub;->DESCRIPTOR:Ljava/lang/String;
Landroid/content/pm/IPackageStatsObserver$Stub;->TRANSACTION_onGetStatsCompleted:I
+Landroid/content/pm/IPackageStatsObserver;->onGetStatsCompleted(Landroid/content/pm/PackageStats;Z)V
Landroid/content/pm/IShortcutService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/pm/IShortcutService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IShortcutService;
Landroid/content/res/ConfigurationBoundResourceCache;-><init>()V
@@ -438,6 +472,7 @@ Landroid/hardware/input/IInputManager$Stub;->asInterface(Landroid/os/IBinder;)La
Landroid/hardware/input/IInputManager$Stub;->TRANSACTION_injectInputEvent:I
Landroid/hardware/input/IInputManager;->injectInputEvent(Landroid/view/InputEvent;I)Z
Landroid/hardware/location/IActivityRecognitionHardwareClient$Stub;-><init>()V
+Landroid/hardware/location/IActivityRecognitionHardwareClient;->onAvailabilityChanged(ZLandroid/hardware/location/IActivityRecognitionHardware;)V
Landroid/hardware/location/IContextHubService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/location/IContextHubService;
Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/hardware/usb/IUsbManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/usb/IUsbManager;
@@ -447,7 +482,10 @@ Landroid/location/ICountryDetector$Stub;->asInterface(Landroid/os/IBinder;)Landr
Landroid/location/ICountryListener$Stub;-><init>()V
Landroid/location/IGeocodeProvider$Stub;-><init>()V
Landroid/location/IGeocodeProvider$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/IGeocodeProvider;
+Landroid/location/IGeocodeProvider;->getFromLocation(DDILandroid/location/GeocoderParams;Ljava/util/List;)Ljava/lang/String;
+Landroid/location/IGeocodeProvider;->getFromLocationName(Ljava/lang/String;DDDDILandroid/location/GeocoderParams;Ljava/util/List;)Ljava/lang/String;
Landroid/location/IGeofenceProvider$Stub;-><init>()V
+Landroid/location/IGeofenceProvider;->setGeofenceHardware(Landroid/hardware/location/IGeofenceHardware;)V
Landroid/location/ILocationListener$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/location/ILocationListener$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Landroid/location/ILocationListener$Stub;-><init>()V
@@ -460,6 +498,10 @@ Landroid/location/ILocationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager;
Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I
Landroid/location/ILocationManager;->getAllProviders()Ljava/util/List;
+Landroid/location/ILocationManager;->getNetworkProviderPackage()Ljava/lang/String;
+Landroid/location/ILocationManager;->reportLocation(Landroid/location/Location;Z)V
+Landroid/location/INetInitiatedListener$Stub;-><init>()V
+Landroid/location/INetInitiatedListener;->sendNiResponse(II)Z
Landroid/location/LocationManager$ListenerTransport;-><init>(Landroid/location/LocationManager;Landroid/location/LocationListener;Landroid/os/Looper;)V
Landroid/Manifest$permission;->CAPTURE_SECURE_VIDEO_OUTPUT:Ljava/lang/String;
Landroid/Manifest$permission;->CAPTURE_VIDEO_OUTPUT:Ljava/lang/String;
@@ -486,6 +528,17 @@ Landroid/media/MediaFile;-><init>()V
Landroid/media/MediaScanner$MyMediaScannerClient;-><init>(Landroid/media/MediaScanner;)V
Landroid/media/projection/IMediaProjectionManager;->hasProjectionPermission(ILjava/lang/String;)Z
Landroid/media/session/ISessionManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/session/ISessionManager;
+Landroid/media/tv/ITvRemoteProvider$Stub;-><init>()V
+Landroid/media/tv/ITvRemoteServiceInput;->clearInputBridge(Landroid/os/IBinder;)V
+Landroid/media/tv/ITvRemoteServiceInput;->closeInputBridge(Landroid/os/IBinder;)V
+Landroid/media/tv/ITvRemoteServiceInput;->openInputBridge(Landroid/os/IBinder;Ljava/lang/String;III)V
+Landroid/media/tv/ITvRemoteServiceInput;->sendKeyDown(Landroid/os/IBinder;I)V
+Landroid/media/tv/ITvRemoteServiceInput;->sendKeyUp(Landroid/os/IBinder;I)V
+Landroid/media/tv/ITvRemoteServiceInput;->sendPointerDown(Landroid/os/IBinder;III)V
+Landroid/media/tv/ITvRemoteServiceInput;->sendPointerSync(Landroid/os/IBinder;)V
+Landroid/media/tv/ITvRemoteServiceInput;->sendPointerUp(Landroid/os/IBinder;I)V
+Landroid/media/tv/ITvRemoteServiceInput;->sendTimestamp(Landroid/os/IBinder;J)V
+Landroid/net/ConnectivityManager$PacketKeepaliveCallback;-><init>()V
Landroid/net/IConnectivityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/IConnectivityManager$Stub$Proxy;->getActiveLinkProperties()Landroid/net/LinkProperties;
Landroid/net/IConnectivityManager$Stub$Proxy;->getActiveNetworkInfo()Landroid/net/NetworkInfo;
@@ -499,6 +552,7 @@ Landroid/net/IConnectivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landro
Landroid/net/IConnectivityManager;->getActiveLinkProperties()Landroid/net/LinkProperties;
Landroid/net/IConnectivityManager;->getActiveNetworkInfo()Landroid/net/NetworkInfo;
Landroid/net/IConnectivityManager;->getAllNetworkInfo()[Landroid/net/NetworkInfo;
+Landroid/net/IConnectivityManager;->getAllNetworkState()[Landroid/net/NetworkState;
Landroid/net/IConnectivityManager;->getLastTetherError(Ljava/lang/String;)I
Landroid/net/IConnectivityManager;->getNetworkInfo(I)Landroid/net/NetworkInfo;
Landroid/net/IConnectivityManager;->getTetherableIfaces()[Ljava/lang/String;
@@ -508,9 +562,12 @@ Landroid/net/IConnectivityManager;->getTetheredIfaces()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->getTetheringErroredIfaces()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->reportInetCondition(II)V
Landroid/net/IConnectivityManager;->startLegacyVpn(Lcom/android/internal/net/VpnProfile;)V
+Landroid/net/INetd$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetd;
+Landroid/net/INetd;->interfaceAddAddress(Ljava/lang/String;Ljava/lang/String;I)V
Landroid/net/INetworkManagementEventObserver$Stub;-><init>()V
Landroid/net/INetworkPolicyListener$Stub;-><init>()V
Landroid/net/INetworkPolicyManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkPolicyManager;
+Landroid/net/INetworkPolicyManager;->getNetworkQuotaInfo(Landroid/net/NetworkState;)Landroid/net/NetworkQuotaInfo;
Landroid/net/INetworkPolicyManager;->getRestrictBackground()Z
Landroid/net/INetworkPolicyManager;->getUidPolicy(I)I
Landroid/net/INetworkPolicyManager;->setNetworkPolicies([Landroid/net/NetworkPolicy;)V
@@ -520,14 +577,19 @@ Landroid/net/INetworkPolicyManager;->snoozeLimit(Landroid/net/NetworkTemplate;)V
Landroid/net/INetworkScoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkScoreService;
Landroid/net/INetworkStatsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String;
+Landroid/net/INetworkStatsService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkStatsService;
Landroid/net/INetworkStatsService;->forceUpdate()V
Landroid/net/INetworkStatsService;->getDataLayerSnapshotForUid(I)Landroid/net/NetworkStats;
Landroid/net/INetworkStatsService;->getMobileIfaces()[Ljava/lang/String;
Landroid/net/INetworkStatsService;->openSession()Landroid/net/INetworkStatsSession;
Landroid/net/INetworkStatsService;->openSessionForUsageStats(ILjava/lang/String;)Landroid/net/INetworkStatsSession;
Landroid/net/INetworkStatsSession;->close()V
+Landroid/net/INetworkStatsSession;->getHistoryForNetwork(Landroid/net/NetworkTemplate;I)Landroid/net/NetworkStatsHistory;
+Landroid/net/INetworkStatsSession;->getHistoryForUid(Landroid/net/NetworkTemplate;IIII)Landroid/net/NetworkStatsHistory;
Landroid/net/INetworkStatsSession;->getSummaryForAllUid(Landroid/net/NetworkTemplate;JJZ)Landroid/net/NetworkStats;
Landroid/net/INetworkStatsSession;->getSummaryForNetwork(Landroid/net/NetworkTemplate;JJ)Landroid/net/NetworkStats;
+Landroid/net/InterfaceConfiguration;-><init>()V
+Landroid/net/LinkProperties$ProvisioningChange;->values()[Landroid/net/LinkProperties$ProvisioningChange;
Landroid/net/MobileLinkQualityInfo;-><init>()V
Landroid/net/nsd/INsdManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/nsd/INsdManager;
Landroid/net/nsd/INsdManager;->getMessenger()Landroid/os/Messenger;
@@ -552,7 +614,12 @@ Landroid/nfc/INfcAdapterExtras;->getDriverName(Ljava/lang/String;)Ljava/lang/Str
Landroid/nfc/INfcAdapterExtras;->open(Ljava/lang/String;Landroid/os/IBinder;)Landroid/os/Bundle;
Landroid/nfc/INfcAdapterExtras;->setCardEmulationRoute(Ljava/lang/String;I)V
Landroid/nfc/INfcAdapterExtras;->transceive(Ljava/lang/String;[B)Landroid/os/Bundle;
+Landroid/os/AsyncResult;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Throwable;)V
+Landroid/os/AsyncResult;->exception:Ljava/lang/Throwable;
Landroid/os/AsyncResult;->forMessage(Landroid/os/Message;)Landroid/os/AsyncResult;
+Landroid/os/AsyncResult;->forMessage(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)Landroid/os/AsyncResult;
+Landroid/os/AsyncResult;->result:Ljava/lang/Object;
+Landroid/os/AsyncResult;->userObj:Ljava/lang/Object;
Landroid/os/AsyncTask;->mFuture:Ljava/util/concurrent/FutureTask;
Landroid/os/AsyncTask;->mStatus:Landroid/os/AsyncTask$Status;
Landroid/os/AsyncTask;->mTaskInvoked:Ljava/util/concurrent/atomic/AtomicBoolean;
@@ -569,18 +636,24 @@ Landroid/os/BatteryManager;->EXTRA_MAX_CHARGING_CURRENT:Ljava/lang/String;
Landroid/os/BatteryManager;->EXTRA_MAX_CHARGING_VOLTAGE:Ljava/lang/String;
Landroid/os/BatteryStats$Counter;-><init>()V
Landroid/os/BatteryStats$Counter;->getCountLocked(I)I
+Landroid/os/BatteryStats$HistoryItem;-><init>()V
Landroid/os/BatteryStats$HistoryItem;->batteryHealth:B
+Landroid/os/BatteryStats$HistoryItem;->batteryLevel:B
Landroid/os/BatteryStats$HistoryItem;->batteryPlugType:B
Landroid/os/BatteryStats$HistoryItem;->batteryStatus:B
Landroid/os/BatteryStats$HistoryItem;->batteryVoltage:C
Landroid/os/BatteryStats$HistoryItem;->clear()V
+Landroid/os/BatteryStats$HistoryItem;->cmd:B
Landroid/os/BatteryStats$HistoryItem;->CMD_UPDATE:B
Landroid/os/BatteryStats$HistoryItem;->next:Landroid/os/BatteryStats$HistoryItem;
Landroid/os/BatteryStats$HistoryItem;->same(Landroid/os/BatteryStats$HistoryItem;)Z
Landroid/os/BatteryStats$HistoryItem;->setTo(JBLandroid/os/BatteryStats$HistoryItem;)V
Landroid/os/BatteryStats$HistoryItem;->setTo(Landroid/os/BatteryStats$HistoryItem;)V
Landroid/os/BatteryStats$HistoryItem;->states2:I
+Landroid/os/BatteryStats$HistoryItem;->states:I
+Landroid/os/BatteryStats$HistoryItem;->time:J
Landroid/os/BatteryStats$Timer;-><init>()V
+Landroid/os/BatteryStats$Timer;->getCountLocked(I)I
Landroid/os/BatteryStats$Timer;->getTotalTimeLocked(JI)J
Landroid/os/BatteryStats$Uid$Pkg$Serv;->getLaunches(I)I
Landroid/os/BatteryStats$Uid$Pkg$Serv;->getStarts(I)I
@@ -604,6 +677,8 @@ Landroid/os/BatteryStats$Uid$Sensor;->getHandle()I
Landroid/os/BatteryStats$Uid$Sensor;->getSensorTime()Landroid/os/BatteryStats$Timer;
Landroid/os/BatteryStats$Uid$Sensor;->GPS:I
Landroid/os/BatteryStats$Uid$Wakelock;-><init>()V
+Landroid/os/BatteryStats$Uid$Wakelock;->getWakeTime(I)Landroid/os/BatteryStats$Timer;
+Landroid/os/BatteryStats$Uid;-><init>()V
Landroid/os/BatteryStats$Uid;->getAudioTurnedOnTimer()Landroid/os/BatteryStats$Timer;
Landroid/os/BatteryStats$Uid;->getFullWifiLockTime(JI)J
Landroid/os/BatteryStats$Uid;->getMobileRadioActiveTime(I)J
@@ -616,6 +691,7 @@ Landroid/os/BatteryStats$Uid;->getVideoTurnedOnTimer()Landroid/os/BatteryStats$T
Landroid/os/BatteryStats$Uid;->getWakelockStats()Landroid/util/ArrayMap;
Landroid/os/BatteryStats$Uid;->getWifiBatchedScanTime(IJI)J
Landroid/os/BatteryStats$Uid;->getWifiMulticastTime(JI)J
+Landroid/os/BatteryStats$Uid;->getWifiRunningTime(JI)J
Landroid/os/BatteryStats$Uid;->getWifiScanTime(JI)J
Landroid/os/BatteryStats;-><init>()V
Landroid/os/BatteryStats;->computeBatteryRealtime(JI)J
@@ -627,6 +703,7 @@ Landroid/os/BatteryStats;->getBatteryUptime(J)J
Landroid/os/BatteryStats;->getGlobalWifiRunningTime(JI)J
Landroid/os/BatteryStats;->getMobileRadioActiveTime(JI)J
Landroid/os/BatteryStats;->getNetworkActivityBytes(II)J
+Landroid/os/BatteryStats;->getNextHistoryLocked(Landroid/os/BatteryStats$HistoryItem;)Z
Landroid/os/BatteryStats;->getPhoneOnTime(JI)J
Landroid/os/BatteryStats;->getPhoneSignalStrengthTime(IJI)J
Landroid/os/BatteryStats;->getScreenBrightnessTime(IJI)J
@@ -640,6 +717,10 @@ Landroid/os/BatteryStats;->STATS_CURRENT:I
Landroid/os/BatteryStats;->WAKE_TYPE_PARTIAL:I
Landroid/os/Binder;->execTransact(IJJI)Z
Landroid/os/Binder;->mObject:J
+Landroid/os/Broadcaster;-><init>()V
+Landroid/os/Broadcaster;->broadcast(Landroid/os/Message;)V
+Landroid/os/Broadcaster;->cancelRequest(ILandroid/os/Handler;I)V
+Landroid/os/Broadcaster;->request(ILandroid/os/Handler;I)V
Landroid/os/Build$VERSION;->ACTIVE_CODENAMES:[Ljava/lang/String;
Landroid/os/Build;->getLong(Ljava/lang/String;)J
Landroid/os/Build;->getString(Ljava/lang/String;)Ljava/lang/String;
@@ -713,6 +794,7 @@ Landroid/os/Environment;->buildExternalStorageAppMediaDirs(Ljava/lang/String;)[L
Landroid/os/Environment;->buildExternalStorageAppObbDirs(Ljava/lang/String;)[Ljava/io/File;
Landroid/os/Environment;->buildPaths([Ljava/io/File;[Ljava/lang/String;)[Ljava/io/File;
Landroid/os/Environment;->getDataSystemDirectory()Ljava/io/File;
+Landroid/os/Environment;->getLegacyExternalStorageDirectory()Ljava/io/File;
Landroid/os/Environment;->getLegacyExternalStorageObbDirectory()Ljava/io/File;
Landroid/os/Environment;->initForCurrentUser()V
Landroid/os/Environment;->maybeTranslateEmulatedPathToInternal(Ljava/io/File;)Ljava/io/File;
@@ -733,12 +815,15 @@ Landroid/os/FileUtils;->setPermissions(Ljava/lang/String;III)I
Landroid/os/FileUtils;->stringToFile(Ljava/io/File;Ljava/lang/String;)V
Landroid/os/FileUtils;->stringToFile(Ljava/lang/String;Ljava/lang/String;)V
Landroid/os/FileUtils;->sync(Ljava/io/FileOutputStream;)Z
+Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V
Landroid/os/Handler;-><init>(Z)V
Landroid/os/Handler;->getIMessenger()Landroid/os/IMessenger;
+Landroid/os/Handler;->getMain()Landroid/os/Handler;
Landroid/os/Handler;->getPostMessage(Ljava/lang/Runnable;Ljava/lang/Object;)Landroid/os/Message;
Landroid/os/Handler;->mCallback:Landroid/os/Handler$Callback;
Landroid/os/Handler;->mLooper:Landroid/os/Looper;
Landroid/os/Handler;->mMessenger:Landroid/os/IMessenger;
+Landroid/os/HwBinder;->reportSyspropChanged()V
Landroid/os/HwParcel;-><init>(Z)V
Landroid/os/HwRemoteBinder;-><init>()V
Landroid/os/IBatteryPropertiesRegistrar$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -749,16 +834,26 @@ Landroid/os/IDeviceIdleController;->addPowerSaveTempWhitelistApp(Ljava/lang/Stri
Landroid/os/IDeviceIdleController;->getAppIdTempWhitelist()[I
Landroid/os/IDeviceIdleController;->getFullPowerWhitelistExceptIdle()[Ljava/lang/String;
Landroid/os/INetworkManagementService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/os/INetworkManagementService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/INetworkManagementService;
+Landroid/os/INetworkManagementService;->clearInterfaceAddresses(Ljava/lang/String;)V
+Landroid/os/INetworkManagementService;->disableIpv6(Ljava/lang/String;)V
Landroid/os/INetworkManagementService;->disableNat(Ljava/lang/String;Ljava/lang/String;)V
+Landroid/os/INetworkManagementService;->enableIpv6(Ljava/lang/String;)V
Landroid/os/INetworkManagementService;->enableNat(Ljava/lang/String;Ljava/lang/String;)V
Landroid/os/INetworkManagementService;->getInterfaceConfig(Ljava/lang/String;)Landroid/net/InterfaceConfiguration;
Landroid/os/INetworkManagementService;->getIpForwardingEnabled()Z
+Landroid/os/INetworkManagementService;->isBandwidthControlEnabled()Z
Landroid/os/INetworkManagementService;->isTetheringStarted()Z
Landroid/os/INetworkManagementService;->listTetheredInterfaces()[Ljava/lang/String;
+Landroid/os/INetworkManagementService;->registerObserver(Landroid/net/INetworkManagementEventObserver;)V
+Landroid/os/INetworkManagementService;->setInterfaceConfig(Ljava/lang/String;Landroid/net/InterfaceConfiguration;)V
+Landroid/os/INetworkManagementService;->setInterfaceIpv6PrivacyExtensions(Ljava/lang/String;Z)V
Landroid/os/INetworkManagementService;->setIpForwardingEnabled(Z)V
+Landroid/os/INetworkManagementService;->setIPv6AddrGenMode(Ljava/lang/String;I)V
Landroid/os/INetworkManagementService;->startTethering([Ljava/lang/String;)V
Landroid/os/INetworkManagementService;->stopTethering()V
Landroid/os/INetworkManagementService;->tetherInterface(Ljava/lang/String;)V
+Landroid/os/INetworkManagementService;->unregisterObserver(Landroid/net/INetworkManagementEventObserver;)V
Landroid/os/INetworkManagementService;->untetherInterface(Ljava/lang/String;)V
Landroid/os/IPermissionController$Stub$Proxy;->checkPermission(Ljava/lang/String;II)Z
Landroid/os/IPermissionController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IPermissionController;
@@ -767,12 +862,15 @@ Landroid/os/IPowerManager$Stub$Proxy;->isLightDeviceIdleMode()Z
Landroid/os/IPowerManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IPowerManager;
Landroid/os/IPowerManager$Stub;->TRANSACTION_acquireWakeLock:I
Landroid/os/IPowerManager$Stub;->TRANSACTION_goToSleep:I
+Landroid/os/IPowerManager;->goToSleep(JII)V
Landroid/os/IPowerManager;->isInteractive()Z
Landroid/os/IPowerManager;->nap(J)V
+Landroid/os/IPowerManager;->reboot(ZLjava/lang/String;Z)V
Landroid/os/IPowerManager;->releaseWakeLock(Landroid/os/IBinder;I)V
Landroid/os/IPowerManager;->userActivity(JII)V
Landroid/os/IPowerManager;->wakeUp(JLjava/lang/String;Ljava/lang/String;)V
Landroid/os/IRecoverySystem$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IRecoverySystem;
+Landroid/os/IRemoteCallback$Stub;-><init>()V
Landroid/os/IRemoteCallback;->sendResult(Landroid/os/Bundle;)V
Landroid/os/IServiceManager;->checkService(Ljava/lang/String;)Landroid/os/IBinder;
Landroid/os/IServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder;
@@ -798,6 +896,7 @@ Landroid/os/Message;->flags:I
Landroid/os/Message;->markInUse()V
Landroid/os/Message;->next:Landroid/os/Message;
Landroid/os/Message;->recycleUnchecked()V
+Landroid/os/Message;->setCallback(Ljava/lang/Runnable;)Landroid/os/Message;
Landroid/os/Message;->target:Landroid/os/Handler;
Landroid/os/Message;->toString(J)Ljava/lang/String;
Landroid/os/Message;->when:J
@@ -817,13 +916,16 @@ Landroid/os/Parcel;->mCreators:Ljava/util/HashMap;
Landroid/os/Parcel;->mNativePtr:J
Landroid/os/Parcel;->readArrayMap(Landroid/util/ArrayMap;Ljava/lang/ClassLoader;)V
Landroid/os/Parcel;->readArraySet(Ljava/lang/ClassLoader;)Landroid/util/ArraySet;
+Landroid/os/Parcel;->readBlob()[B
Landroid/os/Parcel;->readCharSequence()Ljava/lang/CharSequence;
Landroid/os/Parcel;->readCreator(Landroid/os/Parcelable$Creator;Ljava/lang/ClassLoader;)Landroid/os/Parcelable;
Landroid/os/Parcel;->readExceptionCode()I
Landroid/os/Parcel;->readParcelableCreator(Ljava/lang/ClassLoader;)Landroid/os/Parcelable$Creator;
Landroid/os/Parcel;->readRawFileDescriptor()Ljava/io/FileDescriptor;
+Landroid/os/Parcel;->readStringArray()[Ljava/lang/String;
Landroid/os/Parcel;->writeArrayMap(Landroid/util/ArrayMap;)V
Landroid/os/Parcel;->writeArraySet(Landroid/util/ArraySet;)V
+Landroid/os/Parcel;->writeBlob([B)V
Landroid/os/Parcel;->writeCharSequence(Ljava/lang/CharSequence;)V
Landroid/os/Parcel;->writeParcelableCreator(Landroid/os/Parcelable;)V
Landroid/os/ParcelableParcel;-><init>(Ljava/lang/ClassLoader;)V
@@ -890,15 +992,27 @@ Landroid/os/Process;->SHELL_UID:I
Landroid/os/Process;->VPN_UID:I
Landroid/os/Process;->WIFI_UID:I
Landroid/os/RecoverySystem;->verifyPackageCompatibility(Ljava/io/InputStream;)Z
+Landroid/os/Registrant;-><init>(Landroid/os/Handler;ILjava/lang/Object;)V
+Landroid/os/Registrant;->clear()V
Landroid/os/Registrant;->getHandler()Landroid/os/Handler;
Landroid/os/Registrant;->messageForRegistrant()Landroid/os/Message;
+Landroid/os/Registrant;->notifyRegistrant()V
+Landroid/os/Registrant;->notifyRegistrant(Landroid/os/AsyncResult;)V
Landroid/os/Registrant;->notifyResult(Ljava/lang/Object;)V
+Landroid/os/RegistrantList;-><init>()V
Landroid/os/RegistrantList;->add(Landroid/os/Handler;ILjava/lang/Object;)V
+Landroid/os/RegistrantList;->add(Landroid/os/Registrant;)V
+Landroid/os/RegistrantList;->addUnique(Landroid/os/Handler;ILjava/lang/Object;)V
Landroid/os/RegistrantList;->get(I)Ljava/lang/Object;
+Landroid/os/RegistrantList;->notifyRegistrants()V
+Landroid/os/RegistrantList;->notifyRegistrants(Landroid/os/AsyncResult;)V
Landroid/os/RegistrantList;->notifyResult(Ljava/lang/Object;)V
+Landroid/os/RegistrantList;->remove(Landroid/os/Handler;)V
+Landroid/os/RegistrantList;->removeCleared()V
Landroid/os/RegistrantList;->size()I
Landroid/os/RemoteCallback;->mHandler:Landroid/os/Handler;
Landroid/os/RemoteCallbackList;->mCallbacks:Landroid/util/ArrayMap;
+Landroid/os/RemoteException;->rethrowFromSystemServer()Ljava/lang/RuntimeException;
Landroid/os/SELinux;->checkSELinuxAccess(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
Landroid/os/SELinux;->getContext()Ljava/lang/String;
Landroid/os/SELinux;->getFileContext(Ljava/lang/String;)Ljava/lang/String;
@@ -920,6 +1034,7 @@ Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/
Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder;
Landroid/os/ServiceManagerProxy;->mRemote:Landroid/os/IBinder;
Landroid/os/ServiceSpecificException;-><init>(ILjava/lang/String;)V
+Landroid/os/ServiceSpecificException;->errorCode:I
Landroid/os/SharedMemory;->getFd()I
Landroid/os/ShellCommand;->peekNextArg()Ljava/lang/String;
Landroid/os/StatFs;->mStat:Landroid/system/StructStatVfs;
@@ -927,6 +1042,7 @@ Landroid/os/storage/IObbActionListener$Stub;-><init>()V
Landroid/os/storage/IObbActionListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IObbActionListener;
Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
+Landroid/os/storage/StorageEventListener;-><init>()V
Landroid/os/StrictMode$Span;->finish()V
Landroid/os/StrictMode$ThreadPolicy;->mask:I
Landroid/os/StrictMode$VmPolicy$Builder;->mMask:I
@@ -954,8 +1070,12 @@ Landroid/os/SystemProperties;->native_get_int(Ljava/lang/String;I)I
Landroid/os/SystemProperties;->native_get_long(Ljava/lang/String;J)J
Landroid/os/SystemProperties;->native_set(Ljava/lang/String;Ljava/lang/String;)V
Landroid/os/SystemProperties;->PROP_NAME_MAX:I
+Landroid/os/SystemProperties;->reportSyspropChanged()V
Landroid/os/SystemProperties;->sChangeCallbacks:Ljava/util/ArrayList;
Landroid/os/SystemProperties;->set(Ljava/lang/String;Ljava/lang/String;)V
+Landroid/os/SystemService;->start(Ljava/lang/String;)V
+Landroid/os/SystemService;->stop(Ljava/lang/String;)V
+Landroid/os/SystemVibrator;-><init>()V
Landroid/os/SystemVibrator;-><init>(Landroid/content/Context;)V
Landroid/os/Trace;->asyncTraceBegin(JLjava/lang/String;I)V
Landroid/os/Trace;->asyncTraceEnd(JLjava/lang/String;I)V
@@ -994,6 +1114,7 @@ Landroid/os/UserHandle;->getCallingUserId()I
Landroid/os/UserHandle;->getUid(II)I
Landroid/os/UserHandle;->getUserId(I)I
Landroid/os/UserHandle;->isIsolated(I)Z
+Landroid/os/UserHandle;->isSameApp(II)Z
Landroid/os/UserHandle;->mHandle:I
Landroid/os/UserHandle;->MU_ENABLED:Z
Landroid/os/UserHandle;->OWNER:Landroid/os/UserHandle;
@@ -1023,6 +1144,7 @@ Landroid/os/UserManager;->getUserSerialNumber(I)I
Landroid/os/UserManager;->getUserStartRealtime()J
Landroid/os/UserManager;->getUserUnlockRealtime()J
Landroid/os/UserManager;->hasBaseUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
+Landroid/os/UserManager;->hasUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
Landroid/os/UserManager;->isDeviceInDemoMode(Landroid/content/Context;)Z
Landroid/os/UserManager;->isGuestUser(I)Z
Landroid/os/UserManager;->isLinkedUser()Z
@@ -1072,6 +1194,7 @@ Landroid/R$styleable;->CalendarView_unfocusedMonthDateColor:I
Landroid/R$styleable;->CalendarView_weekDayTextAppearance:I
Landroid/R$styleable;->CalendarView_weekNumberColor:I
Landroid/R$styleable;->CalendarView_weekSeparatorLineColor:I
+Landroid/R$styleable;->CheckBoxPreference:[I
Landroid/R$styleable;->CheckedTextView:[I
Landroid/R$styleable;->CheckedTextView_checkMark:I
Landroid/R$styleable;->CompoundButton:[I
@@ -1382,7 +1505,18 @@ Landroid/speech/IRecognitionListener;->onEvent(ILandroid/os/Bundle;)V
Landroid/telecom/Log;->i(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
Landroid/telecom/Log;->w(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
Landroid/telephony/CarrierMessagingServiceManager;-><init>()V
+Landroid/telephony/ims/compat/feature/MMTelFeature;-><init>()V
+Landroid/telephony/ims/compat/ImsService;-><init>()V
+Landroid/telephony/ims/compat/stub/ImsCallSessionImplBase;-><init>()V
+Landroid/telephony/ims/compat/stub/ImsUtListenerImplBase;-><init>()V
Landroid/telephony/JapanesePhoneNumberFormatter;->format(Landroid/text/Editable;)V
+Landroid/telephony/mbms/IMbmsStreamingSessionCallback$Stub;-><init>()V
+Landroid/telephony/mbms/IStreamingServiceCallback$Stub;-><init>()V
+Landroid/telephony/mbms/vendor/IMbmsStreamingService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/telephony/mbms/vendor/IMbmsStreamingService;
+Landroid/telephony/mbms/vendor/IMbmsStreamingService;->getPlaybackUri(ILjava/lang/String;)Landroid/net/Uri;
+Landroid/telephony/mbms/vendor/IMbmsStreamingService;->initialize(Landroid/telephony/mbms/IMbmsStreamingSessionCallback;I)I
+Landroid/telephony/mbms/vendor/IMbmsStreamingService;->requestUpdateStreamingServices(ILjava/util/List;)I
+Landroid/telephony/mbms/vendor/IMbmsStreamingService;->startStreaming(ILjava/lang/String;Landroid/telephony/mbms/IStreamingServiceCallback;)I
Landroid/telephony/SmsCbCmasInfo;->getCategory()I
Landroid/telephony/SmsCbCmasInfo;->getCertainty()I
Landroid/telephony/SmsCbCmasInfo;->getMessageClass()I
@@ -1424,10 +1558,21 @@ Landroid/view/accessibility/IAccessibilityManager;->getEnabledAccessibilityServi
Landroid/view/AccessibilityIterators$AbstractTextSegmentIterator;-><init>()V
Landroid/view/autofill/IAutoFillManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/view/autofill/IAutoFillManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/autofill/IAutoFillManager;
+Landroid/view/IAppTransitionAnimationSpecsFuture$Stub;-><init>()V
Landroid/view/IDockedStackListener$Stub;-><init>()V
Landroid/view/IGraphicsStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/view/IGraphicsStats$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IGraphicsStats;
+Landroid/view/IRecentsAnimationController;->finish(Z)V
+Landroid/view/IRecentsAnimationController;->screenshotTask(I)Landroid/app/ActivityManager$TaskSnapshot;
Landroid/view/IRecentsAnimationController;->setAnimationTargetsBehindSystemBars(Z)V
+Landroid/view/IRecentsAnimationController;->setInputConsumerEnabled(Z)V
+Landroid/view/IRecentsAnimationRunner$Stub;-><init>()V
+Landroid/view/IRecentsAnimationRunner;->onAnimationCanceled()V
+Landroid/view/IRecentsAnimationRunner;->onAnimationStart(Landroid/view/IRecentsAnimationController;[Landroid/view/RemoteAnimationTarget;Landroid/graphics/Rect;Landroid/graphics/Rect;)V
+Landroid/view/IRemoteAnimationFinishedCallback;->onAnimationFinished()V
+Landroid/view/IRemoteAnimationRunner$Stub;-><init>()V
+Landroid/view/IRemoteAnimationRunner;->onAnimationCancelled()V
+Landroid/view/IRemoteAnimationRunner;->onAnimationStart([Landroid/view/RemoteAnimationTarget;Landroid/view/IRemoteAnimationFinishedCallback;)V
Landroid/view/IRotationWatcher$Stub;-><init>()V
Landroid/view/IWindow$Stub;-><init>()V
Landroid/view/IWindow$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IWindow;
@@ -1439,6 +1584,9 @@ Landroid/view/IWindowManager$Stub$Proxy;->hasNavigationBar(I)Z
Landroid/view/IWindowManager$Stub$Proxy;->watchRotation(Landroid/view/IRotationWatcher;I)I
Landroid/view/IWindowManager$Stub;-><init>()V
Landroid/view/IWindowManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IWindowManager;
+Landroid/view/IWindowManager;->createInputConsumer(Landroid/os/IBinder;Ljava/lang/String;ILandroid/view/InputChannel;)V
+Landroid/view/IWindowManager;->destroyInputConsumer(Ljava/lang/String;I)Z
+Landroid/view/IWindowManager;->endProlongedAnimations()V
Landroid/view/IWindowManager;->executeAppTransition()V
Landroid/view/IWindowManager;->freezeRotation(I)V
Landroid/view/IWindowManager;->getAnimationScale(I)F
@@ -1447,16 +1595,20 @@ Landroid/view/IWindowManager;->getBaseDisplaySize(ILandroid/graphics/Point;)V
Landroid/view/IWindowManager;->getDockedStackSide()I
Landroid/view/IWindowManager;->getInitialDisplayDensity(I)I
Landroid/view/IWindowManager;->getInitialDisplaySize(ILandroid/graphics/Point;)V
+Landroid/view/IWindowManager;->getStableInsets(ILandroid/graphics/Rect;)V
Landroid/view/IWindowManager;->hasNavigationBar(I)Z
Landroid/view/IWindowManager;->isKeyguardLocked()Z
Landroid/view/IWindowManager;->isKeyguardSecure()Z
Landroid/view/IWindowManager;->isSafeModeEnabled()Z
Landroid/view/IWindowManager;->lockNow(Landroid/os/Bundle;)V
+Landroid/view/IWindowManager;->overridePendingAppTransitionMultiThumbFuture(Landroid/view/IAppTransitionAnimationSpecsFuture;Landroid/os/IRemoteCallback;ZI)V
+Landroid/view/IWindowManager;->overridePendingAppTransitionRemote(Landroid/view/RemoteAnimationAdapter;I)V
Landroid/view/IWindowManager;->registerDockedStackListener(Landroid/view/IDockedStackListener;)V
Landroid/view/IWindowManager;->removeRotationWatcher(Landroid/view/IRotationWatcher;)V
Landroid/view/IWindowManager;->setAnimationScale(IF)V
Landroid/view/IWindowManager;->setAnimationScales([F)V
Landroid/view/IWindowManager;->setInTouchMode(Z)V
+Landroid/view/IWindowManager;->setNavBarVirtualKeyHapticFeedbackEnabled(Z)V
Landroid/view/IWindowManager;->setShelfHeight(ZI)V
Landroid/view/IWindowManager;->setStrictModeVisualIndicatorPreference(Ljava/lang/String;)V
Landroid/view/IWindowManager;->showStrictModeViolation(Z)V
@@ -1496,6 +1648,7 @@ Lcom/android/ims/ImsCall;->isMultiparty()Z
Lcom/android/ims/ImsCall;->reject(I)V
Lcom/android/ims/ImsCall;->terminate(I)V
Lcom/android/ims/ImsConfigListener$Stub;-><init>()V
+Lcom/android/ims/ImsConfigListener;->onSetFeatureResponse(IIII)V
Lcom/android/ims/ImsEcbm;->exitEmergencyCallbackMode()V
Lcom/android/ims/ImsManager;->getConfigInterface()Lcom/android/ims/ImsConfig;
Lcom/android/ims/ImsManager;->getInstance(Landroid/content/Context;I)Lcom/android/ims/ImsManager;
@@ -1505,12 +1658,48 @@ Lcom/android/ims/ImsManager;->isVolteEnabledByPlatform(Landroid/content/Context;
Lcom/android/ims/ImsUtInterface;->queryCallForward(ILjava/lang/String;Landroid/os/Message;)V
Lcom/android/ims/internal/IImsCallSession$Stub;-><init>()V
Lcom/android/ims/internal/IImsCallSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/ims/internal/IImsCallSession;
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionConferenceStateUpdated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsConferenceState;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHandover(Lcom/android/ims/internal/IImsCallSession;IILandroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHandoverFailed(Lcom/android/ims/internal/IImsCallSession;IILandroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHeld(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHoldFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHoldReceived(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionInviteParticipantsRequestDelivered(Lcom/android/ims/internal/IImsCallSession;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionInviteParticipantsRequestFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMergeComplete(Lcom/android/ims/internal/IImsCallSession;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMergeFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMergeStarted(Lcom/android/ims/internal/IImsCallSession;Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMultipartyStateChanged(Lcom/android/ims/internal/IImsCallSession;Z)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionProgressing(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsStreamMediaProfile;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionResumed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionResumeFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionResumeReceived(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionStarted(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionStartFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionSuppServiceReceived(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsSuppServiceNotification;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionTerminated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionTtyModeReceived(Lcom/android/ims/internal/IImsCallSession;I)V
+Lcom/android/ims/internal/IImsCallSessionListener;->callSessionUpdated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
Lcom/android/ims/internal/IImsConfig$Stub;-><init>()V
Lcom/android/ims/internal/IImsEcbm$Stub;-><init>()V
+Lcom/android/ims/internal/IImsRegistrationListener;->registrationAssociatedUriChanged([Landroid/net/Uri;)V
+Lcom/android/ims/internal/IImsRegistrationListener;->registrationChangeFailed(ILandroid/telephony/ims/ImsReasonInfo;)V
Lcom/android/ims/internal/IImsRegistrationListener;->registrationConnected()V
+Lcom/android/ims/internal/IImsRegistrationListener;->registrationConnectedWithRadioTech(I)V
+Lcom/android/ims/internal/IImsRegistrationListener;->registrationDisconnected(Landroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/IImsRegistrationListener;->registrationFeatureCapabilityChanged(I[I[I)V
+Lcom/android/ims/internal/IImsRegistrationListener;->registrationProgressingWithRadioTech(I)V
+Lcom/android/ims/internal/IImsRegistrationListener;->voiceMessageCountUpdate(I)V
Lcom/android/ims/internal/IImsService$Stub;-><init>()V
Lcom/android/ims/internal/IImsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/ims/internal/IImsService;
Lcom/android/ims/internal/IImsUt$Stub;-><init>()V
+Lcom/android/ims/internal/IImsUtListener;->utConfigurationCallBarringQueried(Lcom/android/ims/internal/IImsUt;I[Landroid/telephony/ims/ImsSsInfo;)V
+Lcom/android/ims/internal/IImsUtListener;->utConfigurationCallForwardQueried(Lcom/android/ims/internal/IImsUt;I[Landroid/telephony/ims/ImsCallForwardInfo;)V
+Lcom/android/ims/internal/IImsUtListener;->utConfigurationCallWaitingQueried(Lcom/android/ims/internal/IImsUt;I[Landroid/telephony/ims/ImsSsInfo;)V
+Lcom/android/ims/internal/IImsUtListener;->utConfigurationQueried(Lcom/android/ims/internal/IImsUt;ILandroid/os/Bundle;)V
+Lcom/android/ims/internal/IImsUtListener;->utConfigurationQueryFailed(Lcom/android/ims/internal/IImsUt;ILandroid/telephony/ims/ImsReasonInfo;)V
+Lcom/android/ims/internal/IImsUtListener;->utConfigurationUpdated(Lcom/android/ims/internal/IImsUt;I)V
+Lcom/android/ims/internal/IImsUtListener;->utConfigurationUpdateFailed(Lcom/android/ims/internal/IImsUt;ILandroid/telephony/ims/ImsReasonInfo;)V
Lcom/android/ims/internal/IImsVideoCallCallback;->changeCallDataUsage(J)V
Lcom/android/ims/internal/IImsVideoCallCallback;->changeCameraCapabilities(Landroid/telecom/VideoProfile$CameraCapabilities;)V
Lcom/android/ims/internal/IImsVideoCallCallback;->changePeerDimensions(II)V
@@ -1521,7 +1710,52 @@ Lcom/android/ims/internal/IImsVideoCallCallback;->receiveSessionModifyResponse(I
Lcom/android/ims/internal/IImsVideoCallProvider$Stub;-><init>()V
Lcom/android/ims/internal/IImsVideoCallProvider;->setCallback(Lcom/android/ims/internal/IImsVideoCallCallback;)V
Lcom/android/ims/internal/ImsVideoCallProviderWrapper;-><init>(Lcom/android/ims/internal/IImsVideoCallProvider;)V
+Lcom/android/ims/internal/uce/options/IOptionsListener;->cmdStatus(Lcom/android/ims/internal/uce/options/OptionsCmdStatus;)V
+Lcom/android/ims/internal/uce/options/IOptionsListener;->getVersionCb(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/options/IOptionsListener;->incomingOptions(Ljava/lang/String;Lcom/android/ims/internal/uce/options/OptionsCapInfo;I)V
+Lcom/android/ims/internal/uce/options/IOptionsListener;->serviceAvailable(Lcom/android/ims/internal/uce/common/StatusCode;)V
+Lcom/android/ims/internal/uce/options/IOptionsListener;->serviceUnavailable(Lcom/android/ims/internal/uce/common/StatusCode;)V
+Lcom/android/ims/internal/uce/options/IOptionsListener;->sipResponseReceived(Ljava/lang/String;Lcom/android/ims/internal/uce/options/OptionsSipResponse;Lcom/android/ims/internal/uce/options/OptionsCapInfo;)V
+Lcom/android/ims/internal/uce/options/IOptionsService$Stub;-><init>()V
+Lcom/android/ims/internal/uce/options/IOptionsService;->addListener(ILcom/android/ims/internal/uce/options/IOptionsListener;Lcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/options/IOptionsService;->getContactCap(ILjava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/options/IOptionsService;->getContactListCap(I[Ljava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/options/IOptionsService;->getMyInfo(II)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/options/IOptionsService;->getVersion(I)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/options/IOptionsService;->removeListener(ILcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/options/IOptionsService;->responseIncomingOptions(IIILjava/lang/String;Lcom/android/ims/internal/uce/options/OptionsCapInfo;Z)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/options/IOptionsService;->setMyInfo(ILcom/android/ims/internal/uce/common/CapInfo;I)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/presence/IPresenceListener;->capInfoReceived(Ljava/lang/String;[Lcom/android/ims/internal/uce/presence/PresTupleInfo;)V
+Lcom/android/ims/internal/uce/presence/IPresenceListener;->cmdStatus(Lcom/android/ims/internal/uce/presence/PresCmdStatus;)V
+Lcom/android/ims/internal/uce/presence/IPresenceListener;->getVersionCb(Ljava/lang/String;)V
+Lcom/android/ims/internal/uce/presence/IPresenceListener;->listCapInfoReceived(Lcom/android/ims/internal/uce/presence/PresRlmiInfo;[Lcom/android/ims/internal/uce/presence/PresResInfo;)V
+Lcom/android/ims/internal/uce/presence/IPresenceListener;->publishTriggering(Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;)V
+Lcom/android/ims/internal/uce/presence/IPresenceListener;->serviceAvailable(Lcom/android/ims/internal/uce/common/StatusCode;)V
+Lcom/android/ims/internal/uce/presence/IPresenceListener;->serviceUnAvailable(Lcom/android/ims/internal/uce/common/StatusCode;)V
+Lcom/android/ims/internal/uce/presence/IPresenceListener;->sipResponseReceived(Lcom/android/ims/internal/uce/presence/PresSipResponse;)V
+Lcom/android/ims/internal/uce/presence/IPresenceListener;->unpublishMessageSent()V
+Lcom/android/ims/internal/uce/presence/IPresenceService$Stub;-><init>()V
+Lcom/android/ims/internal/uce/presence/IPresenceService;->addListener(ILcom/android/ims/internal/uce/presence/IPresenceListener;Lcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/presence/IPresenceService;->getContactCap(ILjava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/presence/IPresenceService;->getContactListCap(I[Ljava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/presence/IPresenceService;->getVersion(I)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/presence/IPresenceService;->publishMyCap(ILcom/android/ims/internal/uce/presence/PresCapInfo;I)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/presence/IPresenceService;->reenableService(II)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/presence/IPresenceService;->removeListener(ILcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode;
+Lcom/android/ims/internal/uce/presence/IPresenceService;->setNewFeatureTag(ILjava/lang/String;Lcom/android/ims/internal/uce/presence/PresServiceInfo;I)Lcom/android/ims/internal/uce/common/StatusCode;
Lcom/android/ims/internal/uce/uceservice/IUceListener$Stub;-><init>()V
+Lcom/android/ims/internal/uce/uceservice/IUceListener;->setStatus(I)V
+Lcom/android/ims/internal/uce/uceservice/IUceService$Stub;-><init>()V
+Lcom/android/ims/internal/uce/uceservice/IUceService;->createOptionsService(Lcom/android/ims/internal/uce/options/IOptionsListener;Lcom/android/ims/internal/uce/common/UceLong;)I
+Lcom/android/ims/internal/uce/uceservice/IUceService;->createPresenceService(Lcom/android/ims/internal/uce/presence/IPresenceListener;Lcom/android/ims/internal/uce/common/UceLong;)I
+Lcom/android/ims/internal/uce/uceservice/IUceService;->destroyOptionsService(I)V
+Lcom/android/ims/internal/uce/uceservice/IUceService;->destroyPresenceService(I)V
+Lcom/android/ims/internal/uce/uceservice/IUceService;->getOptionsService()Lcom/android/ims/internal/uce/options/IOptionsService;
+Lcom/android/ims/internal/uce/uceservice/IUceService;->getPresenceService()Lcom/android/ims/internal/uce/presence/IPresenceService;
+Lcom/android/ims/internal/uce/uceservice/IUceService;->getServiceStatus()Z
+Lcom/android/ims/internal/uce/uceservice/IUceService;->isServiceStarted()Z
+Lcom/android/ims/internal/uce/uceservice/IUceService;->startService(Lcom/android/ims/internal/uce/uceservice/IUceListener;)Z
+Lcom/android/ims/internal/uce/uceservice/IUceService;->stopService()Z
Lcom/android/internal/app/AlertActivity;-><init>()V
Lcom/android/internal/app/AlertActivity;->mAlert:Lcom/android/internal/app/AlertController;
Lcom/android/internal/app/AlertActivity;->mAlertParams:Lcom/android/internal/app/AlertController$AlertParams;
@@ -1552,6 +1786,7 @@ Lcom/android/internal/app/IAppOpsService$Stub;->TRANSACTION_setUserRestrictions:
Lcom/android/internal/app/IAppOpsService$Stub;->TRANSACTION_startOperation:I
Lcom/android/internal/app/IAppOpsService$Stub;->TRANSACTION_startWatchingMode:I
Lcom/android/internal/app/IAppOpsService$Stub;->TRANSACTION_stopWatchingMode:I
+Lcom/android/internal/app/IAppOpsService;->finishOperation(Landroid/os/IBinder;IILjava/lang/String;)V
Lcom/android/internal/app/IAppOpsService;->getOpsForPackage(ILjava/lang/String;[I)Ljava/util/List;
Lcom/android/internal/app/IAppOpsService;->getPackagesForOps([I)Ljava/util/List;
Lcom/android/internal/app/IAppOpsService;->resetAllModes(ILjava/lang/String;)V
@@ -1599,6 +1834,7 @@ Lcom/android/internal/appwidget/IAppWidgetService;->bindRemoteViewsService(Ljava
Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetIds(Landroid/content/ComponentName;)[I
Lcom/android/internal/appwidget/IAppWidgetService;->getAppWidgetViews(Ljava/lang/String;I)Landroid/widget/RemoteViews;
Lcom/android/internal/backup/IBackupTransport$Stub;-><init>()V
+Lcom/android/internal/content/PackageMonitor;-><init>()V
Lcom/android/internal/database/SortCursor;-><init>([Landroid/database/Cursor;Ljava/lang/String;)V
Lcom/android/internal/database/SortCursor;->mCursor:Landroid/database/Cursor;
Lcom/android/internal/database/SortCursor;->mCursors:[Landroid/database/Cursor;
@@ -1612,6 +1848,14 @@ Lcom/android/internal/location/GpsNetInitiatedHandler;->decodeString(Ljava/lang/
Lcom/android/internal/location/GpsNetInitiatedHandler;->handleNiNotification(Lcom/android/internal/location/GpsNetInitiatedHandler$GpsNiNotification;)V
Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z
Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
+Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider;
+Lcom/android/internal/location/ILocationProvider;->disable()V
+Lcom/android/internal/location/ILocationProvider;->enable()V
+Lcom/android/internal/location/ILocationProvider;->getProperties()Lcom/android/internal/location/ProviderProperties;
+Lcom/android/internal/location/ILocationProvider;->getStatus(Landroid/os/Bundle;)I
+Lcom/android/internal/location/ILocationProvider;->getStatusUpdateTime()J
+Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)Z
+Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V
Lcom/android/internal/logging/MetricsLogger;-><init>()V
Lcom/android/internal/net/LegacyVpnInfo;-><init>()V
Lcom/android/internal/net/VpnConfig;-><init>()V
@@ -1981,6 +2225,7 @@ Lcom/android/internal/R$styleable;->MapView_apiKey:I
Lcom/android/internal/R$styleable;->MenuGroup:[I
Lcom/android/internal/R$styleable;->MenuItem:[I
Lcom/android/internal/R$styleable;->MenuView:[I
+Lcom/android/internal/R$styleable;->NumberPicker:[I
Lcom/android/internal/R$styleable;->PopupWindow:[I
Lcom/android/internal/R$styleable;->PopupWindow_popupAnimationStyle:I
Lcom/android/internal/R$styleable;->PopupWindow_popupBackground:I
@@ -2106,6 +2351,7 @@ Lcom/android/internal/R$styleable;->TextView_textStyle:I
Lcom/android/internal/R$styleable;->TextView_typeface:I
Lcom/android/internal/R$styleable;->TextView_width:I
Lcom/android/internal/R$styleable;->Theme:[I
+Lcom/android/internal/R$styleable;->TwoLineListItem:[I
Lcom/android/internal/R$styleable;->View:[I
Lcom/android/internal/R$styleable;->ViewAnimator:[I
Lcom/android/internal/R$styleable;->ViewFlipper:[I
@@ -3126,6 +3372,7 @@ Lcom/android/internal/telephony/ITelephony;->enableLocationUpdates()V
Lcom/android/internal/telephony/ITelephony;->getActivePhoneType()I
Lcom/android/internal/telephony/ITelephony;->getCallState()I
Lcom/android/internal/telephony/ITelephony;->getDataActivity()I
+Lcom/android/internal/telephony/ITelephony;->getDataEnabled(I)Z
Lcom/android/internal/telephony/ITelephony;->getDataState()I
Lcom/android/internal/telephony/ITelephony;->getNetworkType()I
Lcom/android/internal/telephony/ITelephony;->handlePinMmi(Ljava/lang/String;)Z
diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt
deleted file mode 100644
index a21fa3063f17..000000000000
--- a/config/hiddenapi-vendor-list.txt
+++ /dev/null
@@ -1,247 +0,0 @@
-Landroid/app/IActivityController$Stub;-><init>()V
-Landroid/app/IActivityManager;->cancelRecentsAnimation(Z)V
-Landroid/app/IActivityManager;->cancelTaskWindowTransition(I)V
-Landroid/app/IActivityManager;->closeSystemDialogs(Ljava/lang/String;)V
-Landroid/app/IActivityManager;->getCurrentUser()Landroid/content/pm/UserInfo;
-Landroid/app/IActivityManager;->getFilteredTasks(III)Ljava/util/List;
-Landroid/app/IActivityManager;->getLockTaskModeState()I
-Landroid/app/IActivityManager;->getProcessMemoryInfo([I)[Landroid/os/Debug$MemoryInfo;
-Landroid/app/IActivityManager;->getRecentTasks(III)Landroid/content/pm/ParceledListSlice;
-Landroid/app/IActivityManager;->getRunningAppProcesses()Ljava/util/List;
-Landroid/app/IActivityManager;->getTaskSnapshot(IZ)Landroid/app/ActivityManager$TaskSnapshot;
-Landroid/app/IActivityManager;->registerTaskStackListener(Landroid/app/ITaskStackListener;)V
-Landroid/app/IActivityManager;->removeTask(I)Z
-Landroid/app/IActivityManager;->startActivity(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;)I
-Landroid/app/IActivityManager;->startActivityAsUser(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;I)I
-Landroid/app/IActivityManager;->startActivityFromRecents(ILandroid/os/Bundle;)I
-Landroid/app/IActivityManager;->startRecentsActivity(Landroid/content/Intent;Landroid/app/IAssistDataReceiver;Landroid/view/IRecentsAnimationRunner;)V
-Landroid/app/IAlarmManager;->setTime(J)Z
-Landroid/app/IAssistDataReceiver$Stub;-><init>()V
-Landroid/app/IAssistDataReceiver;->onHandleAssistData(Landroid/os/Bundle;)V
-Landroid/app/IAssistDataReceiver;->onHandleAssistScreenshot(Landroid/graphics/Bitmap;)V
-Landroid/bluetooth/IBluetooth;->sendConnectionStateChange(Landroid/bluetooth/BluetoothDevice;III)V
-Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V
-Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelected(Ljava/lang/String;ILjava/lang/String;)V
-Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelectionCancel()V
-Landroid/companion/IFindDeviceCallback;->onSuccess(Landroid/app/PendingIntent;)V
-Landroid/content/pm/IPackageDataObserver$Stub;-><init>()V
-Landroid/content/pm/IPackageDeleteObserver$Stub;-><init>()V
-Landroid/content/pm/IPackageDeleteObserver;->packageDeleted(Ljava/lang/String;I)V
-Landroid/content/pm/IPackageManager;->getActivityInfo(Landroid/content/ComponentName;II)Landroid/content/pm/ActivityInfo;
-Landroid/content/pm/IPackageManager;->getApplicationInfo(Ljava/lang/String;II)Landroid/content/pm/ApplicationInfo;
-Landroid/content/pm/IPackageManager;->getHomeActivities(Ljava/util/List;)Landroid/content/ComponentName;
-Landroid/content/pm/IPackageManager;->getPackageInfo(Ljava/lang/String;II)Landroid/content/pm/PackageInfo;
-Landroid/content/pm/IPackageStatsObserver;->onGetStatsCompleted(Landroid/content/pm/PackageStats;Z)V
-Landroid/hardware/location/IActivityRecognitionHardwareClient;->onAvailabilityChanged(ZLandroid/hardware/location/IActivityRecognitionHardware;)V
-Landroid/location/IGeocodeProvider;->getFromLocation(DDILandroid/location/GeocoderParams;Ljava/util/List;)Ljava/lang/String;
-Landroid/location/IGeocodeProvider;->getFromLocationName(Ljava/lang/String;DDDDILandroid/location/GeocoderParams;Ljava/util/List;)Ljava/lang/String;
-Landroid/location/IGeofenceProvider;->setGeofenceHardware(Landroid/hardware/location/IGeofenceHardware;)V
-Landroid/location/ILocationManager;->getNetworkProviderPackage()Ljava/lang/String;
-Landroid/location/ILocationManager;->reportLocation(Landroid/location/Location;Z)V
-Landroid/location/INetInitiatedListener$Stub;-><init>()V
-Landroid/location/INetInitiatedListener;->sendNiResponse(II)Z
-Landroid/media/tv/ITvRemoteProvider$Stub;-><init>()V
-Landroid/media/tv/ITvRemoteServiceInput;->clearInputBridge(Landroid/os/IBinder;)V
-Landroid/media/tv/ITvRemoteServiceInput;->closeInputBridge(Landroid/os/IBinder;)V
-Landroid/media/tv/ITvRemoteServiceInput;->openInputBridge(Landroid/os/IBinder;Ljava/lang/String;III)V
-Landroid/media/tv/ITvRemoteServiceInput;->sendKeyDown(Landroid/os/IBinder;I)V
-Landroid/media/tv/ITvRemoteServiceInput;->sendKeyUp(Landroid/os/IBinder;I)V
-Landroid/media/tv/ITvRemoteServiceInput;->sendPointerDown(Landroid/os/IBinder;III)V
-Landroid/media/tv/ITvRemoteServiceInput;->sendPointerSync(Landroid/os/IBinder;)V
-Landroid/media/tv/ITvRemoteServiceInput;->sendPointerUp(Landroid/os/IBinder;I)V
-Landroid/media/tv/ITvRemoteServiceInput;->sendTimestamp(Landroid/os/IBinder;J)V
-Landroid/net/ConnectivityManager$PacketKeepaliveCallback;-><init>()V
-Landroid/net/IConnectivityManager;->getAllNetworkState()[Landroid/net/NetworkState;
-Landroid/net/INetd$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetd;
-Landroid/net/INetd;->interfaceAddAddress(Ljava/lang/String;Ljava/lang/String;I)V
-Landroid/net/INetworkPolicyManager;->getNetworkQuotaInfo(Landroid/net/NetworkState;)Landroid/net/NetworkQuotaInfo;
-Landroid/net/INetworkStatsService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkStatsService;
-Landroid/net/INetworkStatsSession;->getHistoryForNetwork(Landroid/net/NetworkTemplate;I)Landroid/net/NetworkStatsHistory;
-Landroid/net/INetworkStatsSession;->getHistoryForUid(Landroid/net/NetworkTemplate;IIII)Landroid/net/NetworkStatsHistory;
-Landroid/net/InterfaceConfiguration;-><init>()V
-Landroid/net/LinkProperties$ProvisioningChange;->values()[Landroid/net/LinkProperties$ProvisioningChange;
-Landroid/os/AsyncResult;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Throwable;)V
-Landroid/os/AsyncResult;->exception:Ljava/lang/Throwable;
-Landroid/os/AsyncResult;->forMessage(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)Landroid/os/AsyncResult;
-Landroid/os/AsyncResult;->result:Ljava/lang/Object;
-Landroid/os/AsyncResult;->userObj:Ljava/lang/Object;
-Landroid/os/BatteryStats$HistoryItem;-><init>()V
-Landroid/os/BatteryStats$HistoryItem;->batteryLevel:B
-Landroid/os/BatteryStats$HistoryItem;->cmd:B
-Landroid/os/BatteryStats$HistoryItem;->states:I
-Landroid/os/BatteryStats$HistoryItem;->time:J
-Landroid/os/BatteryStats$Timer;->getCountLocked(I)I
-Landroid/os/BatteryStats$Uid$Wakelock;->getWakeTime(I)Landroid/os/BatteryStats$Timer;
-Landroid/os/BatteryStats$Uid;-><init>()V
-Landroid/os/BatteryStats$Uid;->getWifiRunningTime(JI)J
-Landroid/os/BatteryStats;->getNextHistoryLocked(Landroid/os/BatteryStats$HistoryItem;)Z
-Landroid/os/Broadcaster;-><init>()V
-Landroid/os/Broadcaster;->broadcast(Landroid/os/Message;)V
-Landroid/os/Broadcaster;->cancelRequest(ILandroid/os/Handler;I)V
-Landroid/os/Broadcaster;->request(ILandroid/os/Handler;I)V
-Landroid/os/Environment;->getLegacyExternalStorageDirectory()Ljava/io/File;
-Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V
-Landroid/os/Handler;->getMain()Landroid/os/Handler;
-Landroid/os/HwBinder;->reportSyspropChanged()V
-Landroid/os/INetworkManagementService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/INetworkManagementService;
-Landroid/os/INetworkManagementService;->clearInterfaceAddresses(Ljava/lang/String;)V
-Landroid/os/INetworkManagementService;->disableIpv6(Ljava/lang/String;)V
-Landroid/os/INetworkManagementService;->enableIpv6(Ljava/lang/String;)V
-Landroid/os/INetworkManagementService;->isBandwidthControlEnabled()Z
-Landroid/os/INetworkManagementService;->registerObserver(Landroid/net/INetworkManagementEventObserver;)V
-Landroid/os/INetworkManagementService;->setInterfaceConfig(Ljava/lang/String;Landroid/net/InterfaceConfiguration;)V
-Landroid/os/INetworkManagementService;->setInterfaceIpv6PrivacyExtensions(Ljava/lang/String;Z)V
-Landroid/os/INetworkManagementService;->setIPv6AddrGenMode(Ljava/lang/String;I)V
-Landroid/os/INetworkManagementService;->unregisterObserver(Landroid/net/INetworkManagementEventObserver;)V
-Landroid/os/IPowerManager;->goToSleep(JII)V
-Landroid/os/IPowerManager;->reboot(ZLjava/lang/String;Z)V
-Landroid/os/IRemoteCallback$Stub;-><init>()V
-Landroid/os/Message;->setCallback(Ljava/lang/Runnable;)Landroid/os/Message;
-Landroid/os/Parcel;->readBlob()[B
-Landroid/os/Parcel;->readStringArray()[Ljava/lang/String;
-Landroid/os/Parcel;->writeBlob([B)V
-Landroid/os/Registrant;-><init>(Landroid/os/Handler;ILjava/lang/Object;)V
-Landroid/os/Registrant;->clear()V
-Landroid/os/Registrant;->notifyRegistrant()V
-Landroid/os/Registrant;->notifyRegistrant(Landroid/os/AsyncResult;)V
-Landroid/os/RegistrantList;-><init>()V
-Landroid/os/RegistrantList;->add(Landroid/os/Registrant;)V
-Landroid/os/RegistrantList;->addUnique(Landroid/os/Handler;ILjava/lang/Object;)V
-Landroid/os/RegistrantList;->notifyRegistrants()V
-Landroid/os/RegistrantList;->notifyRegistrants(Landroid/os/AsyncResult;)V
-Landroid/os/RegistrantList;->remove(Landroid/os/Handler;)V
-Landroid/os/RegistrantList;->removeCleared()V
-Landroid/os/RemoteException;->rethrowFromSystemServer()Ljava/lang/RuntimeException;
-Landroid/os/ServiceSpecificException;->errorCode:I
-Landroid/os/storage/StorageEventListener;-><init>()V
-Landroid/os/SystemProperties;->reportSyspropChanged()V
-Landroid/os/SystemService;->start(Ljava/lang/String;)V
-Landroid/os/SystemService;->stop(Ljava/lang/String;)V
-Landroid/os/SystemVibrator;-><init>()V
-Landroid/os/UserHandle;->isSameApp(II)Z
-Landroid/os/UserManager;->hasUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
-Landroid/R$styleable;->CheckBoxPreference:[I
-Landroid/telephony/ims/compat/feature/MMTelFeature;-><init>()V
-Landroid/telephony/ims/compat/ImsService;-><init>()V
-Landroid/telephony/ims/compat/stub/ImsCallSessionImplBase;-><init>()V
-Landroid/telephony/ims/compat/stub/ImsUtListenerImplBase;-><init>()V
-Landroid/telephony/mbms/IMbmsStreamingSessionCallback$Stub;-><init>()V
-Landroid/telephony/mbms/IStreamingServiceCallback$Stub;-><init>()V
-Landroid/telephony/mbms/vendor/IMbmsStreamingService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/telephony/mbms/vendor/IMbmsStreamingService;
-Landroid/telephony/mbms/vendor/IMbmsStreamingService;->getPlaybackUri(ILjava/lang/String;)Landroid/net/Uri;
-Landroid/telephony/mbms/vendor/IMbmsStreamingService;->initialize(Landroid/telephony/mbms/IMbmsStreamingSessionCallback;I)I
-Landroid/telephony/mbms/vendor/IMbmsStreamingService;->requestUpdateStreamingServices(ILjava/util/List;)I
-Landroid/telephony/mbms/vendor/IMbmsStreamingService;->startStreaming(ILjava/lang/String;Landroid/telephony/mbms/IStreamingServiceCallback;)I
-Landroid/view/IAppTransitionAnimationSpecsFuture$Stub;-><init>()V
-Landroid/view/IRecentsAnimationController;->finish(Z)V
-Landroid/view/IRecentsAnimationController;->screenshotTask(I)Landroid/app/ActivityManager$TaskSnapshot;
-Landroid/view/IRecentsAnimationController;->setInputConsumerEnabled(Z)V
-Landroid/view/IRecentsAnimationRunner$Stub;-><init>()V
-Landroid/view/IRecentsAnimationRunner;->onAnimationCanceled()V
-Landroid/view/IRecentsAnimationRunner;->onAnimationStart(Landroid/view/IRecentsAnimationController;[Landroid/view/RemoteAnimationTarget;Landroid/graphics/Rect;Landroid/graphics/Rect;)V
-Landroid/view/IRemoteAnimationFinishedCallback;->onAnimationFinished()V
-Landroid/view/IRemoteAnimationRunner$Stub;-><init>()V
-Landroid/view/IRemoteAnimationRunner;->onAnimationCancelled()V
-Landroid/view/IRemoteAnimationRunner;->onAnimationStart([Landroid/view/RemoteAnimationTarget;Landroid/view/IRemoteAnimationFinishedCallback;)V
-Landroid/view/IWindowManager;->createInputConsumer(Landroid/os/IBinder;Ljava/lang/String;ILandroid/view/InputChannel;)V
-Landroid/view/IWindowManager;->destroyInputConsumer(Ljava/lang/String;I)Z
-Landroid/view/IWindowManager;->endProlongedAnimations()V
-Landroid/view/IWindowManager;->getStableInsets(ILandroid/graphics/Rect;)V
-Landroid/view/IWindowManager;->overridePendingAppTransitionMultiThumbFuture(Landroid/view/IAppTransitionAnimationSpecsFuture;Landroid/os/IRemoteCallback;ZI)V
-Landroid/view/IWindowManager;->overridePendingAppTransitionRemote(Landroid/view/RemoteAnimationAdapter;I)V
-Landroid/view/IWindowManager;->setNavBarVirtualKeyHapticFeedbackEnabled(Z)V
-Lcom/android/ims/ImsConfigListener;->onSetFeatureResponse(IIII)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionConferenceStateUpdated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsConferenceState;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHandover(Lcom/android/ims/internal/IImsCallSession;IILandroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHandoverFailed(Lcom/android/ims/internal/IImsCallSession;IILandroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHeld(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHoldFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionHoldReceived(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionInviteParticipantsRequestDelivered(Lcom/android/ims/internal/IImsCallSession;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionInviteParticipantsRequestFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMergeComplete(Lcom/android/ims/internal/IImsCallSession;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMergeFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMergeStarted(Lcom/android/ims/internal/IImsCallSession;Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionMultipartyStateChanged(Lcom/android/ims/internal/IImsCallSession;Z)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionProgressing(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsStreamMediaProfile;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionResumed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionResumeFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionResumeReceived(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionStarted(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionStartFailed(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionSuppServiceReceived(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsSuppServiceNotification;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionTerminated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionTtyModeReceived(Lcom/android/ims/internal/IImsCallSession;I)V
-Lcom/android/ims/internal/IImsCallSessionListener;->callSessionUpdated(Lcom/android/ims/internal/IImsCallSession;Landroid/telephony/ims/ImsCallProfile;)V
-Lcom/android/ims/internal/IImsRegistrationListener;->registrationAssociatedUriChanged([Landroid/net/Uri;)V
-Lcom/android/ims/internal/IImsRegistrationListener;->registrationChangeFailed(ILandroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsRegistrationListener;->registrationConnectedWithRadioTech(I)V
-Lcom/android/ims/internal/IImsRegistrationListener;->registrationDisconnected(Landroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsRegistrationListener;->registrationFeatureCapabilityChanged(I[I[I)V
-Lcom/android/ims/internal/IImsRegistrationListener;->registrationProgressingWithRadioTech(I)V
-Lcom/android/ims/internal/IImsRegistrationListener;->voiceMessageCountUpdate(I)V
-Lcom/android/ims/internal/IImsUtListener;->utConfigurationCallBarringQueried(Lcom/android/ims/internal/IImsUt;I[Landroid/telephony/ims/ImsSsInfo;)V
-Lcom/android/ims/internal/IImsUtListener;->utConfigurationCallForwardQueried(Lcom/android/ims/internal/IImsUt;I[Landroid/telephony/ims/ImsCallForwardInfo;)V
-Lcom/android/ims/internal/IImsUtListener;->utConfigurationCallWaitingQueried(Lcom/android/ims/internal/IImsUt;I[Landroid/telephony/ims/ImsSsInfo;)V
-Lcom/android/ims/internal/IImsUtListener;->utConfigurationQueried(Lcom/android/ims/internal/IImsUt;ILandroid/os/Bundle;)V
-Lcom/android/ims/internal/IImsUtListener;->utConfigurationQueryFailed(Lcom/android/ims/internal/IImsUt;ILandroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/IImsUtListener;->utConfigurationUpdated(Lcom/android/ims/internal/IImsUt;I)V
-Lcom/android/ims/internal/IImsUtListener;->utConfigurationUpdateFailed(Lcom/android/ims/internal/IImsUt;ILandroid/telephony/ims/ImsReasonInfo;)V
-Lcom/android/ims/internal/uce/options/IOptionsListener;->cmdStatus(Lcom/android/ims/internal/uce/options/OptionsCmdStatus;)V
-Lcom/android/ims/internal/uce/options/IOptionsListener;->getVersionCb(Ljava/lang/String;)V
-Lcom/android/ims/internal/uce/options/IOptionsListener;->incomingOptions(Ljava/lang/String;Lcom/android/ims/internal/uce/options/OptionsCapInfo;I)V
-Lcom/android/ims/internal/uce/options/IOptionsListener;->serviceAvailable(Lcom/android/ims/internal/uce/common/StatusCode;)V
-Lcom/android/ims/internal/uce/options/IOptionsListener;->serviceUnavailable(Lcom/android/ims/internal/uce/common/StatusCode;)V
-Lcom/android/ims/internal/uce/options/IOptionsListener;->sipResponseReceived(Ljava/lang/String;Lcom/android/ims/internal/uce/options/OptionsSipResponse;Lcom/android/ims/internal/uce/options/OptionsCapInfo;)V
-Lcom/android/ims/internal/uce/options/IOptionsService$Stub;-><init>()V
-Lcom/android/ims/internal/uce/options/IOptionsService;->addListener(ILcom/android/ims/internal/uce/options/IOptionsListener;Lcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/options/IOptionsService;->getContactCap(ILjava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/options/IOptionsService;->getContactListCap(I[Ljava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/options/IOptionsService;->getMyInfo(II)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/options/IOptionsService;->getVersion(I)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/options/IOptionsService;->removeListener(ILcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/options/IOptionsService;->responseIncomingOptions(IIILjava/lang/String;Lcom/android/ims/internal/uce/options/OptionsCapInfo;Z)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/options/IOptionsService;->setMyInfo(ILcom/android/ims/internal/uce/common/CapInfo;I)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/presence/IPresenceListener;->capInfoReceived(Ljava/lang/String;[Lcom/android/ims/internal/uce/presence/PresTupleInfo;)V
-Lcom/android/ims/internal/uce/presence/IPresenceListener;->cmdStatus(Lcom/android/ims/internal/uce/presence/PresCmdStatus;)V
-Lcom/android/ims/internal/uce/presence/IPresenceListener;->getVersionCb(Ljava/lang/String;)V
-Lcom/android/ims/internal/uce/presence/IPresenceListener;->listCapInfoReceived(Lcom/android/ims/internal/uce/presence/PresRlmiInfo;[Lcom/android/ims/internal/uce/presence/PresResInfo;)V
-Lcom/android/ims/internal/uce/presence/IPresenceListener;->publishTriggering(Lcom/android/ims/internal/uce/presence/PresPublishTriggerType;)V
-Lcom/android/ims/internal/uce/presence/IPresenceListener;->serviceAvailable(Lcom/android/ims/internal/uce/common/StatusCode;)V
-Lcom/android/ims/internal/uce/presence/IPresenceListener;->serviceUnAvailable(Lcom/android/ims/internal/uce/common/StatusCode;)V
-Lcom/android/ims/internal/uce/presence/IPresenceListener;->sipResponseReceived(Lcom/android/ims/internal/uce/presence/PresSipResponse;)V
-Lcom/android/ims/internal/uce/presence/IPresenceListener;->unpublishMessageSent()V
-Lcom/android/ims/internal/uce/presence/IPresenceService$Stub;-><init>()V
-Lcom/android/ims/internal/uce/presence/IPresenceService;->addListener(ILcom/android/ims/internal/uce/presence/IPresenceListener;Lcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/presence/IPresenceService;->getContactCap(ILjava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/presence/IPresenceService;->getContactListCap(I[Ljava/lang/String;I)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/presence/IPresenceService;->getVersion(I)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/presence/IPresenceService;->publishMyCap(ILcom/android/ims/internal/uce/presence/PresCapInfo;I)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/presence/IPresenceService;->reenableService(II)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/presence/IPresenceService;->removeListener(ILcom/android/ims/internal/uce/common/UceLong;)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/presence/IPresenceService;->setNewFeatureTag(ILjava/lang/String;Lcom/android/ims/internal/uce/presence/PresServiceInfo;I)Lcom/android/ims/internal/uce/common/StatusCode;
-Lcom/android/ims/internal/uce/uceservice/IUceListener;->setStatus(I)V
-Lcom/android/ims/internal/uce/uceservice/IUceService$Stub;-><init>()V
-Lcom/android/ims/internal/uce/uceservice/IUceService;->createOptionsService(Lcom/android/ims/internal/uce/options/IOptionsListener;Lcom/android/ims/internal/uce/common/UceLong;)I
-Lcom/android/ims/internal/uce/uceservice/IUceService;->createPresenceService(Lcom/android/ims/internal/uce/presence/IPresenceListener;Lcom/android/ims/internal/uce/common/UceLong;)I
-Lcom/android/ims/internal/uce/uceservice/IUceService;->destroyOptionsService(I)V
-Lcom/android/ims/internal/uce/uceservice/IUceService;->destroyPresenceService(I)V
-Lcom/android/ims/internal/uce/uceservice/IUceService;->getOptionsService()Lcom/android/ims/internal/uce/options/IOptionsService;
-Lcom/android/ims/internal/uce/uceservice/IUceService;->getPresenceService()Lcom/android/ims/internal/uce/presence/IPresenceService;
-Lcom/android/ims/internal/uce/uceservice/IUceService;->getServiceStatus()Z
-Lcom/android/ims/internal/uce/uceservice/IUceService;->isServiceStarted()Z
-Lcom/android/ims/internal/uce/uceservice/IUceService;->startService(Lcom/android/ims/internal/uce/uceservice/IUceListener;)Z
-Lcom/android/ims/internal/uce/uceservice/IUceService;->stopService()Z
-Lcom/android/internal/app/IAppOpsService;->finishOperation(Landroid/os/IBinder;IILjava/lang/String;)V
-Lcom/android/internal/content/PackageMonitor;-><init>()V
-Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider;
-Lcom/android/internal/location/ILocationProvider;->disable()V
-Lcom/android/internal/location/ILocationProvider;->enable()V
-Lcom/android/internal/location/ILocationProvider;->getProperties()Lcom/android/internal/location/ProviderProperties;
-Lcom/android/internal/location/ILocationProvider;->getStatus(Landroid/os/Bundle;)I
-Lcom/android/internal/location/ILocationProvider;->getStatusUpdateTime()J
-Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)Z
-Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V
-Lcom/android/internal/R$styleable;->NumberPicker:[I
-Lcom/android/internal/R$styleable;->TwoLineListItem:[I
-Lcom/android/internal/telephony/ITelephony;->getDataEnabled(I)Z
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 6f0b6c8687db..c7a9d99fe927 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1731,8 +1731,11 @@ class ContextImpl extends Context {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
- IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
- getOuterContext(), conn);
+ IServiceConnection sd = mPackageInfo.lookupServiceDispatcher(conn, getOuterContext());
+ if (sd == null) {
+ throw new IllegalArgumentException("ServiceConnection not currently bound: "
+ + conn);
+ }
try {
ActivityManager.getService().updateServiceGroup(sd, group, importance);
} catch (RemoteException e) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 3f1075448c84..759763b4199a 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -696,6 +696,23 @@ public final class LoadedApk {
return loaders;
}
+ private StrictMode.ThreadPolicy allowThreadDiskReads() {
+ if (mActivityThread == null) {
+ // When LoadedApk is used without an ActivityThread (usually in a
+ // zygote context), don't call into StrictMode, as it initializes
+ // the binder subsystem, which we don't want.
+ return null;
+ }
+
+ return StrictMode.allowThreadDiskReads();
+ }
+
+ private void setThreadPolicy(StrictMode.ThreadPolicy policy) {
+ if (mActivityThread != null && policy != null) {
+ StrictMode.setThreadPolicy(policy);
+ }
+ }
+
private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
if (mPackageName.equals("android")) {
// Note: This branch is taken for system server and we don't need to setup
@@ -718,8 +735,11 @@ public final class LoadedApk {
// Avoid the binder call when the package is the current application package.
// The activity manager will perform ensure that dexopt is performed before
- // spinning up the process.
- if (!Objects.equals(mPackageName, ActivityThread.currentPackageName()) && mIncludeCode) {
+ // spinning up the process. Similarly, don't call into binder when we don't
+ // have an ActivityThread object.
+ if (mActivityThread != null
+ && !Objects.equals(mPackageName, ActivityThread.currentPackageName())
+ && mIncludeCode) {
try {
ActivityThread.getPackageManager().notifyPackageUse(mPackageName,
PackageManager.NOTIFY_PACKAGE_USE_CROSS_PACKAGE);
@@ -790,12 +810,12 @@ public final class LoadedApk {
// mIncludeCode == false).
if (!mIncludeCode) {
if (mDefaultClassLoader == null) {
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoader(
"" /* codePath */, mApplicationInfo.targetSdkVersion, isBundledApp,
librarySearchPath, libraryPermittedPath, mBaseClassLoader,
null /* classLoaderName */);
- StrictMode.setThreadPolicy(oldPolicy);
+ setThreadPolicy(oldPolicy);
mAppComponentFactory = AppComponentFactory.DEFAULT;
}
@@ -822,7 +842,7 @@ public final class LoadedApk {
if (mDefaultClassLoader == null) {
// Temporarily disable logging of disk reads on the Looper thread
// as this is early and necessary.
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders(
mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath,
@@ -834,18 +854,18 @@ public final class LoadedApk {
mApplicationInfo.classLoaderName, sharedLibraries);
mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
- StrictMode.setThreadPolicy(oldPolicy);
+ setThreadPolicy(oldPolicy);
// Setup the class loader paths for profiling.
needToSetupJitProfiles = true;
}
if (!libPaths.isEmpty() && SystemProperties.getBoolean(PROPERTY_NAME_APPEND_NATIVE, true)) {
// Temporarily disable logging of disk reads on the Looper thread as this is necessary
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
try {
ApplicationLoaders.getDefault().addNative(mDefaultClassLoader, libPaths);
} finally {
- StrictMode.setThreadPolicy(oldPolicy);
+ setThreadPolicy(oldPolicy);
}
}
@@ -879,11 +899,11 @@ public final class LoadedApk {
extraLibPaths.add("/product/lib" + abiSuffix);
}
if (!extraLibPaths.isEmpty()) {
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
try {
ApplicationLoaders.getDefault().addNative(mDefaultClassLoader, extraLibPaths);
} finally {
- StrictMode.setThreadPolicy(oldPolicy);
+ setThreadPolicy(oldPolicy);
}
}
@@ -1639,6 +1659,19 @@ public final class LoadedApk {
}
}
+ @UnsupportedAppUsage
+ public IServiceConnection lookupServiceDispatcher(ServiceConnection c,
+ Context context) {
+ synchronized (mServices) {
+ LoadedApk.ServiceDispatcher sd = null;
+ ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
+ if (map != null) {
+ sd = map.get(c);
+ }
+ return sd != null ? sd.getIServiceConnection() : null;
+ }
+ }
+
public final IServiceConnection forgetServiceDispatcher(Context context,
ServiceConnection c) {
synchronized (mServices) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0281e6a0631e..aa1b5af9b112 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8263,7 +8263,7 @@ public class Notification implements Parcelable
customContent = customContent.clone();
remoteViews.removeAllViewsExceptId(R.id.notification_main_column, R.id.progress);
remoteViews.addView(R.id.notification_main_column, customContent, 0 /* index */);
- remoteViews.setReapplyDisallowed();
+ remoteViews.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED);
}
// also update the end margin if there is an image
Resources resources = mBuilder.mContext.getResources();
@@ -8394,7 +8394,7 @@ public class Notification implements Parcelable
customContent.overrideTextColors(mBuilder.getPrimaryTextColor(mBuilder.mParams));
remoteViews.removeAllViews(id);
remoteViews.addView(id, customContent);
- remoteViews.setReapplyDisallowed();
+ remoteViews.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED);
}
return remoteViews;
}
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 32fc0dcebbc8..9dcd1228522b 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -119,6 +119,7 @@ public final class StatsManager {
/**
* @deprecated Use {@link #addConfig(long, byte[])}
*/
+ @Deprecated
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean addConfiguration(long configKey, byte[] config) {
try {
@@ -154,6 +155,7 @@ public final class StatsManager {
/**
* @deprecated Use {@link #removeConfig(long)}
*/
+ @Deprecated
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean removeConfiguration(long configKey) {
try {
@@ -222,6 +224,7 @@ public final class StatsManager {
/**
* @deprecated Use {@link #setBroadcastSubscriber(PendingIntent, long, long)}
*/
+ @Deprecated
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean setBroadcastSubscriber(
long configKey, long subscriberId, PendingIntent pendingIntent) {
@@ -275,6 +278,7 @@ public final class StatsManager {
/**
* @deprecated Use {@link #setFetchReportsOperation(PendingIntent, long)}
*/
+ @Deprecated
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public boolean setDataFetchOperation(long configKey, PendingIntent pendingIntent) {
try {
@@ -312,6 +316,7 @@ public final class StatsManager {
/**
* @deprecated Use {@link #getReports(long)}
*/
+ @Deprecated
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public @Nullable byte[] getData(long configKey) {
try {
@@ -348,6 +353,7 @@ public final class StatsManager {
/**
* @deprecated Use {@link #getStatsMetadata()}
*/
+ @Deprecated
@RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
public @Nullable byte[] getMetadata() {
try {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index dfe371c3248e..0404e80df9e2 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -59,6 +59,7 @@ import android.hardware.SystemSensorManager;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.IBiometricService;
import android.hardware.camera2.CameraManager;
+import android.hardware.display.ColorDisplayManager;
import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
import android.hardware.face.IFaceService;
@@ -386,6 +387,14 @@ final class SystemServiceRegistry {
return new DisplayManager(ctx.getOuterContext());
}});
+ registerService(Context.COLOR_DISPLAY_SERVICE, ColorDisplayManager.class,
+ new CachedServiceFetcher<ColorDisplayManager>() {
+ @Override
+ public ColorDisplayManager createService(ContextImpl ctx) {
+ return new ColorDisplayManager();
+ }
+ });
+
// InputMethodManager has its own cache strategy based on display id to support apps that
// still assume InputMethodManager is a per-process singleton and it's safe to directly
// access internal fields via reflection. Hence directly use ServiceFetcher instead of
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 78b7d48165ec..257122d3abe0 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -75,6 +75,9 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
/** The current windowing mode of the configuration. */
private @WindowingMode int mWindowingMode;
+ /** The display windowing mode of the configuration */
+ private @WindowingMode int mDisplayWindowingMode;
+
/** Windowing mode is currently not defined. */
public static final int WINDOWING_MODE_UNDEFINED = 0;
/** Occupies the full area of the screen or the parent container. */
@@ -176,6 +179,10 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
/** Bit that indicates that the {@link #mRotation} changed.
* @hide */
public static final int WINDOW_CONFIG_ROTATION = 1 << 5;
+ /** Bit that indicates that the {@link #mDisplayWindowingMode} changed.
+ * @hide */
+ public static final int WINDOW_CONFIG_DISPLAY_WINDOWING_MODE = 1 << 6;
+
/** @hide */
@IntDef(flag = true, prefix = { "WINDOW_CONFIG_" }, value = {
WINDOW_CONFIG_BOUNDS,
@@ -184,6 +191,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
WINDOW_CONFIG_ACTIVITY_TYPE,
WINDOW_CONFIG_ALWAYS_ON_TOP,
WINDOW_CONFIG_ROTATION,
+ WINDOW_CONFIG_DISPLAY_WINDOWING_MODE,
})
public @interface WindowConfig {}
@@ -211,6 +219,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
dest.writeInt(mActivityType);
dest.writeInt(mAlwaysOnTop);
dest.writeInt(mRotation);
+ dest.writeInt(mDisplayWindowingMode);
}
private void readFromParcel(Parcel source) {
@@ -220,6 +229,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
mActivityType = source.readInt();
mAlwaysOnTop = source.readInt();
mRotation = source.readInt();
+ mDisplayWindowingMode = source.readInt();
}
@Override
@@ -322,6 +332,12 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
return mWindowingMode;
}
+ /** @hide */
+ public void setDisplayWindowingMode(@WindowingMode int windowingMode) {
+ mDisplayWindowingMode = windowingMode;
+ }
+
+
public void setActivityType(@ActivityType int activityType) {
if (mActivityType == activityType) {
return;
@@ -351,6 +367,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
setActivityType(other.mActivityType);
setAlwaysOnTop(other.mAlwaysOnTop);
setRotation(other.mRotation);
+ setDisplayWindowingMode(other.mDisplayWindowingMode);
}
/** Set this object to completely undefined.
@@ -367,6 +384,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
setActivityType(ACTIVITY_TYPE_UNDEFINED);
setAlwaysOnTop(ALWAYS_ON_TOP_UNDEFINED);
setRotation(ROTATION_UNDEFINED);
+ setDisplayWindowingMode(WINDOWING_MODE_UNDEFINED);
}
/**
@@ -407,6 +425,11 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
changed |= WINDOW_CONFIG_ROTATION;
setRotation(delta.mRotation);
}
+ if (delta.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED
+ && mDisplayWindowingMode != delta.mDisplayWindowingMode) {
+ changed |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE;
+ setDisplayWindowingMode(delta.mDisplayWindowingMode);
+ }
return changed;
}
@@ -455,6 +478,11 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
changes |= WINDOW_CONFIG_ROTATION;
}
+ if ((compareUndefined || other.mDisplayWindowingMode != WINDOWING_MODE_UNDEFINED)
+ && mDisplayWindowingMode != other.mDisplayWindowingMode) {
+ changes |= WINDOW_CONFIG_DISPLAY_WINDOWING_MODE;
+ }
+
return changes;
}
@@ -493,6 +521,8 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
if (n != 0) return n;
n = mRotation - that.mRotation;
if (n != 0) return n;
+ n = mDisplayWindowingMode - that.mDisplayWindowingMode;
+ if (n != 0) return n;
// if (n != 0) return n;
return n;
@@ -522,6 +552,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
result = 31 * result + mActivityType;
result = 31 * result + mAlwaysOnTop;
result = 31 * result + mRotation;
+ result = 31 * result + mDisplayWindowingMode;
return result;
}
@@ -531,6 +562,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
return "{ mBounds=" + mBounds
+ " mAppBounds=" + mAppBounds
+ " mWindowingMode=" + windowingModeToString(mWindowingMode)
+ + " mDisplayWindowingMode=" + windowingModeToString(mDisplayWindowingMode)
+ " mActivityType=" + activityTypeToString(mActivityType)
+ " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop)
+ " mRotation=" + (mRotation == ROTATION_UNDEFINED
@@ -603,7 +635,8 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
* @hide
*/
public boolean hasWindowDecorCaption() {
- return mWindowingMode == WINDOWING_MODE_FREEFORM;
+ return mActivityType == ACTIVITY_TYPE_STANDARD && (mWindowingMode == WINDOWING_MODE_FREEFORM
+ || mDisplayWindowingMode == WINDOWING_MODE_FREEFORM);
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 98d2a406fc0c..3a9728413151 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -10092,11 +10092,40 @@ public class DevicePolicyManager {
if (mService != null) {
try {
return mService.isPackageAllowedToAccessCalendarForUser(packageName,
- mContext.getUserId());
+ myUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return false;
}
+
+ /**
+ * Gets a set of package names that are whitelisted to access cross profile calendar APIs.
+ *
+ * <p>To query for a specific user, use
+ * {@link Context#createPackageContextAsUser(String, int, UserHandle)} to create a context for
+ * that user, and get a {@link DevicePolicyManager} from this context.
+ *
+ * @return the set of names of packages that were previously whitelisted via
+ * {@link #addCrossProfileCalendarPackage(ComponentName, String)}, or an
+ * empty set if none have been whitelisted.
+ *
+ * @see #addCrossProfileCalendarPackage(ComponentName, String)
+ * @see #removeCrossProfileCalendarPackage(ComponentName, String)
+ * @see #getCrossProfileCalendarPackages(ComponentName)
+ * @hide
+ */
+ public @NonNull Set<String> getCrossProfileCalendarPackages() {
+ throwIfParentInstance("getCrossProfileCalendarPackages");
+ if (mService != null) {
+ try {
+ return new ArraySet<>(mService.getCrossProfileCalendarPackagesForUser(
+ myUserId()));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return Collections.emptySet();
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 297676d397bf..fcf74ee301d8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -427,4 +427,5 @@ interface IDevicePolicyManager {
boolean removeCrossProfileCalendarPackage(in ComponentName admin, String packageName);
List<String> getCrossProfileCalendarPackages(in ComponentName admin);
boolean isPackageAllowedToAccessCalendarForUser(String packageName, int userHandle);
+ List<String> getCrossProfileCalendarPackagesForUser(int userHandle);
}
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 318dbee99e5a..c740c42c9c0d 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -88,6 +88,7 @@ public class AppWidgetHostView extends FrameLayout {
int mViewMode = VIEW_MODE_NOINIT;
int mLayoutId = -1;
private OnClickHandler mOnClickHandler;
+ private boolean mOnLightBackground;
private Executor mAsyncExecutor;
private CancellationSignal mLastExecutionSignal;
@@ -374,6 +375,15 @@ public class AppWidgetHostView extends FrameLayout {
}
/**
+ * Sets whether the widget should is being displayed on a light/white background and use an
+ * alternate UI if available.
+ * @see RemoteViews#setLightBackgroundLayoutId(int)
+ */
+ public void setOnLightBackground(boolean useDarkTextLayout) {
+ mOnLightBackground = useDarkTextLayout;
+ }
+
+ /**
* Update the AppWidgetProviderInfo for this view, and reset it to the
* initial layout.
*/
@@ -413,6 +423,10 @@ public class AppWidgetHostView extends FrameLayout {
mLayoutId = -1;
mViewMode = VIEW_MODE_DEFAULT;
} else {
+ if (mOnLightBackground) {
+ remoteViews = remoteViews.getDarkTextViews();
+ }
+
if (mAsyncExecutor != null && useAsyncIfPossible) {
inflateAsync(remoteViews);
return;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 145c92731458..d1017c59b963 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -51,6 +51,7 @@ import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -586,7 +587,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
private int noteProxyOp(String callingPkg, int op) {
if (op != AppOpsManager.OP_NONE) {
int mode = mAppOpsManager.noteProxyOp(op, callingPkg);
- return mode == MODE_DEFAULT ? interpretDefaultAppOpMode(op) : mode;
+ int nonDefaultMode = mode == MODE_DEFAULT ? interpretDefaultAppOpMode(op) : mode;
+ if (mode == MODE_DEFAULT && nonDefaultMode == MODE_IGNORED) {
+ Slog.w(TAG, "Denying access for " + callingPkg + " to " + getClass().getName()
+ + " (" + AppOpsManager.opToName(op)
+ + " = " + AppOpsManager.opToName(mode) + ")");
+ }
+ return mode == MODE_DEFAULT ? nonDefaultMode : mode;
}
return AppOpsManager.MODE_ALLOWED;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 68aac642ecb0..e2c7b85b3280 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3003,6 +3003,11 @@ public abstract class Context {
* how the process will be managed in some cases based on those flags. Currently only
* works on isolated processes (will be ignored for non-isolated processes).
*
+ * <p>Note that this call does not take immediate effect, but will be applied the next
+ * time the impacted process is adjusted for some other reason. Typically you would
+ * call this before then calling a new {@link #bindIsolatedService} on the service
+ * of interest, with that binding causing the process to be shuffled accordingly.</p>
+ *
* @param conn The connection interface previously supplied to bindService(). This
* parameter must not be null.
* @param group A group to put this connection's process in. Upon calling here, this
@@ -3126,6 +3131,7 @@ public abstract class Context {
//@hide: HDMI_CONTROL_SERVICE,
INPUT_SERVICE,
DISPLAY_SERVICE,
+ //@hide COLOR_DISPLAY_SERVICE,
USER_SERVICE,
RESTRICTIONS_SERVICE,
APP_OPS_SERVICE,
@@ -4108,6 +4114,16 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.hardware.display.ColorDisplayManager} for controlling color transforms.
+ *
+ * @see #getSystemService(String)
+ * @see android.hardware.display.ColorDisplayManager
+ * @hide
+ */
+ public static final String COLOR_DISPLAY_SERVICE = "color_display";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.os.UserManager} for managing users on devices that support multiple users.
*
* @see #getSystemService(String)
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index edfb3a72e933..c2907d2ccc1b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1916,12 +1916,15 @@ public class Intent implements Parcelable, Cloneable {
/**
* Activity action: Launch UI to review app uses of permissions.
* <p>
- * Input: Nothing
+ * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission name
+ * that will be displayed by the launched UI.
* </p>
* <p>
* Output: Nothing.
* </p>
*
+ * @see #EXTRA_PERMISSION_NAME
+ *
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 98a135f96d98..07d6e4785759 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1303,7 +1303,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/** {@hide} */
public void writeToProto(ProtoOutputStream proto, long fieldId, int dumpFlags) {
long token = proto.start(fieldId);
- super.writeToProto(proto, ApplicationInfoProto.PACKAGE);
+ super.writeToProto(proto, ApplicationInfoProto.PACKAGE, dumpFlags);
proto.write(ApplicationInfoProto.PERMISSION, permission);
proto.write(ApplicationInfoProto.PROCESS_NAME, processName);
proto.write(ApplicationInfoProto.UID, uid);
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index cdb781438909..ff7b34773268 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -433,18 +433,18 @@ public class PackageItemInfo {
/**
* @hide
*/
- public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ public void writeToProto(ProtoOutputStream proto, long fieldId, int dumpFlags) {
long token = proto.start(fieldId);
if (name != null) {
proto.write(PackageItemInfoProto.NAME, name);
}
proto.write(PackageItemInfoProto.PACKAGE_NAME, packageName);
- if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) {
- proto.write(PackageItemInfoProto.LABEL_RES, labelRes);
+ proto.write(PackageItemInfoProto.LABEL_RES, labelRes);
+ if (nonLocalizedLabel != null) {
proto.write(PackageItemInfoProto.NON_LOCALIZED_LABEL, nonLocalizedLabel.toString());
- proto.write(PackageItemInfoProto.ICON, icon);
- proto.write(PackageItemInfoProto.BANNER, banner);
}
+ proto.write(PackageItemInfoProto.ICON, icon);
+ proto.write(PackageItemInfoProto.BANNER, banner);
proto.end(token);
}
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
index 79bc9a30b1e2..73addb70ea05 100644
--- a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
+++ b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
@@ -16,13 +16,15 @@
package android.content.pm.permission;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -32,7 +34,7 @@ import android.permissionpresenterservice.RuntimePermissionPresenterService;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.os.SomeArgs;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.util.ArrayList;
import java.util.Collections;
@@ -109,13 +111,11 @@ public final class RuntimePermissionPresenter {
*/
public void getAppPermissions(@NonNull String packageName,
@NonNull OnResultCallback callback, @Nullable Handler handler) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = packageName;
- args.arg2 = callback;
- args.arg3 = handler;
- Message message = mRemoteService.obtainMessage(
- RemoteService.MSG_GET_APP_PERMISSIONS, args);
- mRemoteService.processMessage(message);
+ checkNotNull(packageName);
+ checkNotNull(callback);
+
+ mRemoteService.processMessage(obtainMessage(RemoteService::getAppPermissions,
+ mRemoteService, packageName, callback, handler));
}
/**
@@ -124,24 +124,20 @@ public final class RuntimePermissionPresenter {
* @param packageName The package for which to revoke
* @param permissionName The permission to revoke
*/
- public void revokeRuntimePermission(String packageName, String permissionName) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = packageName;
- args.arg2 = permissionName;
-
- Message message = mRemoteService.obtainMessage(
- RemoteService.MSG_REVOKE_APP_PERMISSIONS, args);
- mRemoteService.processMessage(message);
+ public void revokeRuntimePermission(@NonNull String packageName,
+ @NonNull String permissionName) {
+ checkNotNull(packageName);
+ checkNotNull(permissionName);
+
+ mRemoteService.processMessage(obtainMessage(RemoteService::revokeAppPermissions,
+ mRemoteService, packageName, permissionName));
}
private static final class RemoteService
extends Handler implements ServiceConnection {
private static final long UNBIND_TIMEOUT_MILLIS = 10000;
- public static final int MSG_GET_APP_PERMISSIONS = 1;
- public static final int MSG_GET_APPS_USING_PERMISSIONS = 2;
- public static final int MSG_UNBIND = 3;
- public static final int MSG_REVOKE_APP_PERMISSIONS = 4;
+ public static final int MSG_UNBIND = 0;
private final Object mLock = new Object();
@@ -191,89 +187,74 @@ public final class RuntimePermissionPresenter {
}
}
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_GET_APP_PERMISSIONS: {
- SomeArgs args = (SomeArgs) msg.obj;
- final String packageName = (String) args.arg1;
- final OnResultCallback callback = (OnResultCallback) args.arg2;
- final Handler handler = (Handler) args.arg3;
- args.recycle();
- final IRuntimePermissionPresenter remoteInstance;
- synchronized (mLock) {
- remoteInstance = mRemoteInstance;
- }
- if (remoteInstance == null) {
- return;
- }
- try {
- remoteInstance.getAppPermissions(packageName,
- new RemoteCallback(new RemoteCallback.OnResultListener() {
- @Override
- public void onResult(Bundle result) {
- final List<RuntimePermissionPresentationInfo> reportedPermissions;
- List<RuntimePermissionPresentationInfo> permissions = null;
- if (result != null) {
- permissions = result.getParcelableArrayList(KEY_RESULT);
- }
- if (permissions == null) {
- permissions = Collections.emptyList();
- }
- reportedPermissions = permissions;
- if (handler != null) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- callback.onGetAppPermissions(reportedPermissions);
- }
- });
- } else {
- callback.onGetAppPermissions(reportedPermissions);
- }
+ private void getAppPermissions(@NonNull String packageName,
+ @NonNull OnResultCallback callback, @Nullable Handler handler) {
+ final IRuntimePermissionPresenter remoteInstance;
+ synchronized (mLock) {
+ remoteInstance = mRemoteInstance;
+ }
+ if (remoteInstance == null) {
+ return;
+ }
+ try {
+ remoteInstance.getAppPermissions(packageName,
+ new RemoteCallback(result -> {
+ final List<RuntimePermissionPresentationInfo> reportedPermissions;
+ List<RuntimePermissionPresentationInfo> permissions = null;
+ if (result != null) {
+ permissions = result.getParcelableArrayList(KEY_RESULT);
+ }
+ if (permissions == null) {
+ permissions = Collections.emptyList();
+ }
+ reportedPermissions = permissions;
+ if (handler != null) {
+ handler.post(
+ () -> callback.onGetAppPermissions(reportedPermissions));
+ } else {
+ callback.onGetAppPermissions(reportedPermissions);
}
}, this));
- } catch (RemoteException re) {
- Log.e(TAG, "Error getting app permissions", re);
- }
- scheduleUnbind();
- } break;
-
- case MSG_UNBIND: {
- synchronized (mLock) {
- if (mBound) {
- mContext.unbindService(this);
- mBound = false;
- }
- mRemoteInstance = null;
- }
- } break;
-
- case MSG_REVOKE_APP_PERMISSIONS: {
- SomeArgs args = (SomeArgs) msg.obj;
- final String packageName = (String) args.arg1;
- final String permissionName = (String) args.arg2;
- args.recycle();
- final IRuntimePermissionPresenter remoteInstance;
- synchronized (mLock) {
- remoteInstance = mRemoteInstance;
- }
- if (remoteInstance == null) {
- return;
- }
- try {
- remoteInstance.revokeRuntimePermission(packageName, permissionName);
- } catch (RemoteException re) {
- Log.e(TAG, "Error getting app permissions", re);
- }
- } break;
+ } catch (RemoteException re) {
+ Log.e(TAG, "Error getting app permissions", re);
}
+ scheduleUnbind();
synchronized (mLock) {
scheduleNextMessageIfNeededLocked();
}
}
+ private void revokeAppPermissions(@NonNull String packageName,
+ @NonNull String permissionName) {
+ final IRuntimePermissionPresenter remoteInstance;
+ synchronized (mLock) {
+ remoteInstance = mRemoteInstance;
+ }
+ if (remoteInstance == null) {
+ return;
+ }
+ try {
+ remoteInstance.revokeRuntimePermission(packageName, permissionName);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Error getting app permissions", re);
+ }
+
+ synchronized (mLock) {
+ scheduleNextMessageIfNeededLocked();
+ }
+ }
+
+ private void unbind() {
+ synchronized (mLock) {
+ if (mBound) {
+ mContext.unbindService(this);
+ mBound = false;
+ }
+ mRemoteInstance = null;
+ }
+ }
+
@GuardedBy("mLock")
private void scheduleNextMessageIfNeededLocked() {
if (mBound && mRemoteInstance != null && !mPendingWork.isEmpty()) {
@@ -284,7 +265,8 @@ public final class RuntimePermissionPresenter {
private void scheduleUnbind() {
removeMessages(MSG_UNBIND);
- sendEmptyMessageDelayed(MSG_UNBIND, UNBIND_TIMEOUT_MILLIS);
+ sendMessageDelayed(PooledLambda.obtainMessage(RemoteService::unbind, this)
+ .setWhat(MSG_UNBIND), UNBIND_TIMEOUT_MILLIS);
}
}
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 7148b124253e..5e402c7edc40 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -393,7 +393,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* doesn't have any recommendation for this use case or the recommended configurations
* are invalid.
*/
- public RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(
+ public @Nullable RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(
@RecommendedStreamConfigurationMap.RecommendedUsecase int usecase) {
if (((usecase >= RecommendedStreamConfigurationMap.USECASE_PREVIEW) &&
(usecase <= RecommendedStreamConfigurationMap.USECASE_RAW)) ||
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index dc6cffc4ebee..448591f2c52a 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -968,6 +968,36 @@ public abstract class CameraDevice implements AutoCloseable {
public abstract void close();
/**
+ * Checks whether a particular {@link SessionConfiguration} is supported by the camera device.
+ *
+ * <p>This method performs a runtime check of a given {@link SessionConfiguration}. The result
+ * confirms whether or not the passed session configuration can be successfully used to
+ * create a camera capture session using
+ * {@link CameraDevice#createCaptureSession(SessionConfiguration)}.
+ * </p>
+ *
+ * <p>The method can be called at any point before, during and after active capture session.
+ * It must not impact normal camera behavior in any way and must complete significantly
+ * faster than creating a regular or constrained capture session.</p>
+ *
+ * <p>Note that session parameters will be ignored and calls to
+ * {@link SessionConfiguration#setSessionParameters} are not required.</p>
+ *
+ * @return {@code true} if the given session configuration is supported by the camera device
+ * {@code false} otherwise.
+ * @throws UnsupportedOperationException if the query operation is not supported by the camera
+ * device
+ * @throws IllegalArgumentException if the session configuration is invalid
+ * @throws CameraAccessException if the camera device is no longer connected or has
+ * encountered a fatal error
+ * @throws IllegalStateException if the camera device has been closed
+ */
+ public boolean isSessionConfigurationSupported(
+ @NonNull SessionConfiguration sessionConfig) throws CameraAccessException {
+ throw new UnsupportedOperationException("Subclasses must override this method");
+ }
+
+ /**
* A callback objects for receiving updates about the state of a camera device.
*
* <p>A callback instance must be provided to the {@link CameraManager#openCamera} method to
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 7810e6c19abe..57b608f0fd84 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -703,6 +703,17 @@ public class CameraDeviceImpl extends CameraDevice
}
}
+ @Override
+ public boolean isSessionConfigurationSupported(
+ @NonNull SessionConfiguration sessionConfig) throws CameraAccessException,
+ UnsupportedOperationException, IllegalArgumentException {
+ synchronized(mInterfaceLock) {
+ checkIfCameraClosedOrInError();
+
+ return mRemoteDevice.isSessionConfigurationSupported(sessionConfig);
+ }
+ }
+
/**
* For use by backwards-compatibility code only.
*/
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
index 1f4ed13ee09e..c8ded8dde54a 100644
--- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -30,9 +30,11 @@ import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.utils.SubmitInfo;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.view.Surface;
/**
@@ -181,6 +183,25 @@ public class ICameraDeviceUserWrapper {
}
}
+ public boolean isSessionConfigurationSupported(SessionConfiguration sessionConfig)
+ throws CameraAccessException {
+ try {
+ return mRemoteDevice.isSessionConfigurationSupported(sessionConfig);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
+ throw new UnsupportedOperationException("Session configuration query not " +
+ "supported");
+ } else if (e.errorCode == ICameraService.ERROR_ILLEGAL_ARGUMENT) {
+ throw new IllegalArgumentException("Invalid session configuration");
+ }
+
+ throw e;
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
+
public long flush() throws CameraAccessException {
try {
return mRemoteDevice.flush();
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index bc7b1260751e..123eb8ee1431 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -28,6 +28,7 @@ import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.utils.SubmitInfo;
import android.os.ConditionVariable;
import android.os.IBinder;
@@ -480,6 +481,12 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
@Override
+ public boolean isSessionConfigurationSupported(SessionConfiguration sessionConfig) {
+ // TODO: Add support for this in legacy mode
+ throw new UnsupportedOperationException("Session configuration query not supported!");
+ }
+
+ @Override
public void beginConfigure() {
if (DEBUG) {
Log.d(TAG, "beginConfigure called.");
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index 83a02285e720..1b28d614a7f2 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -521,9 +521,10 @@ public class SurfaceTextureRenderer {
clearState();
}
- private void makeCurrent(EGLSurface surface) {
+ private void makeCurrent(EGLSurface surface)
+ throws LegacyExceptionUtils.BufferQueueAbandonedException {
EGL14.eglMakeCurrent(mEGLDisplay, surface, surface, mEGLContext);
- checkEglError("makeCurrent");
+ checkEglDrawError("makeCurrent");
}
private boolean swapBuffers(EGLSurface surface)
@@ -557,6 +558,17 @@ public class SurfaceTextureRenderer {
}
}
+ private void checkEglDrawError(String msg)
+ throws LegacyExceptionUtils.BufferQueueAbandonedException {
+ int error;
+ if ((error = EGL14.eglGetError()) == EGL14.EGL_BAD_NATIVE_WINDOW) {
+ throw new LegacyExceptionUtils.BufferQueueAbandonedException();
+ }
+ if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
+ throw new IllegalStateException(msg + ": EGL error: 0x" + Integer.toHexString(error));
+ }
+ }
+
private void checkEglError(String msg) {
int error;
if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
@@ -709,8 +721,14 @@ public class SurfaceTextureRenderer {
if (mConversionSurfaces.size() > 0) {
configureEGLPbufferSurfaces(mConversionSurfaces);
}
- makeCurrent((mSurfaces.size() > 0) ? mSurfaces.get(0).eglSurface :
+
+ try {
+ makeCurrent((mSurfaces.size() > 0) ? mSurfaces.get(0).eglSurface :
mConversionSurfaces.get(0).eglSurface);
+ } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+ Log.w(TAG, "Surface abandoned, skipping configuration... ", e);
+ }
+
initializeGLState();
mSurfaceTexture = new SurfaceTexture(getTextureId());
@@ -798,9 +816,9 @@ public class SurfaceTextureRenderer {
}
for (EGLSurfaceHolder holder : mConversionSurfaces) {
if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
- makeCurrent(holder.eglSurface);
// glReadPixels reads from the bottom of the buffer, so add an extra vertical flip
try {
+ makeCurrent(holder.eglSurface);
drawFrame(mSurfaceTexture, holder.width, holder.height,
(mFacing == CameraCharacteristics.LENS_FACING_FRONT) ?
FLIP_TYPE_BOTH : FLIP_TYPE_VERTICAL);
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
index 59e4a3366995..068c0ce8d052 100644
--- a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
@@ -17,6 +17,7 @@
package android.hardware.camera2.params;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.ImageFormat;
@@ -173,7 +174,7 @@ public final class RecommendedStreamConfigurationMap {
*
* @return Use case id.
*/
- public int getRecommendedUseCase() {
+ public @RecommendedUsecase int getRecommendedUseCase() {
return mUsecase;
}
@@ -326,7 +327,7 @@ public final class RecommendedStreamConfigurationMap {
* @throws IllegalArgumentException if input size does not exist in the return value of
* getHighSpeedVideoSizes
*/
- public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRangesFor(Size size) {
+ public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRangesFor(@NonNull Size size) {
return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRangesFor(size));
}
@@ -349,14 +350,14 @@ public final class RecommendedStreamConfigurationMap {
* For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizesFor}.
* </p>
*
- * @param fpsRange one of the FPS range returned by {@link #getHighSpeedVideoFpsRanges()}
+ * @param fpsRange one of the FPS ranges returned by {@link #getHighSpeedVideoFpsRanges()}
* @return A non-modifiable set of video sizes to create high speed capture sessions for high
* speed streaming use cases.
*
* @throws IllegalArgumentException if input FPS range does not exist in the return value of
* getHighSpeedVideoFpsRanges
*/
- public @Nullable Set<Size> getHighSpeedVideoSizesFor(Range<Integer> fpsRange) {
+ public @Nullable Set<Size> getHighSpeedVideoSizesFor(@NonNull Range<Integer> fpsRange) {
return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizesFor(fpsRange));
}
@@ -390,10 +391,8 @@ public final class RecommendedStreamConfigurationMap {
* 0 if the minimum frame duration is not available.
*
* @throws IllegalArgumentException if {@code format} or {@code size} was not supported
- * @throws NullPointerException if {@code size} was {@code null}
- *
*/
- public long getOutputMinFrameDuration(int format, Size size) {
+ public @IntRange(from = 0) long getOutputMinFrameDuration(int format, @NonNull Size size) {
return mRecommendedMap.getOutputMinFrameDuration(format, size);
}
@@ -409,9 +408,8 @@ public final class RecommendedStreamConfigurationMap {
* @return a stall duration {@code >=} 0 in nanoseconds
*
* @throws IllegalArgumentException if {@code format} or {@code size} was not supported
- * @throws NullPointerException if {@code size} was {@code null}
*/
- public long getOutputStallDuration(int format, Size size) {
+ public @IntRange(from = 0) long getOutputStallDuration(int format, @NonNull Size size) {
return mRecommendedMap.getOutputStallDuration(format, size);
}
@@ -422,16 +420,12 @@ public final class RecommendedStreamConfigurationMap {
* </p>
*
* @param klass
- * a non-{@code null} {@link Class} object reference
+ * a {@link Class} object reference
* @return
* a non-modifiable set of supported sizes for {@link ImageFormat#PRIVATE} format,
* or {@code null} if the {@code klass} is not a supported output.
- *
- *
- * @throws NullPointerException if {@code klass} was {@code null}
- *
*/
- public <T> @Nullable Set<Size> getOutputSizes(Class<T> klass) {
+ public <T> @Nullable Set<Size> getOutputSizes(@NonNull Class<T> klass) {
if (mSupportsPrivate) {
return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(klass));
}
@@ -447,16 +441,15 @@ public final class RecommendedStreamConfigurationMap {
* {@link StreamConfigurationMap#getOutputMinFrameDuration(Class, Size)}.</p>
*
* @param klass
- * a class which has a non-empty array returned by {@link #getOutputSizes(Class)}
+ * a class which has a non-empty array returned by {@link #getOutputSizes(Class)}
* @param size an output-compatible size
* @return a minimum frame duration {@code >} 0 in nanoseconds, or
* 0 if the minimum frame duration is not available.
*
* @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
- * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
- *
*/
- public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
+ public <T> @IntRange(from = 0) long getOutputMinFrameDuration(@NonNull final Class<T> klass,
+ @NonNull final Size size) {
if (mSupportsPrivate) {
return mRecommendedMap.getOutputMinFrameDuration(klass, size);
}
@@ -473,14 +466,13 @@ public final class RecommendedStreamConfigurationMap {
* @param klass
* a class which has a non-empty array returned by {@link #getOutputSizes(Class)}.
* @param size an output-compatible size
- * @return a minimum frame duration {@code >=} 0 in nanoseconds, or 0 if the stall duration is
+ * @return a minimum frame duration {@code >} 0 in nanoseconds, or 0 if the stall duration is
* not available.
*
* @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
- * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
- *
*/
- public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
+ public <T> @IntRange(from = 0) long getOutputStallDuration(@NonNull final Class<T> klass,
+ @NonNull final Size size) {
if (mSupportsPrivate) {
return mRecommendedMap.getOutputStallDuration(klass, size);
}
@@ -495,14 +487,13 @@ public final class RecommendedStreamConfigurationMap {
* <p>For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
* </p>
*
- * @param surface a non-{@code null} {@link Surface} object reference
+ * @param surface a {@link Surface} object reference
* @return {@code true} if this is supported, {@code false} otherwise
*
- * @throws NullPointerException if {@code surface} was {@code null}
* @throws IllegalArgumentException if the Surface endpoint is no longer valid
*
*/
- public boolean isOutputSupportedFor(Surface surface) {
+ public boolean isOutputSupportedFor(@NonNull Surface surface) {
return mRecommendedMap.isOutputSupportedFor(surface);
}
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index 8a8afb24b3f8..3ea58ad83327 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -27,6 +27,10 @@ import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.InputConfiguration;
import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.utils.HashCodeHelpers;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
import java.util.Collections;
import java.util.List;
@@ -40,7 +44,9 @@ import static com.android.internal.util.Preconditions.*;
/**
* A helper class that aggregates all supported arguments for capture session initialization.
*/
-public final class SessionConfiguration {
+public final class SessionConfiguration implements Parcelable {
+ private static final String TAG = "SessionConfiguration";
+
/**
* A regular session type containing instances of {@link OutputConfiguration} running
* at regular non high speed FPS ranges and optionally {@link InputConfiguration} for
@@ -110,6 +116,108 @@ public final class SessionConfiguration {
}
/**
+ * Create a SessionConfiguration from Parcel.
+ * No support for parcelable 'mStateCallback', 'mExecutor' and 'mSessionParameters' yet.
+ */
+ private SessionConfiguration(@NonNull Parcel source) {
+ int sessionType = source.readInt();
+ int inputWidth = source.readInt();
+ int inputHeight = source.readInt();
+ int inputFormat = source.readInt();
+ ArrayList<OutputConfiguration> outConfigs = new ArrayList<OutputConfiguration>();
+ source.readTypedList(outConfigs, OutputConfiguration.CREATOR);
+
+ if ((inputWidth > 0) && (inputHeight > 0) && (inputFormat != -1)) {
+ mInputConfig = new InputConfiguration(inputWidth, inputHeight, inputFormat);
+ }
+ mSessionType = sessionType;
+ mOutputConfigurations = outConfigs;
+ }
+
+ public static final Parcelable.Creator<SessionConfiguration> CREATOR =
+ new Parcelable.Creator<SessionConfiguration> () {
+ @Override
+ public SessionConfiguration createFromParcel(Parcel source) {
+ try {
+ SessionConfiguration sessionConfiguration = new SessionConfiguration(source);
+ return sessionConfiguration;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating SessionConfiguration from parcel", e);
+ return null;
+ }
+ }
+
+ @Override
+ public SessionConfiguration[] newArray(int size) {
+ return new SessionConfiguration[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (dest == null) {
+ throw new IllegalArgumentException("dest must not be null");
+ }
+ dest.writeInt(mSessionType);
+ if (mInputConfig != null) {
+ dest.writeInt(mInputConfig.getWidth());
+ dest.writeInt(mInputConfig.getHeight());
+ dest.writeInt(mInputConfig.getFormat());
+ } else {
+ dest.writeInt(/*inputWidth*/ 0);
+ dest.writeInt(/*inputHeight*/ 0);
+ dest.writeInt(/*inputFormat*/ -1);
+ }
+ dest.writeTypedList(mOutputConfigurations);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Check if this {@link SessionConfiguration} is equal to another {@link SessionConfiguration}.
+ *
+ * <p>Two output session configurations are only equal if and only if the underlying input
+ * configuration, output configurations, and session type are equal. </p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ } else if (this == obj) {
+ return true;
+ } else if (obj instanceof SessionConfiguration) {
+ final SessionConfiguration other = (SessionConfiguration) obj;
+ if (mInputConfig != other.mInputConfig || mSessionType != other.mSessionType ||
+ mOutputConfigurations.size() != other.mOutputConfigurations.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < mOutputConfigurations.size(); i++) {
+ if (!mOutputConfigurations.get(i).equals(other.mOutputConfigurations.get(i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mOutputConfigurations.hashCode(), mInputConfig.hashCode(),
+ mSessionType);
+ }
+
+ /**
* Retrieve the type of the capture session.
*
* @return The capture session type.
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index 0a76c2bc724e..a4c1332b45d1 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -16,20 +16,81 @@
package android.hardware.display;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
import com.android.internal.R;
/**
* Manages the display's color transforms and modes.
+ *
* @hide
*/
+@SystemService(Context.COLOR_DISPLAY_SERVICE)
public final class ColorDisplayManager {
+ private final ColorDisplayManagerInternal mManager;
+
+ /**
+ * @hide
+ */
+ public ColorDisplayManager() {
+ mManager = ColorDisplayManagerInternal.getInstance();
+ }
+
+ /**
+ * Returns whether the device has a wide color gamut display.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+ public boolean isDeviceColorManaged() {
+ return mManager.isDeviceColorManaged();
+ }
+
/**
* Returns {@code true} if Night Display is supported by the device.
*/
public static boolean isNightDisplayAvailable(Context context) {
return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable);
}
+
+ private static class ColorDisplayManagerInternal {
+
+ private static ColorDisplayManagerInternal sInstance;
+
+ private final IColorDisplayManager mCdm;
+
+ private ColorDisplayManagerInternal(IColorDisplayManager colorDisplayManager) {
+ mCdm = colorDisplayManager;
+ }
+
+ public static ColorDisplayManagerInternal getInstance() {
+ synchronized (ColorDisplayManagerInternal.class) {
+ if (sInstance == null) {
+ try {
+ IBinder b = ServiceManager.getServiceOrThrow(Context.COLOR_DISPLAY_SERVICE);
+ sInstance = new ColorDisplayManagerInternal(
+ IColorDisplayManager.Stub.asInterface(b));
+ } catch (ServiceNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ return sInstance;
+ }
+ }
+
+ boolean isDeviceColorManaged() {
+ try {
+ return mCdm.isDeviceColorManaged();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
}
diff --git a/core/java/android/hardware/display/IColorDisplayManager.aidl b/core/java/android/hardware/display/IColorDisplayManager.aidl
new file mode 100644
index 000000000000..f7865899812a
--- /dev/null
+++ b/core/java/android/hardware/display/IColorDisplayManager.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+/** @hide */
+interface IColorDisplayManager {
+ boolean isDeviceColorManaged();
+} \ No newline at end of file
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 64314a7d8060..2ae796c1ec56 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -85,6 +85,15 @@ public class Binder implements IBinder {
public static boolean LOG_RUNTIME_EXCEPTION = false; // DO NOT SUBMIT WITH TRUE
/**
+ * Value to represents that a calling work source is not set.
+ *
+ * This constatnt needs to be kept in sync with IPCThreadState::kUnsetWorkSource.
+ *
+ * @hide
+ */
+ public static final int UNSET_WORKSOURCE = -1;
+
+ /**
* Control whether dump() calls are allowed.
*/
private static volatile String sDumpDisabled = null;
@@ -449,8 +458,6 @@ public class Binder implements IBinder {
* }
* </pre>
*
- * <p>The work source will be propagated for future outgoing binder transactions
- * executed on this thread.
* @hide
**/
@CriticalNative
@@ -912,6 +919,16 @@ public class Binder implements IBinder {
// Entry point from android_util_Binder.cpp's onTransact
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
+ final long origWorkSource = ThreadLocalWorkSource.setUid(Binder.getCallingUid());
+ try {
+ return execTransactInternal(code, dataObj, replyObj, flags);
+ } finally {
+ ThreadLocalWorkSource.restore(origWorkSource);
+ }
+ }
+
+ private boolean execTransactInternal(int code, long dataObj, long replyObj,
+ int flags) {
// Make sure the observer won't change while processing a transaction.
final BinderInternal.Observer observer = sObserver;
final CallSession callSession =
@@ -925,7 +942,6 @@ public class Binder implements IBinder {
// Log any exceptions as warnings, don't silently suppress them.
// If the call was FLAG_ONEWAY then these exceptions disappear into the ether.
final boolean tracingEnabled = Binder.isTracingEnabled();
- final long origWorkSource = ThreadLocalWorkSource.setUid(Binder.getCallingUid());
try {
if (tracingEnabled) {
final String transactionName = getTransactionName(code);
@@ -952,7 +968,6 @@ public class Binder implements IBinder {
}
res = true;
} finally {
- ThreadLocalWorkSource.restore(origWorkSource);
if (tracingEnabled) {
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
}
@@ -972,7 +987,6 @@ public class Binder implements IBinder {
if (observer != null) {
observer.callEnded(callSession, requestSizeBytes, replySizeBytes);
}
-
return res;
}
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 900b62d98bf4..8cafbde8e3eb 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -269,7 +269,7 @@ public class GraphicsEnvironment {
}
// If no temp rules, load the real ones from the APK
- if (rulesFd == null) {
+ if (DEBUG && (rulesFd == null)) {
// Pass the rules file to loader for ANGLE decisions
AssetManager angleAssets = null;
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 894015ff5a92..c3e04894c6c9 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -17,7 +17,9 @@
package android.os;
import android.Manifest.permission;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
@@ -25,11 +27,15 @@ import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import android.service.dreams.Sandman;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.Preconditions;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
/**
* This class gives you control of the power state of the device.
@@ -643,6 +649,9 @@ public final class PowerManager {
final IPowerManager mService;
final Handler mHandler;
+ IThermalService mThermalService;
+ private ArrayMap<ThermalStatusCallback, IThermalStatusListener> mCallbackMap = new ArrayMap<>();
+
IDeviceIdleController mIDeviceIdleController;
/**
@@ -1443,6 +1452,159 @@ public final class PowerManager {
}
/**
+ * Thermal status code: Not under throttling.
+ */
+ public static final int THERMAL_STATUS_NONE = Temperature.THROTTLING_NONE;
+
+ /**
+ * Thermal status code: Light throttling where UX is not impacted.
+ */
+ public static final int THERMAL_STATUS_LIGHT = Temperature.THROTTLING_LIGHT;
+
+ /**
+ * Thermal status code: Moderate throttling where UX is not largely impacted.
+ */
+ public static final int THERMAL_STATUS_MODERATE = Temperature.THROTTLING_MODERATE;
+
+ /**
+ * Thermal status code: Severe throttling where UX is largely impacted.
+ */
+ public static final int THERMAL_STATUS_SEVERE = Temperature.THROTTLING_SEVERE;
+
+ /**
+ * Thermal status code: Platform has done everything to reduce power.
+ */
+ public static final int THERMAL_STATUS_CRITICAL = Temperature.THROTTLING_CRITICAL;
+
+ /**
+ * Thermal status code: Key components in platform are shutting down due to thermal condition.
+ * Device functionalities will be limited.
+ */
+ public static final int THERMAL_STATUS_EMERGENCY = Temperature.THROTTLING_EMERGENCY;
+
+ /**
+ * Thermal status code: Need shutdown immediately.
+ */
+ public static final int THERMAL_STATUS_SHUTDOWN = Temperature.THROTTLING_SHUTDOWN;
+
+ /** @hide */
+ @IntDef(prefix = { "THERMAL_STATUS_" }, value = {
+ THERMAL_STATUS_NONE,
+ THERMAL_STATUS_LIGHT,
+ THERMAL_STATUS_MODERATE,
+ THERMAL_STATUS_SEVERE,
+ THERMAL_STATUS_CRITICAL,
+ THERMAL_STATUS_EMERGENCY,
+ THERMAL_STATUS_SHUTDOWN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ThermalStatus {}
+
+ /**
+ * This function returns the current thermal status of the device.
+ *
+ * @return thermal status as int, {@link #THERMAL_STATUS_NONE} if device in not under
+ * thermal throttling.
+ */
+ public @ThermalStatus int getCurrentThermalStatus() {
+ synchronized (this) {
+ if (mThermalService == null) {
+ mThermalService = IThermalService.Stub.asInterface(
+ ServiceManager.getService(Context.THERMAL_SERVICE));
+ }
+ try {
+ return mThermalService.getCurrentThermalStatus();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ }
+
+ /**
+ * Callback passed to
+ * {@link PowerManager#registerThermalStatusCallback} and
+ * {@link PowerManager#unregisterThermalStatusCallback}
+ * to notify caller of thermal status.
+ */
+ public abstract static class ThermalStatusCallback {
+
+ /**
+ * Called when overall thermal throttling status changed.
+ * @param status defined in {@link android.os.Temperature}.
+ */
+ public void onStatusChange(@ThermalStatus int status) {}
+ }
+
+ /**
+ * This function registers a callback for thermal status change.
+ *
+ * @param callback callback to be registered.
+ * @param executor {@link Executor} to handle the callbacks.
+ */
+ public void registerThermalStatusCallback(
+ @NonNull ThermalStatusCallback callback, @NonNull @CallbackExecutor Executor executor) {
+ Preconditions.checkNotNull(callback, "callback cannnot be null");
+ Preconditions.checkNotNull(executor, "executor cannnot be null");
+ synchronized (this) {
+ if (mThermalService == null) {
+ mThermalService = IThermalService.Stub.asInterface(
+ ServiceManager.getService(Context.THERMAL_SERVICE));
+ }
+ try {
+ if (mCallbackMap.containsKey(callback)) {
+ throw new IllegalArgumentException("ThermalStatusCallback already registered");
+ }
+ IThermalStatusListener listener = new IThermalStatusListener.Stub() {
+ @Override
+ public void onStatusChange(int status) {
+ executor.execute(() -> {
+ callback.onStatusChange(status);
+ });
+ }
+ };
+ if (mThermalService.registerThermalStatusListener(listener)) {
+ mCallbackMap.put(callback, listener);
+ } else {
+ throw new RuntimeException("ThermalStatusCallback failed to register");
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * This function unregisters a callback for thermal status change.
+ *
+ * @param callback to be unregistered.
+ *
+ * see {@link #registerThermalStatusCallback}
+ */
+ public void unregisterThermalStatusCallback(ThermalStatusCallback callback) {
+ Preconditions.checkNotNull(callback, "callback cannnot be null");
+ synchronized (this) {
+ if (mThermalService == null) {
+ mThermalService = IThermalService.Stub.asInterface(
+ ServiceManager.getService(Context.THERMAL_SERVICE));
+ }
+ try {
+ IThermalStatusListener listener = mCallbackMap.get(callback);
+ if (listener == null) {
+ throw new IllegalArgumentException("ThermalStatusCallback not registered");
+ }
+ if (mThermalService.unregisterThermalStatusListener(listener)) {
+ mCallbackMap.remove(callback);
+ } else {
+ throw new RuntimeException("ThermalStatusCallback failed to unregister");
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* If true, the doze component is not started until after the screen has been
* turned off and the screen off animation has been performed.
* @hide
diff --git a/core/java/android/os/Temperature.java b/core/java/android/os/Temperature.java
index 21aba595bd5e..5499181c3cdb 100644
--- a/core/java/android/os/Temperature.java
+++ b/core/java/android/os/Temperature.java
@@ -44,7 +44,7 @@ public final class Temperature implements Parcelable {
THROTTLING_MODERATE,
THROTTLING_SEVERE,
THROTTLING_CRITICAL,
- THROTTLING_WARNING,
+ THROTTLING_EMERGENCY,
THROTTLING_SHUTDOWN,
})
@Retention(RetentionPolicy.SOURCE)
@@ -56,7 +56,7 @@ public final class Temperature implements Parcelable {
public static final int THROTTLING_MODERATE = ThrottlingSeverity.MODERATE;
public static final int THROTTLING_SEVERE = ThrottlingSeverity.SEVERE;
public static final int THROTTLING_CRITICAL = ThrottlingSeverity.CRITICAL;
- public static final int THROTTLING_WARNING = ThrottlingSeverity.WARNING;
+ public static final int THROTTLING_EMERGENCY = ThrottlingSeverity.EMERGENCY;
public static final int THROTTLING_SHUTDOWN = ThrottlingSeverity.SHUTDOWN;
@IntDef(prefix = { "TYPE_" }, value = {
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index 18aea03315ef..a41a64422038 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -16,6 +16,9 @@
package android.permissionpresenterservice;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.app.Service;
@@ -27,12 +30,8 @@ import android.content.pm.permission.RuntimePermissionPresenter;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
import android.os.RemoteCallback;
-import com.android.internal.os.SomeArgs;
-
import java.util.List;
/**
@@ -63,7 +62,7 @@ public abstract class RuntimePermissionPresenterService extends Service {
@Override
public final void attachBaseContext(Context base) {
super.attachBaseContext(base);
- mHandler = new MyHandler(base.getMainLooper());
+ mHandler = new Handler(base.getMainLooper());
}
/**
@@ -71,7 +70,8 @@ public abstract class RuntimePermissionPresenterService extends Service {
*
* @param packageName The package for which to query.
*/
- public abstract List<RuntimePermissionPresentationInfo> onGetAppPermissions(String packageName);
+ public abstract List<RuntimePermissionPresentationInfo> onGetAppPermissions(
+ @NonNull String packageName);
/**
* Revokes the permission {@code permissionName} for app {@code packageName}
@@ -87,61 +87,35 @@ public abstract class RuntimePermissionPresenterService extends Service {
return new IRuntimePermissionPresenter.Stub() {
@Override
public void getAppPermissions(String packageName, RemoteCallback callback) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = packageName;
- args.arg2 = callback;
- mHandler.obtainMessage(MyHandler.MSG_GET_APP_PERMISSIONS,
- args).sendToTarget();
+ checkNotNull(packageName, "packageName");
+ checkNotNull(callback, "callback");
+
+ mHandler.sendMessage(
+ obtainMessage(RuntimePermissionPresenterService::getAppPermissions,
+ RuntimePermissionPresenterService.this, packageName, callback));
}
@Override
public void revokeRuntimePermission(String packageName, String permissionName) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = packageName;
- args.arg2 = permissionName;
- mHandler.obtainMessage(MyHandler.MSG_REVOKE_APP_PERMISSION,
- args).sendToTarget();
+ checkNotNull(packageName, "packageName");
+ checkNotNull(permissionName, "permissionName");
+
+ mHandler.sendMessage(
+ obtainMessage(RuntimePermissionPresenterService::onRevokeRuntimePermission,
+ RuntimePermissionPresenterService.this, packageName,
+ permissionName));
}
};
}
- private final class MyHandler extends Handler {
- public static final int MSG_GET_APP_PERMISSIONS = 1;
- public static final int MSG_GET_APPS_USING_PERMISSIONS = 2;
- public static final int MSG_REVOKE_APP_PERMISSION = 3;
-
- public MyHandler(Looper looper) {
- super(looper, null, false);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_GET_APP_PERMISSIONS: {
- SomeArgs args = (SomeArgs) msg.obj;
- String packageName = (String) args.arg1;
- RemoteCallback callback = (RemoteCallback) args.arg2;
- args.recycle();
- List<RuntimePermissionPresentationInfo> permissions =
- onGetAppPermissions(packageName);
- if (permissions != null && !permissions.isEmpty()) {
- Bundle result = new Bundle();
- result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT,
- permissions);
- callback.sendResult(result);
- } else {
- callback.sendResult(null);
- }
- } break;
- case MSG_REVOKE_APP_PERMISSION: {
- SomeArgs args = (SomeArgs) msg.obj;
- String packageName = (String) args.arg1;
- String permissionName = (String) args.arg2;
- args.recycle();
-
- onRevokeRuntimePermission(packageName, permissionName);
- } break;
- }
+ private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) {
+ List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
+ if (permissions != null && !permissions.isEmpty()) {
+ Bundle result = new Bundle();
+ result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT, permissions);
+ callback.sendResult(result);
+ } else {
+ callback.sendResult(null);
}
}
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index e032c1896a4b..37c84bd74395 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -152,6 +152,17 @@ public final class DocumentsContract {
"android:query-arg-last-modified-after";
/**
+ * Key for {@link DocumentsProvider} to decide whether the files that
+ * have been added to MediaStore should be excluded. If the value is
+ * true, exclude them. Otherwise, include them.
+ *
+ * @see DocumentsProvider#querySearchDocuments(String, String[],
+ * Bundle)
+ * {@hide}
+ */
+ public static final String QUERY_ARG_EXCLUDE_MEDIA = "android:query-arg-exclude-media";
+
+ /**
* Sets the desired initial location visible to user when file chooser is shown.
*
* <p>Applicable to {@link Intent} with actions:
@@ -1017,6 +1028,7 @@ public final class DocumentsContract {
/**
* Get the handled query arguments from the query bundle. The handled arguments are
+ * {@link DocumentsContract#QUERY_ARG_EXCLUDE_MEDIA},
* {@link DocumentsContract#QUERY_ARG_DISPLAY_NAME},
* {@link DocumentsContract#QUERY_ARG_MIME_TYPES},
* {@link DocumentsContract#QUERY_ARG_FILE_SIZE_OVER} and
@@ -1032,6 +1044,11 @@ public final class DocumentsContract {
}
final ArrayList<String> args = new ArrayList<>();
+
+ if (queryArgs.keySet().contains(QUERY_ARG_EXCLUDE_MEDIA)) {
+ args.add(QUERY_ARG_EXCLUDE_MEDIA);
+ }
+
if (queryArgs.keySet().contains(QUERY_ARG_DISPLAY_NAME)) {
args.add(QUERY_ARG_DISPLAY_NAME);
}
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 58f82134ec50..6ab72c7bb372 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -677,6 +677,7 @@ public abstract class DocumentsProvider extends ContentProvider {
* cursor. If {@code null} all supported columns should be
* included.
* @param queryArgs the query arguments.
+ * {@link DocumentsContract#QUERY_ARG_EXCLUDE_MEDIA},
* {@link DocumentsContract#QUERY_ARG_DISPLAY_NAME},
* {@link DocumentsContract#QUERY_ARG_MIME_TYPES},
* {@link DocumentsContract#QUERY_ARG_FILE_SIZE_OVER},
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 9e26a368ad80..0299e416707a 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -37,6 +37,7 @@ import android.database.DatabaseUtils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
+import android.media.ExifInterface;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -1166,13 +1167,25 @@ public final class MediaStore {
/**
* The latitude where the image was captured.
* <P>Type: DOUBLE</P>
+ *
+ * @deprecated location details are no longer indexed for privacy
+ * reasons, and this value is now always {@code null}.
+ * You can still manually obtain location metadata using
+ * {@link ExifInterface#getLatLong(float[])}.
*/
+ @Deprecated
public static final String LATITUDE = "latitude";
/**
* The longitude where the image was captured.
* <P>Type: DOUBLE</P>
+ *
+ * @deprecated location details are no longer indexed for privacy
+ * reasons, and this value is now always {@code null}.
+ * You can still manually obtain location metadata using
+ * {@link ExifInterface#getLatLong(float[])}.
*/
+ @Deprecated
public static final String LONGITUDE = "longitude";
/**
@@ -2410,13 +2423,25 @@ public final class MediaStore {
/**
* The latitude where the video was captured.
* <P>Type: DOUBLE</P>
+ *
+ * @deprecated location details are no longer indexed for privacy
+ * reasons, and this value is now always {@code null}.
+ * You can still manually obtain location metadata using
+ * {@link ExifInterface#getLatLong(float[])}.
*/
+ @Deprecated
public static final String LATITUDE = "latitude";
/**
* The longitude where the video was captured.
* <P>Type: DOUBLE</P>
+ *
+ * @deprecated location details are no longer indexed for privacy
+ * reasons, and this value is now always {@code null}.
+ * You can still manually obtain location metadata using
+ * {@link ExifInterface#getLatLong(float[])}.
*/
+ @Deprecated
public static final String LONGITUDE = "longitude";
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b53d9af5d4e4..c3217a2189cf 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4252,6 +4252,7 @@ public final class Settings {
PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY_TIMEOUT);
PUBLIC_SETTINGS.add(NEXT_ALARM_FORMATTED);
PUBLIC_SETTINGS.add(FONT_SCALE);
+ PUBLIC_SETTINGS.add(SYSTEM_LOCALES);
PUBLIC_SETTINGS.add(DIM_SCREEN);
PUBLIC_SETTINGS.add(SCREEN_OFF_TIMEOUT);
PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS);
@@ -12838,6 +12839,23 @@ public final class Settings {
"max_sound_trigger_detection_service_ops_per_day";
/**
+ * Property used by {@code com.android.server.SystemServer} on start to decide whether
+ * the Smart Suggestions service should be created or not
+ *
+ * <p>By default it should *NOT* be set (in which case the decision is based on whether
+ * the OEM provides an implementation for the service), but it can be overridden to:
+ *
+ * <ul>
+ * <li>Provide a "kill switch" so OEMs can disable it remotely in case of emergency.
+ * <li>Enable the CTS tests to be run on AOSP builds
+ * </ul>
+ *
+ * @hide
+ */
+ public static final String SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED =
+ "smart_suggestions_service_explicitly_enabled";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -13510,6 +13528,13 @@ public final class Settings {
*/
public static final String WARNING_TEMPERATURE = "warning_temperature";
+
+ /**
+ * USB Temperature at which the high temperature alarm notification should be shown.
+ * @hide
+ */
+ public static final String USB_ALARM_TEMPERATURE = "usb_alarm_temperature";
+
/**
* Whether the diskstats logging task is enabled/disabled.
* @hide
diff --git a/core/java/android/service/intelligence/FillCallback.java b/core/java/android/service/intelligence/FillCallback.java
index af2da79170ef..ddf37f737296 100644
--- a/core/java/android/service/intelligence/FillCallback.java
+++ b/core/java/android/service/intelligence/FillCallback.java
@@ -15,8 +15,10 @@
*/
package android.service.intelligence;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.service.intelligence.SmartSuggestionsService.AutofillProxy;
/**
* Callback used to indicate at {@link FillRequest} has been fulfilled.
@@ -25,8 +27,11 @@ import android.annotation.SystemApi;
*/
@SystemApi
public final class FillCallback {
+ private final AutofillProxy mProxy;
- FillCallback() {}
+ FillCallback(@NonNull AutofillProxy proxy) {
+ mProxy = proxy;
+ }
/**
* Sets the response associated with the request.
@@ -35,6 +40,7 @@ public final class FillCallback {
* could not provide autofill for the request.
*/
public void onSuccess(@Nullable FillResponse response) {
+ mProxy.report(AutofillProxy.REPORT_EVENT_ON_SUCCESS);
final FillWindow fillWindow = response.getFillWindow();
if (fillWindow != null) {
fillWindow.show();
diff --git a/core/java/android/service/intelligence/FillRequest.java b/core/java/android/service/intelligence/FillRequest.java
index f68db9df6fe3..53e99a5fd3b8 100644
--- a/core/java/android/service/intelligence/FillRequest.java
+++ b/core/java/android/service/intelligence/FillRequest.java
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.service.intelligence.SmartSuggestionsService.AutofillProxy;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
/**
* Represents a request to augment-fill an activity.
@@ -52,6 +53,14 @@ public final class FillRequest {
}
/**
+ * Gets the current value of the field that triggered the request.
+ */
+ @NonNull
+ public AutofillValue getFocusedAutofillValue() {
+ return mProxy.focusedValue;
+ }
+
+ /**
* Gets the Smart Suggestions object used to embed the autofill UI.
*
* @return object used to embed the autofill UI, or {@code null} if not supported.
diff --git a/core/java/android/service/intelligence/FillWindow.java b/core/java/android/service/intelligence/FillWindow.java
index 309f6a1b6f1b..39d7e08a68d9 100644
--- a/core/java/android/service/intelligence/FillWindow.java
+++ b/core/java/android/service/intelligence/FillWindow.java
@@ -23,6 +23,7 @@ import android.annotation.SystemApi;
import android.app.Dialog;
import android.graphics.Rect;
import android.service.intelligence.PresentationParams.Area;
+import android.service.intelligence.SmartSuggestionsService.AutofillProxy;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
@@ -33,6 +34,8 @@ import android.view.WindowManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
+import dalvik.system.CloseGuard;
+
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -73,6 +76,7 @@ public final class FillWindow {
@interface Flags{}
private final Object mLock = new Object();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
@GuardedBy("mLock")
private Dialog mDialog;
@@ -80,6 +84,8 @@ public final class FillWindow {
@GuardedBy("mLock")
private boolean mDestroyed;
+ private AutofillProxy mProxy;
+
/**
* Updates the content of the window.
*
@@ -123,6 +129,8 @@ public final class FillWindow {
synchronized (mLock) {
checkNotDestroyedLocked();
+ mProxy = area.proxy;
+
// TODO(b/111330312): once we have the SurfaceControl approach, we should update the
// window instead of destroying. In fact, it might be better to allocate a full window
// initially, which is transparent (and let touches get through) everywhere but in the
@@ -133,6 +141,7 @@ public final class FillWindow {
// etc.
mDialog = new Dialog(rootView.getContext());
+ mCloseGuard.open("destroy");
final Window window = mDialog.getWindow();
window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
@@ -156,7 +165,7 @@ public final class FillWindow {
Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView);
}
- area.proxy.setFillWindow(this);
+ mProxy.setFillWindow(this);
return true;
}
}
@@ -173,6 +182,9 @@ public final class FillWindow {
}
mDialog.show();
+ if (mProxy != null) {
+ mProxy.report(AutofillProxy.REPORT_EVENT_UI_SHOWN);
+ }
}
}
@@ -182,15 +194,29 @@ public final class FillWindow {
* <p>Once destroyed, this window cannot be used anymore
*/
public void destroy() {
- if (DEBUG) Log.d(TAG, "destroy(): mDestroyed = " + mDestroyed);
+ if (DEBUG) Log.d(TAG, "destroy(): mDestroyed=" + mDestroyed + " mDialog=" + mDialog);
synchronized (this) {
- if (mDestroyed) return;
+ if (mDestroyed || mDialog == null) return;
- if (mDialog != null) {
- mDialog.dismiss();
- mDialog = null;
+ mDialog.dismiss();
+ mDialog = null;
+ if (mProxy != null) {
+ mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
}
+ mCloseGuard.close();
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ destroy();
+ } finally {
+ super.finalize();
}
}
diff --git a/core/java/android/service/intelligence/IIntelligenceService.aidl b/core/java/android/service/intelligence/IIntelligenceService.aidl
index d6b31079e34c..2b924fbaadc4 100644
--- a/core/java/android/service/intelligence/IIntelligenceService.aidl
+++ b/core/java/android/service/intelligence/IIntelligenceService.aidl
@@ -23,6 +23,7 @@ import android.service.intelligence.InteractionContext;
import android.service.intelligence.SnapshotData;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
import android.view.intelligence.ContentCaptureEvent;
import java.util.List;
@@ -45,7 +46,8 @@ oneway interface IIntelligenceService {
in SnapshotData snapshotData);
void onAutofillRequest(in InteractionSessionId sessionId, in IBinder autofillManagerClient,
- int autofilSessionId, in AutofillId focusedId);
+ int autofilSessionId, in AutofillId focusedId,
+ in AutofillValue focusedValue, long requestTime);
void onDestroyAutofillWindowsRequest(in InteractionSessionId sessionId);
}
diff --git a/core/java/android/service/intelligence/SmartSuggestionsService.java b/core/java/android/service/intelligence/SmartSuggestionsService.java
index 0e29e70ecc3b..b684b0208d8d 100644
--- a/core/java/android/service/intelligence/SmartSuggestionsService.java
+++ b/core/java/android/service/intelligence/SmartSuggestionsService.java
@@ -18,6 +18,7 @@ package android.service.intelligence;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.CallSuper;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -30,10 +31,13 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.service.intelligence.PresentationParams.SystemPopupPresentationParams;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
+import android.util.Slog;
+import android.util.TimeUtils;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAugmentedAutofillManagerClient;
@@ -43,6 +47,8 @@ import com.android.internal.annotations.GuardedBy;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -110,9 +116,11 @@ public abstract class SmartSuggestionsService extends Service {
@Override
public void onAutofillRequest(InteractionSessionId sessionId, IBinder client,
- int autofilSessionId, AutofillId focusedId) {
+ int autofilSessionId, AutofillId focusedId, AutofillValue focusedValue,
+ long requestTime) {
mHandler.sendMessage(obtainMessage(SmartSuggestionsService::handleOnAutofillRequest,
- SmartSuggestionsService.this, sessionId, client, autofilSessionId, focusedId));
+ SmartSuggestionsService.this, sessionId, client, autofilSessionId, focusedId,
+ focusedValue, requestTime));
}
@Override
@@ -229,13 +237,15 @@ public abstract class SmartSuggestionsService extends Service {
@NonNull ContentCaptureEventsRequest request);
private void handleOnAutofillRequest(@NonNull InteractionSessionId sessionId,
- @NonNull IBinder client, int autofillSessionId, @NonNull AutofillId focusedId) {
+ @NonNull IBinder client, int autofillSessionId, @NonNull AutofillId focusedId,
+ @Nullable AutofillValue focusedValue, long requestTime) {
if (mAutofillProxies == null) {
mAutofillProxies = new ArrayMap<>();
}
AutofillProxy proxy = mAutofillProxies.get(sessionId);
if (proxy == null) {
- proxy = new AutofillProxy(sessionId, client, autofillSessionId, focusedId);
+ proxy = new AutofillProxy(sessionId, client, autofillSessionId, focusedId, focusedValue,
+ requestTime);
mAutofillProxies.put(sessionId, proxy);
} else {
// TODO(b/111330312): figure out if it's ok to reuse the proxy; add logging
@@ -244,7 +254,7 @@ public abstract class SmartSuggestionsService extends Service {
// TODO(b/111330312): set cancellation signal
final CancellationSignal cancellationSignal = null;
onFillRequest(sessionId, new FillRequest(proxy), cancellationSignal,
- new FillController(proxy), new FillCallback());
+ new FillController(proxy), new FillCallback(proxy));
}
/**
@@ -332,11 +342,32 @@ public abstract class SmartSuggestionsService extends Service {
/** @hide */
static final class AutofillProxy {
+
+ static final int REPORT_EVENT_ON_SUCCESS = 1;
+ static final int REPORT_EVENT_UI_SHOWN = 2;
+ static final int REPORT_EVENT_UI_DESTROYED = 3;
+
+ @IntDef(prefix = { "REPORT_EVENT_" }, value = {
+ REPORT_EVENT_ON_SUCCESS,
+ REPORT_EVENT_UI_SHOWN,
+ REPORT_EVENT_UI_DESTROYED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface ReportEvent{}
+
+
private final Object mLock = new Object();
private final IAugmentedAutofillManagerClient mClient;
private final int mAutofillSessionId;
public final InteractionSessionId sessionId;
public final AutofillId focusedId;
+ public final AutofillValue focusedValue;
+
+ // Objects used to log metrics
+ private final long mRequestTime;
+ private long mOnSuccessTime;
+ private long mUiFirstShownTime;
+ private long mUiFirstDestroyedTime;
@GuardedBy("mLock")
private SystemPopupPresentationParams mSmartSuggestion;
@@ -345,11 +376,14 @@ public abstract class SmartSuggestionsService extends Service {
private FillWindow mFillWindow;
private AutofillProxy(@NonNull InteractionSessionId sessionId, @NonNull IBinder client,
- int autofillSessionId, @NonNull AutofillId focusedId) {
+ int autofillSessionId, @NonNull AutofillId focusedId,
+ @Nullable AutofillValue focusedValue, long requestTime) {
this.sessionId = sessionId;
mClient = IAugmentedAutofillManagerClient.Stub.asInterface(client);
mAutofillSessionId = autofillSessionId;
this.focusedId = focusedId;
+ this.focusedValue = focusedValue;
+ this.mRequestTime = requestTime;
// TODO(b/111330312): linkToDeath
}
@@ -400,9 +434,50 @@ public abstract class SmartSuggestionsService extends Service {
}
}
+ // Used for metrics.
+ public void report(@ReportEvent int event) {
+ switch (event) {
+ case REPORT_EVENT_ON_SUCCESS:
+ if (mOnSuccessTime == 0) {
+ mOnSuccessTime = SystemClock.elapsedRealtime();
+ if (DEBUG) {
+ Slog.d(TAG, "Service responsed in "
+ + TimeUtils.formatDuration(mOnSuccessTime - mRequestTime));
+ }
+ }
+ break;
+ case REPORT_EVENT_UI_SHOWN:
+ if (mUiFirstShownTime == 0) {
+ mUiFirstShownTime = SystemClock.elapsedRealtime();
+ if (DEBUG) {
+ Slog.d(TAG, "UI shown in "
+ + TimeUtils.formatDuration(mUiFirstShownTime - mRequestTime));
+ }
+ }
+ break;
+ case REPORT_EVENT_UI_DESTROYED:
+ if (mUiFirstDestroyedTime == 0) {
+ mUiFirstDestroyedTime = SystemClock.elapsedRealtime();
+ if (DEBUG) {
+ Slog.d(TAG, "UI destroyed in "
+ + TimeUtils.formatDuration(
+ mUiFirstDestroyedTime - mRequestTime));
+ }
+ }
+ break;
+ default:
+ Slog.w(TAG, "invalid event reported: " + event);
+ }
+ // TODO(b/111330312): log metrics as well
+ }
+
+
public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
pw.print(prefix); pw.print("afSessionId: "); pw.println(mAutofillSessionId);
pw.print(prefix); pw.print("focusedId: "); pw.println(focusedId);
+ if (focusedValue != null) {
+ pw.print(prefix); pw.print("focusedValue: "); pw.println(focusedValue);
+ }
pw.print(prefix); pw.print("client: "); pw.println(mClient);
final String prefix2 = prefix + " ";
if (mFillWindow != null) {
@@ -413,6 +488,23 @@ public abstract class SmartSuggestionsService extends Service {
pw.print(prefix); pw.println("smartSuggestion:");
mSmartSuggestion.dump(prefix2, pw);
}
+ if (mOnSuccessTime > 0) {
+ final long responseTime = mOnSuccessTime - mRequestTime;
+ pw.print(prefix); pw.print("response time: ");
+ TimeUtils.formatDuration(responseTime, pw); pw.println();
+ }
+
+ if (mUiFirstShownTime > 0) {
+ final long uiRenderingTime = mUiFirstShownTime - mRequestTime;
+ pw.print(prefix); pw.print("UI rendering time: ");
+ TimeUtils.formatDuration(uiRenderingTime, pw); pw.println();
+ }
+
+ if (mUiFirstDestroyedTime > 0) {
+ final long uiTotalTime = mUiFirstDestroyedTime - mRequestTime;
+ pw.print(prefix); pw.print("UI life time: ");
+ TimeUtils.formatDuration(uiTotalTime, pw); pw.println();
+ }
}
private void destroy() {
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 3ee5f1fcc883..33b3ff4fef59 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -18,6 +18,7 @@ package android.view;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.os.Build;
import android.os.Handler;
import android.os.Message;
@@ -225,7 +226,7 @@ public class GestureDetector {
private int mMinimumFlingVelocity;
private int mMaximumFlingVelocity;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
@@ -592,8 +593,8 @@ public class GestureDetector {
if (mIsLongpressEnabled) {
mHandler.removeMessages(LONG_PRESS);
- mHandler.sendEmptyMessageAtTime(LONG_PRESS,
- mCurrentDownEvent.getDownTime() + LONGPRESS_TIMEOUT);
+ mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
+ + ViewConfiguration.getLongPressTimeout());
}
mHandler.sendEmptyMessageAtTime(SHOW_PRESS,
mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 8b39cc72af8f..9cced4e0052f 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1803,6 +1803,28 @@ public class KeyEvent extends InputEvent implements Parcelable {
}
/**
+ * Returns whether this key will be sent to the
+ * {@link android.media.session.MediaSession.Callback} if not handled.
+ */
+ public static final boolean isMediaSessionKey(int keyCode) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Returns true if the specified keycode is a gamepad button.
* @return True if the keycode is a gamepad button, such as {@link #KEYCODE_BUTTON_A}.
*/
@@ -1861,31 +1883,6 @@ public class KeyEvent extends InputEvent implements Parcelable {
}
}
- /**
- * Returns whether this key can be handled by
- * {@link android.media.session.MediaSession.Callback}.
- *
- * @hide
- */
- public static final boolean isMediaSessionKey(int keyCode) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_MUTE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- case KeyEvent.KEYCODE_MEDIA_RECORD:
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
- return true;
- }
- return false;
- }
-
-
/** Is this a system key? System keys can not be used for menu shortcuts.
* @hide
*/
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4b9cbff8c161..bd2aa64b33a1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -112,6 +112,9 @@ import android.view.autofill.AutofillValue;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
+import android.view.inspector.InspectableProperty;
+import android.view.inspector.InspectableProperty.EnumMap;
+import android.view.inspector.InspectableProperty.FlagMap;
import android.view.intelligence.ContentCaptureManager;
import android.widget.Checkable;
import android.widget.FrameLayout;
@@ -4895,6 +4898,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public static final int LAYER_TYPE_HARDWARE = 2;
+ /** @hide */
+ @IntDef(prefix = { "LAYER_TYPE_" }, value = {
+ LAYER_TYPE_NONE,
+ LAYER_TYPE_SOFTWARE,
+ LAYER_TYPE_HARDWARE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LayerType {}
+
@ViewDebug.ExportedProperty(category = "drawing", mapping = {
@ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"),
@ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"),
@@ -6516,6 +6528,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return a bitmask representing the enabled scroll indicators
*/
+ @InspectableProperty(flagMapping = {
+ @FlagMap(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"),
+ @FlagMap(target = SCROLL_INDICATOR_TOP, name = "top"),
+ @FlagMap(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"),
+ @FlagMap(target = SCROLL_INDICATOR_LEFT, name = "left"),
+ @FlagMap(target = SCROLL_INDICATOR_RIGHT, name = "right"),
+ @FlagMap(target = SCROLL_INDICATOR_START, name = "start"),
+ @FlagMap(target = SCROLL_INDICATOR_END, name = "end")
+ })
@ScrollIndicators
public int getScrollIndicators() {
return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK)
@@ -7582,7 +7603,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* {@see #setAccessibilityPaneTitle}.
*/
- @Nullable public CharSequence getAccessibilityPaneTitle() {
+ @InspectableProperty
+ @Nullable
+ public CharSequence getAccessibilityPaneTitle() {
return mAccessibilityPaneTitle;
}
@@ -8580,6 +8603,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_autofillHints
*/
@ViewDebug.ExportedProperty()
+ @InspectableProperty
@Nullable public String[] getAutofillHints() {
return mAutofillHints;
}
@@ -8624,6 +8648,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
to = "yesExcludeDescendants"),
@ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
to = "noExcludeDescendants")})
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"),
+ @EnumMap(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"),
+ @EnumMap(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"),
+ @EnumMap(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
+ name = "yesExcludeDescendants"),
+ @EnumMap(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
+ name = "noExcludeDescendants"),
+ })
public @AutofillImportance int getImportantForAutofill() {
return (mPrivateFlags3
& PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT;
@@ -8808,6 +8841,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
to = "yesExcludeDescendants"),
@ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
to = "noExcludeDescendants")})
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"),
+ @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"),
+ @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"),
+ @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS,
+ name = "yesExcludeDescendants"),
+ @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
+ name = "noExcludeDescendants"),
+ })
public @ContentCaptureImportance int getImportantForContentCapture() {
// NOTE: the important for content capture values were the first flags added and are set in
// the rightmost position, so we don't need to shift them
@@ -9619,6 +9661,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_contentDescription
*/
@ViewDebug.ExportedProperty(category = "accessibility")
+ @InspectableProperty
public CharSequence getContentDescription() {
return mContentDescription;
}
@@ -9699,6 +9742,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @see #setAccessibilityTraversalBefore(int)
*/
+ @InspectableProperty
public int getAccessibilityTraversalBefore() {
return mAccessibilityTraversalBeforeId;
}
@@ -9743,6 +9787,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @see #setAccessibilityTraversalAfter(int)
*/
+ @InspectableProperty
public int getAccessibilityTraversalAfter() {
return mAccessibilityTraversalAfterId;
}
@@ -9754,6 +9799,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The labeled view id.
*/
@ViewDebug.ExportedProperty(category = "accessibility")
+ @InspectableProperty
public int getLabelFor() {
return mLabelForId;
}
@@ -9817,6 +9863,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return True if this view has focus, false otherwise.
*/
@ViewDebug.ExportedProperty(category = "focus")
+ @InspectableProperty(hasAttributeId = false)
public boolean isFocused() {
return (mPrivateFlags & PFLAG_FOCUSED) != 0;
}
@@ -9841,6 +9888,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_isScrollContainer
*/
+ @InspectableProperty(name = "isScrollContainer")
public boolean isScrollContainer() {
return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0;
}
@@ -9896,6 +9944,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@Deprecated
@DrawingCacheQuality
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = DRAWING_CACHE_QUALITY_LOW, name = "low"),
+ @EnumMap(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"),
+ @EnumMap(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto")
+ })
public int getDrawingCacheQuality() {
return mViewFlags & DRAWING_CACHE_QUALITY_MASK;
}
@@ -9941,6 +9994,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_keepScreenOn
*/
+ @InspectableProperty
public boolean getKeepScreenOn() {
return (mViewFlags & KEEP_SCREEN_ON) != 0;
}
@@ -9965,6 +10019,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_nextFocusLeft
*/
+ @InspectableProperty(name = "nextFocusLeft")
public int getNextFocusLeftId() {
return mNextFocusLeftId;
}
@@ -9986,6 +10041,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_nextFocusRight
*/
+ @InspectableProperty(name = "nextFocusRight")
public int getNextFocusRightId() {
return mNextFocusRightId;
}
@@ -10007,6 +10063,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_nextFocusUp
*/
+ @InspectableProperty(name = "nextFocusUp")
public int getNextFocusUpId() {
return mNextFocusUpId;
}
@@ -10028,6 +10085,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_nextFocusDown
*/
+ @InspectableProperty(name = "nextFocusDown")
public int getNextFocusDownId() {
return mNextFocusDownId;
}
@@ -10049,6 +10107,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_nextFocusForward
*/
+ @InspectableProperty(name = "nextFocusForward")
public int getNextFocusForwardId() {
return mNextFocusForwardId;
}
@@ -10071,6 +10130,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_nextClusterForward
*/
+ @InspectableProperty(name = "nextClusterForward")
public int getNextClusterForwardId() {
return mNextClusterForwardId;
}
@@ -10437,6 +10497,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setSystemUiVisibility(int)
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty
public boolean getFitsSystemWindows() {
return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS;
}
@@ -10498,6 +10559,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"),
@ViewDebug.IntToString(from = GONE, to = "GONE")
})
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = VISIBLE, name = "visible"),
+ @EnumMap(value = INVISIBLE, name = "invisible"),
+ @EnumMap(value = GONE, name = "gone")
+ })
@Visibility
public int getVisibility() {
return mViewFlags & VISIBILITY_MASK;
@@ -10521,6 +10587,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return True if this view is enabled, false otherwise.
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty
public boolean isEnabled() {
return (mViewFlags & ENABLED_MASK) == ENABLED;
}
@@ -10690,6 +10757,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_soundEffectsEnabled
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty
public boolean isSoundEffectsEnabled() {
return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED);
}
@@ -10719,6 +10787,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_hapticFeedbackEnabled
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty
public boolean isHapticFeedbackEnabled() {
return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED);
}
@@ -10741,6 +10810,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"),
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE")
})
+ @InspectableProperty(hasAttributeId = false, enumMapping = {
+ @EnumMap(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
+ @EnumMap(value = LAYOUT_DIRECTION_RTL, name = "rtl"),
+ @EnumMap(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"),
+ @EnumMap(value = LAYOUT_DIRECTION_LOCALE, name = "locale")
+ })
@LayoutDir
public int getRawLayoutDirection() {
return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
@@ -10794,6 +10869,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"),
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL")
})
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
+ @EnumMap(value = LAYOUT_DIRECTION_RTL, name = "rtl")
+ })
@ResolvedLayoutDir
public int getLayoutDirection() {
final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
@@ -10980,6 +11059,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_clickable
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty
public boolean isClickable() {
return (mViewFlags & CLICKABLE) == CLICKABLE;
}
@@ -11007,6 +11087,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setLongClickable(boolean)
* @attr ref android.R.styleable#View_longClickable
*/
+ @InspectableProperty
public boolean isLongClickable() {
return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE;
}
@@ -11032,6 +11113,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setContextClickable(boolean)
* @attr ref android.R.styleable#View_contextClickable
*/
+ @InspectableProperty
public boolean isContextClickable() {
return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
}
@@ -11111,6 +11193,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return true if the view is currently pressed, false otherwise
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty(hasAttributeId = false)
public boolean isPressed() {
return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED;
}
@@ -11126,6 +11209,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setAssistBlocked(boolean)
* @attr ref android.R.styleable#View_assistBlocked
*/
+ @InspectableProperty
public boolean isAssistBlocked() {
return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0;
}
@@ -11163,6 +11247,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setSaveEnabled(boolean)
* @attr ref android.R.styleable#View_saveEnabled
*/
+ @InspectableProperty
public boolean isSaveEnabled() {
return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED;
}
@@ -11198,6 +11283,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_filterTouchesWhenObscured
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty
public boolean getFilterTouchesWhenObscured() {
return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0;
}
@@ -11270,6 +11356,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"),
@ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO")
}, category = "focus")
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = NOT_FOCUSABLE, name = "false"),
+ @EnumMap(value = FOCUSABLE, name = "true"),
+ @EnumMap(value = FOCUSABLE_AUTO, name = "auto")
+ })
@Focusable
public int getFocusable() {
return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE;
@@ -11284,6 +11375,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_focusableInTouchMode
*/
@ViewDebug.ExportedProperty(category = "focus")
+ @InspectableProperty
public final boolean isFocusableInTouchMode() {
return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE);
}
@@ -11295,6 +11387,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return Whether the view should be treated as a focusable unit by screen reader.
*/
+ @InspectableProperty
public boolean isScreenReaderFocusable() {
return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0;
}
@@ -11323,6 +11416,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_accessibilityHeading
*/
+ @InspectableProperty
public boolean isAccessibilityHeading() {
return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0;
}
@@ -11377,6 +11471,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_keyboardNavigationCluster
*/
@ViewDebug.ExportedProperty(category = "focus")
+ @InspectableProperty
public final boolean isKeyboardNavigationCluster() {
return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0;
}
@@ -11486,6 +11581,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_focusedByDefault
*/
@ViewDebug.ExportedProperty(category = "focus")
+ @InspectableProperty
public final boolean isFocusedByDefault() {
return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0;
}
@@ -11599,6 +11695,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_defaultFocusHighlightEnabled
*/
@ViewDebug.ExportedProperty(category = "focus")
+ @InspectableProperty
public final boolean getDefaultFocusHighlightEnabled() {
return mDefaultFocusHighlightEnabled;
}
@@ -11817,6 +11914,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return True if this View is accessibility focused.
*/
+ @InspectableProperty(hasAttributeId = false)
public boolean isAccessibilityFocused() {
return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0;
}
@@ -12143,6 +12241,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
to = "noHideDescendants")
})
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"),
+ @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"),
+ @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"),
+ @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
+ name = "noHideDescendants"),
+ })
public int getImportantForAccessibility() {
return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK)
>> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
@@ -12195,6 +12300,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @see #setAccessibilityLiveRegion(int)
*/
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"),
+ @EnumMap(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"),
+ @EnumMap(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive")
+ })
public int getAccessibilityLiveRegion() {
return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK)
>> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT;
@@ -15042,6 +15152,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return The left edge of the displayed part of your view, in pixels.
*/
+ @InspectableProperty
public final int getScrollX() {
return mScrollX;
}
@@ -15053,6 +15164,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return The top edge of the displayed part of your view, in pixels.
*/
+ @InspectableProperty
public final int getScrollY() {
return mScrollY;
}
@@ -15289,6 +15401,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The degrees of rotation.
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public float getRotation() {
return mRenderNode.getRotation();
}
@@ -15329,6 +15442,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The degrees of Y rotation.
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public float getRotationY() {
return mRenderNode.getRotationY();
}
@@ -15373,6 +15487,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The degrees of X rotation.
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public float getRotationX() {
return mRenderNode.getRotationX();
}
@@ -15418,6 +15533,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The scaling factor.
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public float getScaleX() {
return mRenderNode.getScaleX();
}
@@ -15455,6 +15571,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The scaling factor.
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public float getScaleY() {
return mRenderNode.getScaleY();
}
@@ -15494,6 +15611,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_transformPivotX
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty(name = "transformPivotX")
public float getPivotX() {
return mRenderNode.getPivotX();
}
@@ -15536,6 +15654,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_transformPivotY
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty(name = "transformPivotY")
public float getPivotY() {
return mRenderNode.getPivotY();
}
@@ -15594,6 +15713,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The opacity of the view.
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public float getAlpha() {
return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
}
@@ -15816,6 +15936,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return true if force dark is allowed (default), false if it is disabled
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public boolean isForceDarkAllowed() {
return mRenderNode.isForceDarkAllowed();
}
@@ -16187,6 +16308,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The base depth position of the view, in pixels.
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public float getElevation() {
return mRenderNode.getElevation();
}
@@ -16215,6 +16337,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The horizontal position of this view relative to its left position, in pixels.
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public float getTranslationX() {
return mRenderNode.getTranslationX();
}
@@ -16249,6 +16372,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* in pixels.
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public float getTranslationY() {
return mRenderNode.getTranslationY();
}
@@ -16280,6 +16404,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The depth of this view relative to its elevation.
*/
@ViewDebug.ExportedProperty(category = "drawing")
+ @InspectableProperty
public float getTranslationZ() {
return mRenderNode.getTranslationZ();
}
@@ -16324,6 +16449,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return StateListAnimator or null if it does not exists
* @see #setStateListAnimator(android.animation.StateListAnimator)
*/
+ @InspectableProperty
public StateListAnimator getStateListAnimator() {
return mStateListAnimator;
}
@@ -16437,6 +16563,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @see #setOutlineProvider(ViewOutlineProvider)
*/
+ @InspectableProperty
public ViewOutlineProvider getOutlineProvider() {
return mOutlineProvider;
}
@@ -16513,6 +16640,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing
* was set
*/
+ @InspectableProperty
public @ColorInt int getOutlineSpotShadowColor() {
return mRenderNode.getSpotShadowColor();
}
@@ -16541,6 +16669,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if
* nothing was set
*/
+ @InspectableProperty
public @ColorInt int getOutlineAmbientShadowColor() {
return mRenderNode.getAmbientShadowColor();
}
@@ -17720,6 +17849,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Get the fading edge flags, used for inspection.
+ *
+ * @return One of {@link #FADING_EDGE_NONE}, {@link #FADING_EDGE_VERTICAL},
+ * or {@link #FADING_EDGE_HORIZONTAL}
+ * @hide
+ */
+ @InspectableProperty(name = "requiresFadingEdge", flagMapping = {
+ @FlagMap(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"),
+ @FlagMap(target = FADING_EDGE_VERTICAL, name = "vertical"),
+ @FlagMap(target = FADING_EDGE_HORIZONTAL, name = "horizontal")
+ })
+ int getFadingEdge() {
+ return mViewFlags & FADING_EDGE_MASK;
+ }
+
+ /**
+ * Get the fading edge length, used for inspection
+ *
+ * @return The fading edge length or 0
+ * @hide
+ */
+ @InspectableProperty
+ int getFadingEdgeLength() {
+ if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) {
+ return mScrollCache.fadingEdgeLength;
+ }
+ return 0;
+ }
+
+ /**
* Returns the strength, or intensity, of the top faded edge. The strength is
* a value between 0.0 (no fade) and 1.0 (full fade). The default implementation
* returns 0.0 or 1.0 but no value in between.
@@ -17883,6 +18042,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade
*/
+ @InspectableProperty
public int getScrollBarDefaultDelayBeforeFade() {
return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() :
mScrollCache.scrollBarDefaultDelayBeforeFade;
@@ -17907,6 +18067,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_scrollbarFadeDuration
*/
+ @InspectableProperty
public int getScrollBarFadeDuration() {
return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() :
mScrollCache.scrollBarFadeDuration;
@@ -17931,6 +18092,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_scrollbarSize
*/
+ @InspectableProperty
public int getScrollBarSize() {
return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() :
mScrollCache.scrollBarSize;
@@ -17990,6 +18152,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"),
@ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET")
})
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"),
+ @EnumMap(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"),
+ @EnumMap(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"),
+ @EnumMap(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset")
+ })
@ScrollBarStyle
public int getScrollBarStyle() {
return mViewFlags & SCROLLBARS_STYLE_MASK;
@@ -19411,6 +19579,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #getDrawableState()
* @see #setDuplicateParentStateEnabled(boolean)
*/
+ @InspectableProperty(name = "duplicateParentState")
public boolean isDuplicateParentStateEnabled() {
return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE;
}
@@ -19452,7 +19621,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_layerType
*/
- public void setLayerType(int layerType, @Nullable Paint paint) {
+ public void setLayerType(@LayerType int layerType, @Nullable Paint paint) {
if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) {
throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, "
+ "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
@@ -19536,6 +19705,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #LAYER_TYPE_SOFTWARE
* @see #LAYER_TYPE_HARDWARE
*/
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = LAYER_TYPE_NONE, name = "none"),
+ @EnumMap(value = LAYER_TYPE_SOFTWARE, name = "software"),
+ @EnumMap(value = LAYER_TYPE_HARDWARE, name = "hardware")
+ })
+ @LayerType
public int getLayerType() {
return mLayerType;
}
@@ -22312,6 +22487,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_background
*/
+ @InspectableProperty
public Drawable getBackground() {
return mBackground;
}
@@ -22347,6 +22523,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_backgroundTint
* @see #setBackgroundTintList(ColorStateList)
*/
+ @InspectableProperty(name = "backgroundTint")
@Nullable
public ColorStateList getBackgroundTintList() {
return mBackgroundTint != null ? mBackgroundTint.mTintList : null;
@@ -22383,6 +22560,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setBackgroundTintMode(PorterDuff.Mode)
*/
@Nullable
+ @InspectableProperty
public PorterDuff.Mode getBackgroundTintMode() {
return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
}
@@ -22418,6 +22596,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @see #onDrawForeground(Canvas)
*/
+ @InspectableProperty
public Drawable getForeground() {
return mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
}
@@ -22496,6 +22675,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_foregroundGravity
*/
+ @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY)
public int getForegroundGravity() {
return mForegroundInfo != null ? mForegroundInfo.mGravity
: Gravity.START | Gravity.TOP;
@@ -22563,6 +22743,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_foregroundTint
* @see #setForegroundTintList(ColorStateList)
*/
+ @InspectableProperty(name = "foregroundTint")
@Nullable
public ColorStateList getForegroundTintList() {
return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
@@ -22602,6 +22783,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @attr ref android.R.styleable#View_foregroundTintMode
* @see #setForegroundTintMode(PorterDuff.Mode)
*/
+ @InspectableProperty
@Nullable
public PorterDuff.Mode getForegroundTintMode() {
return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
@@ -22846,6 +23028,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return the top padding in pixels
*/
+ @InspectableProperty
public int getPaddingTop() {
return mPaddingTop;
}
@@ -22857,6 +23040,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return the bottom padding in pixels
*/
+ @InspectableProperty
public int getPaddingBottom() {
return mPaddingBottom;
}
@@ -22868,6 +23052,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return the left padding in pixels
*/
+ @InspectableProperty
public int getPaddingLeft() {
if (!isPaddingResolved()) {
resolvePadding();
@@ -22897,6 +23082,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return the right padding in pixels
*/
+ @InspectableProperty
public int getPaddingRight() {
if (!isPaddingResolved()) {
resolvePadding();
@@ -23019,6 +23205,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return true if the view is selected, false otherwise
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty(hasAttributeId = false)
public boolean isSelected() {
return (mPrivateFlags & PFLAG_SELECTED) != 0;
}
@@ -23062,6 +23249,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return true if the view is activated, false otherwise
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty(hasAttributeId = false)
public boolean isActivated() {
return (mPrivateFlags & PFLAG_ACTIVATED) != 0;
}
@@ -23560,6 +23748,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@IdRes
@ViewDebug.CapturedViewProperty
+ @InspectableProperty
public int getId() {
return mID;
}
@@ -23584,6 +23773,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #getTag(int)
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty
public Object getTag() {
return mTag;
}
@@ -23780,6 +23970,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* if baseline alignment is not supported
*/
@ViewDebug.ExportedProperty(category = "layout")
+ @InspectableProperty
public int getBaseline() {
return -1;
}
@@ -24150,6 +24341,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_minHeight
*/
+ @InspectableProperty(name = "minHeight")
public int getMinimumHeight() {
return mMinHeight;
}
@@ -24180,6 +24372,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @attr ref android.R.styleable#View_minWidth
*/
+ @InspectableProperty(name = "minWidth")
public int getMinimumWidth() {
return mMinWidth;
}
@@ -25199,6 +25392,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return This view's over-scroll mode.
*/
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = OVER_SCROLL_ALWAYS, name = "always"),
+ @EnumMap(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"),
+ @EnumMap(value = OVER_SCROLL_NEVER, name = "never")
+ })
public int getOverScrollMode() {
return mOverScrollMode;
}
@@ -25257,6 +25455,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @see #setNestedScrollingEnabled(boolean)
*/
+ @InspectableProperty
public boolean isNestedScrollingEnabled() {
return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) ==
PFLAG3_NESTED_SCROLLING_ENABLED;
@@ -25586,6 +25785,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"),
@ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
})
+ @InspectableProperty(hasAttributeId = false, enumMapping = {
+ @EnumMap(value = TEXT_DIRECTION_INHERIT, name = "inherit"),
+ @EnumMap(value = TEXT_DIRECTION_LOCALE, name = "locale"),
+ @EnumMap(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
+ @EnumMap(value = TEXT_DIRECTION_LTR, name = "ltr"),
+ @EnumMap(value = TEXT_DIRECTION_RTL, name = "rtl"),
+ @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
+ @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
+ @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
+ })
@UnsupportedAppUsage
public int getRawTextDirection() {
return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT;
@@ -25653,6 +25862,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"),
@ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
})
+ @InspectableProperty(hasAttributeId = false, enumMapping = {
+ @EnumMap(value = TEXT_DIRECTION_LOCALE, name = "locale"),
+ @EnumMap(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
+ @EnumMap(value = TEXT_DIRECTION_LTR, name = "ltr"),
+ @EnumMap(value = TEXT_DIRECTION_RTL, name = "rtl"),
+ @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
+ @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
+ @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
+ })
public int getTextDirection() {
return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
}
@@ -25824,6 +26042,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"),
@ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
})
+ @InspectableProperty(hasAttributeId = false, enumMapping = {
+ @EnumMap(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"),
+ @EnumMap(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
+ @EnumMap(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
+ @EnumMap(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
+ @EnumMap(value = TEXT_ALIGNMENT_CENTER, name = "center"),
+ @EnumMap(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
+ @EnumMap(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
+ })
@TextAlignment
@UnsupportedAppUsage
public int getRawTextAlignment() {
@@ -25890,6 +26117,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"),
@ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
})
+ @InspectableProperty(enumMapping = {
+ @EnumMap(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
+ @EnumMap(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
+ @EnumMap(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
+ @EnumMap(value = TEXT_ALIGNMENT_CENTER, name = "center"),
+ @EnumMap(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
+ @EnumMap(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
+ })
@TextAlignment
public int getTextAlignment() {
return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >>
@@ -26122,6 +26357,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Gets the pointer icon for the current view.
*/
+ @InspectableProperty
public PointerIcon getPointerIcon() {
return mPointerIcon;
}
@@ -26672,6 +26908,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* if no name has been given.
*/
@ViewDebug.ExportedProperty
+ @InspectableProperty
public String getTransitionName() {
return mTransitionName;
}
@@ -28277,6 +28514,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @see #setTooltipText(CharSequence)
* @attr ref android.R.styleable#View_tooltipText
*/
+ @InspectableProperty
@Nullable
public CharSequence getTooltipText() {
return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null;
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index 8df83c0e5dff..797b861e9e70 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -76,7 +76,9 @@ public final class ActionsSuggestionsHelper {
return new ActionsSuggestionsModel.ConversationMessage[]{
new ActionsSuggestionsModel.ConversationMessage(
FIRST_NON_LOCAL_USER,
- lastMessage.getText().toString())};
+ lastMessage.getText().toString(),
+ 0,
+ null)};
}
// Encode the messages in the reverse order, stop whenever the Person object is missing.
@@ -89,7 +91,7 @@ public final class ActionsSuggestionsHelper {
}
nativeMessages.push(new ActionsSuggestionsModel.ConversationMessage(
personEncoder.encode(message.getAuthor()),
- message.getText().toString()));
+ message.getText().toString(), 0, null));
}
return nativeMessages.toArray(
new ActionsSuggestionsModel.ConversationMessage[nativeMessages.size()]);
diff --git a/core/java/android/webkit/TokenBindingService.java b/core/java/android/webkit/TokenBindingService.java
index b37e1b8962c5..4d2c04663579 100644
--- a/core/java/android/webkit/TokenBindingService.java
+++ b/core/java/android/webkit/TokenBindingService.java
@@ -16,12 +16,7 @@
package android.webkit;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.net.Uri;
-
-import java.security.KeyPair;
/**
* Enables the token binding procotol, and provides access to the keys. See
@@ -30,86 +25,9 @@ import java.security.KeyPair;
* All methods are required to be called on the UI thread where WebView is
* attached to the View hierarchy.
* @hide
+ * @deprecated this is no longer supported.
*/
@SystemApi
+@Deprecated
public abstract class TokenBindingService {
-
- public static final String KEY_ALGORITHM_RSA2048_PKCS_1_5 = "RSA2048_PKCS_1.5";
- public static final String KEY_ALGORITHM_RSA2048_PSS = "RSA2048PSS";
- public static final String KEY_ALGORITHM_ECDSAP256 = "ECDSAP256";
-
- /**
- * Provides the KeyPair information.
- */
- public static abstract class TokenBindingKey {
- /**
- * The public, private key pair.
- */
- public abstract KeyPair getKeyPair();
-
- /**
- * The algorithm that is used to generate the key pair.
- */
- public abstract String getAlgorithm();
- }
-
- /**
- * Returns the default TokenBinding service instance. At present there is
- * only one token binding service instance for all WebView instances,
- * however this restriction may be relaxed in the future.
- *
- * @return The default TokenBindingService instance.
- */
- public static TokenBindingService getInstance() {
- return WebViewFactory.getProvider().getTokenBindingService();
- }
-
- /**
- * Enables the token binding protocol. The token binding protocol
- * has to be enabled before creating any WebViews.
- *
- * @throws IllegalStateException if a WebView was already created.
- */
- public abstract void enableTokenBinding();
-
- /**
- * Retrieves the key pair for a given origin from the internal
- * TokenBinding key store asynchronously.
- *
- * The user can provide a list of acceptable algorithms for the retrieved
- * key pair. If a key pair exists and it is in the list of algorithms, then
- * the key is returned. If it is not in the list, no key is returned.
- *
- * If no key pair exists, WebView chooses an algorithm from the list, in
- * the order given, to generate a key.
- *
- * The user can pass {@code null} if any algorithm is acceptable.
- *
- * @param origin The origin for the server.
- * @param algorithm The list of algorithms. An IllegalArgumentException is thrown if array is
- * empty.
- * @param callback The callback that will be called when key is available.
- */
- public abstract void getKey(Uri origin,
- @Nullable String[] algorithm,
- @NonNull ValueCallback<TokenBindingKey> callback);
- /**
- * Deletes specified key (for use when associated cookie is cleared).
- *
- * @param origin The origin of the server.
- * @param callback The callback that will be called when key is deleted. The
- * callback parameter (Boolean) will indicate if operation is
- * successful or if failed.
- */
- public abstract void deleteKey(Uri origin,
- @Nullable ValueCallback<Boolean> callback);
-
- /**
- * Deletes all the keys (for use when cookies are cleared).
- *
- * @param callback The callback that will be called when keys are deleted.
- * The callback parameter (Boolean) will indicate if operation is
- * successful or if failed.
- */
- public abstract void deleteAllKeys(@Nullable ValueCallback<Boolean> callback);
}
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 4ff49ea1bbc3..6a1ed39e25b3 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -129,7 +129,8 @@ public interface WebViewFactoryProvider {
* Gets the TokenBindingService instance for this WebView implementation. The
* implementation must return the same instance on subsequent calls.
*
- * @return the TokenBindingService instance
+ * @deprecated this method only returns {@code null}
+ * @return the TokenBindingService instance (which is always {@code null})
*/
TokenBindingService getTokenBindingService();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index c6155ced9c9f..3c32bb29cf66 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2051,8 +2051,8 @@ public class Editor {
}
void updateCursorPosition() {
- if (mTextView.mCursorDrawableRes == 0) {
- mDrawableForCursor = null;
+ loadCursorDrawable();
+ if (mDrawableForCursor == null) {
return;
}
@@ -2462,10 +2462,7 @@ public class Editor {
}
private void updateCursorPosition(int top, int bottom, float horizontal) {
- if (mDrawableForCursor == null) {
- mDrawableForCursor = mTextView.getContext().getDrawable(
- mTextView.mCursorDrawableRes);
- }
+ loadCursorDrawable();
final int left = clampHorizontalPosition(mDrawableForCursor, horizontal);
final int width = mDrawableForCursor.getIntrinsicWidth();
mDrawableForCursor.setBounds(left, top - mTempRect.top, left + width,
@@ -5698,6 +5695,12 @@ public class Editor {
public boolean isActive();
}
+ void loadCursorDrawable() {
+ if (mDrawableForCursor == null) {
+ mDrawableForCursor = mTextView.getTextCursorDrawable();
+ }
+ }
+
private class InsertionPointCursorController implements CursorController {
private InsertionHandleView mHandle;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7b39efed0c3a..2dec4e87e662 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -18,6 +18,8 @@ package android.widget;
import android.annotation.ColorInt;
import android.annotation.DimenRes;
+import android.annotation.IntDef;
+import android.annotation.LayoutRes;
import android.annotation.NonNull;
import android.annotation.StyleRes;
import android.annotation.UnsupportedAppUsage;
@@ -131,6 +133,12 @@ public class RemoteViews implements Parcelable, Filter {
static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId";
/**
+ * The intent extra that contains {@code true} if inflating as dak text theme.
+ * @hide
+ */
+ static final String EXTRA_REMOTEADAPTER_ON_LIGHT_BACKGROUND = "remoteAdapterOnLightBackground";
+
+ /**
* The intent extra that contains the bounds for all shared elements.
*/
public static final String EXTRA_SHARED_ELEMENT_BOUNDS =
@@ -163,6 +171,36 @@ public class RemoteViews implements Parcelable, Filter {
private static final int SET_RIPPLE_DRAWABLE_COLOR_TAG = 21;
private static final int SET_INT_TAG_TAG = 22;
+ /** @hide **/
+ @IntDef(flag = true, value = {
+ FLAG_REAPPLY_DISALLOWED,
+ FLAG_WIDGET_IS_COLLECTION_CHILD,
+ FLAG_USE_LIGHT_BACKGROUND_LAYOUT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ApplyFlags {}
+ /**
+ * Whether reapply is disallowed on this remoteview. This maybe be true if some actions modify
+ * the layout in a way that isn't recoverable, since views are being removed.
+ * @hide
+ */
+ public static final int FLAG_REAPPLY_DISALLOWED = 1;
+ /**
+ * This flag indicates whether this RemoteViews object is being created from a
+ * RemoteViewsService for use as a child of a widget collection. This flag is used
+ * to determine whether or not certain features are available, in particular,
+ * setting on click extras and setting on click pending intents. The former is enabled,
+ * and the latter disabled when this flag is true.
+ * @hide
+ */
+ public static final int FLAG_WIDGET_IS_COLLECTION_CHILD = 2;
+ /**
+ * When this flag is set, the views is inflated with {@link #mLightBackgroundLayoutId} instead
+ * of {link #mLayoutId}
+ * @hide
+ */
+ public static final int FLAG_USE_LIGHT_BACKGROUND_LAYOUT = 4;
+
/**
* Application that hosts the remote views.
*
@@ -178,6 +216,11 @@ public class RemoteViews implements Parcelable, Filter {
private final int mLayoutId;
/**
+ * The resource ID of the layout file in dark text mode. (Added to the parcel)
+ */
+ private int mLightBackgroundLayoutId = 0;
+
+ /**
* An array of actions to perform on the view tree once it has been
* inflated
*/
@@ -197,12 +240,6 @@ public class RemoteViews implements Parcelable, Filter {
private boolean mIsRoot = true;
/**
- * Whether reapply is disallowed on this remoteview. This maybe be true if some actions modify
- * the layout in a way that isn't recoverable, since views are being removed.
- */
- private boolean mReapplyDisallowed;
-
- /**
* Constants to whether or not this RemoteViews is composed of a landscape and portrait
* RemoteViews.
*/
@@ -218,14 +255,8 @@ public class RemoteViews implements Parcelable, Filter {
@UnsupportedAppUsage
private RemoteViews mPortrait = null;
- /**
- * This flag indicates whether this RemoteViews object is being created from a
- * RemoteViewsService for use as a child of a widget collection. This flag is used
- * to determine whether or not certain features are available, in particular,
- * setting on click extras and setting on click pending intents. The former is enabled,
- * and the latter disabled when this flag is true.
- */
- private boolean mIsWidgetCollectionChild = false;
+ @ApplyFlags
+ private int mApplyFlags = 0;
/** Class cookies of the Parcel this instance was read from. */
private final Map<Class, Object> mClassCookies;
@@ -289,18 +320,15 @@ public class RemoteViews implements Parcelable, Filter {
*
* @hide
*/
- public void setReapplyDisallowed() {
- mReapplyDisallowed = true;
+ public void addFlags(@ApplyFlags int flags) {
+ mApplyFlags = mApplyFlags | flags;
}
/**
- * @return Whether it is disallowed to reapply another remoteview with the same layout as this
- * view. True if this remoteview has actions that destroyed view tree of the base layout.
- *
* @hide
*/
- public boolean isReapplyDisallowed() {
- return mReapplyDisallowed;
+ public boolean hasFlags(@ApplyFlags int flag) {
+ return (mApplyFlags & flag) == flag;
}
/**
@@ -768,7 +796,10 @@ public class RemoteViews implements Parcelable, Filter {
// Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent
// RemoteViewsService
AppWidgetHostView host = (AppWidgetHostView) rootParent;
- intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, host.getAppWidgetId());
+ intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, host.getAppWidgetId())
+ .putExtra(EXTRA_REMOTEADAPTER_ON_LIGHT_BACKGROUND,
+ hasFlags(FLAG_USE_LIGHT_BACKGROUND_LAYOUT));
+
if (target instanceof AbsListView) {
AbsListView v = (AbsListView) target;
v.setRemoteViewsAdapter(intent, isAsync);
@@ -829,7 +860,7 @@ public class RemoteViews implements Parcelable, Filter {
// If the view is an AdapterView, setting a PendingIntent on click doesn't make
// much sense, do they mean to set a PendingIntent template for the
// AdapterView's children?
- if (mIsWidgetCollectionChild) {
+ if (hasFlags(FLAG_WIDGET_IS_COLLECTION_CHILD)) {
Log.w(LOG_TAG, "Cannot SetOnClickResponse for collection item "
+ "(id: " + viewId + ")");
ApplicationInfo appInfo = root.getContext().getApplicationInfo();
@@ -843,7 +874,7 @@ public class RemoteViews implements Parcelable, Filter {
}
target.setTagInternal(R.id.pending_intent_tag, mResponse.mPendingIntent);
} else if (mResponse.mFillIntent != null) {
- if (!mIsWidgetCollectionChild) {
+ if (!hasFlags(FLAG_WIDGET_IS_COLLECTION_CHILD)) {
Log.e(LOG_TAG, "The method setOnClickFillInIntent is available "
+ "only from RemoteViewsFactory (ie. on collection items).");
return;
@@ -1545,6 +1576,7 @@ public class RemoteViews implements Parcelable, Filter {
viewId = parcel.readInt();
mIndex = parcel.readInt();
mNestedViews = new RemoteViews(parcel, bitmapCache, info, depth, classCookies);
+ mNestedViews.addFlags(mApplyFlags);
}
public void writeToParcel(Parcel dest, int flags) {
@@ -2190,7 +2222,7 @@ public class RemoteViews implements Parcelable, Filter {
*
* @hide
*/
- public RemoteViews(String packageName, int userId, int layoutId) {
+ public RemoteViews(String packageName, int userId, @LayoutRes int layoutId) {
this(getApplicationInfo(packageName, userId), layoutId);
}
@@ -2203,7 +2235,7 @@ public class RemoteViews implements Parcelable, Filter {
*
* @hide
*/
- protected RemoteViews(ApplicationInfo application, int layoutId) {
+ protected RemoteViews(ApplicationInfo application, @LayoutRes int layoutId) {
mApplication = application;
mLayoutId = layoutId;
mBitmapCache = new BitmapCache();
@@ -2229,7 +2261,8 @@ public class RemoteViews implements Parcelable, Filter {
throw new RuntimeException("Both RemoteViews must share the same package and user");
}
mApplication = portrait.mApplication;
- mLayoutId = portrait.getLayoutId();
+ mLayoutId = portrait.mLayoutId;
+ mLightBackgroundLayoutId = portrait.mLightBackgroundLayoutId;
mLandscape = landscape;
mPortrait = portrait;
@@ -2250,8 +2283,8 @@ public class RemoteViews implements Parcelable, Filter {
mApplication = src.mApplication;
mIsRoot = src.mIsRoot;
mLayoutId = src.mLayoutId;
- mIsWidgetCollectionChild = src.mIsWidgetCollectionChild;
- mReapplyDisallowed = src.mReapplyDisallowed;
+ mLightBackgroundLayoutId = src.mLightBackgroundLayoutId;
+ mApplyFlags = src.mApplyFlags;
mClassCookies = src.mClassCookies;
if (src.hasLandscapeAndPortraitLayouts()) {
@@ -2309,7 +2342,7 @@ public class RemoteViews implements Parcelable, Filter {
mApplication = parcel.readInt() == 0 ? info :
ApplicationInfo.CREATOR.createFromParcel(parcel);
mLayoutId = parcel.readInt();
- mIsWidgetCollectionChild = parcel.readInt() == 1;
+ mLightBackgroundLayoutId = parcel.readInt();
readActionsFromParcel(parcel, depth);
} else {
@@ -2318,9 +2351,10 @@ public class RemoteViews implements Parcelable, Filter {
mPortrait = new RemoteViews(parcel, mBitmapCache, mLandscape.mApplication, depth,
mClassCookies);
mApplication = mPortrait.mApplication;
- mLayoutId = mPortrait.getLayoutId();
+ mLayoutId = mPortrait.mLayoutId;
+ mLightBackgroundLayoutId = mPortrait.mLightBackgroundLayoutId;
}
- mReapplyDisallowed = parcel.readInt() == 0;
+ mApplyFlags = parcel.readInt();
}
private void readActionsFromParcel(Parcel parcel, int depth) {
@@ -2409,19 +2443,8 @@ public class RemoteViews implements Parcelable, Filter {
* @return the layout id.
*/
public int getLayoutId() {
- return mLayoutId;
- }
-
- /*
- * This flag indicates whether this RemoteViews object is being created from a
- * RemoteViewsService for use as a child of a widget collection. This flag is used
- * to determine whether or not certain features are available, in particular,
- * setting on click extras and setting on click pending intents. The former is enabled,
- * and the latter disabled when this flag is true.
- */
- @UnsupportedAppUsage
- void setIsWidgetCollectionChild(boolean isWidgetCollectionChild) {
- mIsWidgetCollectionChild = isWidgetCollectionChild;
+ return hasFlags(FLAG_USE_LIGHT_BACKGROUND_LAYOUT) && (mLightBackgroundLayoutId != 0)
+ ? mLightBackgroundLayoutId : mLayoutId;
}
/**
@@ -3292,6 +3315,33 @@ public class RemoteViews implements Parcelable, Filter {
setInt(viewId, "setLabelFor", labeledId);
}
+ /**
+ * Provides an alternate layout ID, which can be used to inflate this view. This layout will be
+ * used by the host when the widgets displayed on a light-background where foreground elements
+ * and text can safely draw using a dark color without any additional background protection.
+ */
+ public void setLightBackgroundLayoutId(@LayoutRes int layoutId) {
+ mLightBackgroundLayoutId = layoutId;
+ }
+
+ /**
+ * If this view supports dark text versions, creates a copy representing that version,
+ * otherwise returns itself.
+ * @hide
+ */
+ public RemoteViews getDarkTextViews() {
+ if (hasFlags(FLAG_USE_LIGHT_BACKGROUND_LAYOUT)) {
+ return this;
+ }
+
+ try {
+ addFlags(FLAG_USE_LIGHT_BACKGROUND_LAYOUT);
+ return new RemoteViews(this);
+ } finally {
+ mApplyFlags &= ~FLAG_USE_LIGHT_BACKGROUND_LAYOUT;
+ }
+ }
+
private RemoteViews getRemoteViewsToApply(Context context) {
if (hasLandscapeAndPortraitLayouts()) {
int orientation = context.getResources().getConfiguration().orientation;
@@ -3373,6 +3423,12 @@ public class RemoteViews implements Parcelable, Filter {
* @hide
*/
public interface OnViewAppliedListener {
+ /**
+ * Callback when the RemoteView has finished inflating,
+ * but no actions have been applied yet.
+ */
+ default void onViewInflated(View v) {};
+
void onViewApplied(View v);
void onError(Exception e);
@@ -3469,6 +3525,10 @@ public class RemoteViews implements Parcelable, Filter {
@Override
protected void onPostExecute(ViewTree viewTree) {
if (mError == null) {
+ if (mListener != null) {
+ mListener.onViewInflated(viewTree.mRoot);
+ }
+
try {
if (mActions != null) {
OnClickHandler handler = mHandler == null
@@ -3652,7 +3712,7 @@ public class RemoteViews implements Parcelable, Filter {
mApplication.writeToParcel(dest, flags);
}
dest.writeInt(mLayoutId);
- dest.writeInt(mIsWidgetCollectionChild ? 1 : 0);
+ dest.writeInt(mLightBackgroundLayoutId);
writeActionsToParcel(dest);
} else {
dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT);
@@ -3665,7 +3725,7 @@ public class RemoteViews implements Parcelable, Filter {
// Both RemoteViews already share the same package and user
mPortrait.writeToParcel(dest, flags | PARCELABLE_ELIDE_DUPLICATES);
}
- dest.writeInt(mReapplyDisallowed ? 1 : 0);
+ dest.writeInt(mApplyFlags);
}
private void writeActionsToParcel(Parcel parcel) {
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index d17c7c58ee74..c5cd1a1ece35 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -16,6 +16,9 @@
package android.widget;
+import static android.widget.RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID;
+import static android.widget.RemoteViews.EXTRA_REMOTEADAPTER_ON_LIGHT_BACKGROUND;
+
import android.annotation.UnsupportedAppUsage;
import android.annotation.WorkerThread;
import android.app.IServiceConnection;
@@ -97,6 +100,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
private final Context mContext;
private final Intent mIntent;
private final int mAppWidgetId;
+ private final boolean mOnLightBackground;
private final Executor mAsyncViewLoadExecutor;
private OnClickHandler mRemoteViewsOnClickHandler;
@@ -817,13 +821,13 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
throw new IllegalArgumentException("Non-null Intent must be specified.");
}
- mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
+ mAppWidgetId = intent.getIntExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
mRequestedViews = new RemoteViewsFrameLayoutRefSet();
+ mOnLightBackground = intent.getBooleanExtra(EXTRA_REMOTEADAPTER_ON_LIGHT_BACKGROUND, false);
// Strip the previously injected app widget id from service intent
- if (intent.hasExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID)) {
- intent.removeExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID);
- }
+ intent.removeExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID);
+ intent.removeExtra(EXTRA_REMOTEADAPTER_ON_LIGHT_BACKGROUND);
// Initialize the worker thread
mWorkerThread = new HandlerThread("RemoteViewsCache-loader");
@@ -1107,6 +1111,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
} else {
layout = new RemoteViewsFrameLayout(parent.getContext(), mCache);
layout.setExecutor(mAsyncViewLoadExecutor);
+ layout.setOnLightBackground(mOnLightBackground);
}
if (isInCache) {
diff --git a/core/java/android/widget/RemoteViewsListAdapter.java b/core/java/android/widget/RemoteViewsListAdapter.java
index e490458b38a8..b80fe4871616 100644
--- a/core/java/android/widget/RemoteViewsListAdapter.java
+++ b/core/java/android/widget/RemoteViewsListAdapter.java
@@ -85,7 +85,7 @@ public class RemoteViewsListAdapter extends BaseAdapter {
public View getView(int position, View convertView, ViewGroup parent) {
if (position < getCount()) {
RemoteViews rv = mRemoteViewsList.get(position);
- rv.setIsWidgetCollectionChild(true);
+ rv.addFlags(RemoteViews.FLAG_WIDGET_IS_COLLECTION_CHILD);
View v;
if (convertView != null && rv != null &&
convertView.getId() == rv.getLayoutId()) {
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index 2827f634b389..214e5cc01b9e 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -163,7 +163,7 @@ public abstract class RemoteViewsService extends Service {
try {
rv = mFactory.getViewAt(position);
if (rv != null) {
- rv.setIsWidgetCollectionChild(true);
+ rv.addFlags(RemoteViews.FLAG_WIDGET_IS_COLLECTION_CHILD);
}
} catch (Exception ex) {
Thread t = Thread.currentThread();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 085f8f1d678f..90cf871830fd 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -799,8 +799,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Although these fields are specific to editable text, they are not added to Editor because
// they are defined by the TextView's style and are theme-dependent.
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
int mCursorDrawableRes;
+ private Drawable mCursorDrawable;
// Note: this might be stale if setTextSelectHandleLeft is used. We could simplify the code
// by removing it, but we would break apps targeting <= P that use it by reflection.
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -3640,6 +3641,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* Returns the Drawable corresponding to the right handle used
* for selecting text.
+ * Note that any change applied to the handle Drawable will not be visible
+ * until the handle is hidden and then drawn again.
*
* @return the right text selection handle drawable
*
@@ -3655,6 +3658,58 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Sets the Drawable corresponding to the text cursor. The Drawable defaults to the
+ * value of the textCursorDrawable attribute.
+ * Note that any change applied to the cursor Drawable will not be visible
+ * until the cursor is hidden and then drawn again.
+ *
+ * @see #setTextCursorDrawable(int)
+ * @attr ref android.R.styleable#TextView_textCursorDrawable
+ */
+ public void setTextCursorDrawable(@NonNull Drawable textCursorDrawable) {
+ Preconditions.checkNotNull(textCursorDrawable,
+ "The cursor drawable should not be null.");
+ mCursorDrawable = textCursorDrawable;
+ mCursorDrawableRes = 0;
+ if (mEditor != null) {
+ mEditor.loadCursorDrawable();
+ }
+ }
+
+ /**
+ * Sets the Drawable corresponding to the text cursor. The Drawable defaults to the
+ * value of the textCursorDrawable attribute.
+ * Note that any change applied to the cursor Drawable will not be visible
+ * until the cursor is hidden and then drawn again.
+ *
+ * @see #setTextCursorDrawable(Drawable)
+ * @attr ref android.R.styleable#TextView_textCursorDrawable
+ */
+ public void setTextCursorDrawable(@DrawableRes int textCursorDrawable) {
+ Preconditions.checkArgumentPositive(textCursorDrawable,
+ "The cursor drawable should be a valid drawable resource id.");
+ setTextCursorDrawable(mContext.getDrawable(textCursorDrawable));
+ }
+
+ /**
+ * Returns the Drawable corresponding to the text cursor.
+ * Note that any change applied to the cursor Drawable will not be visible
+ * until the cursor is hidden and then drawn again.
+ *
+ * @return the text cursor drawable
+ *
+ * @see #setTextCursorDrawable(Drawable)
+ * @see #setTextCursorDrawable(int)
+ * @attr ref android.R.styleable#TextView_textCursorDrawable
+ */
+ @Nullable public Drawable getTextCursorDrawable() {
+ if (mCursorDrawable == null && mCursorDrawableRes != 0) {
+ mCursorDrawable = mContext.getDrawable(mCursorDrawableRes);
+ }
+ return mCursorDrawable;
+ }
+
+ /**
* Sets the text appearance from the specified style resource.
* <p>
* Use a framework-defined {@code TextAppearance} style like
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 875d7c9ee7a6..ff34036ce7e9 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -19,7 +19,9 @@ package com.android.internal.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Binder;
+import android.os.Process;
import android.os.SystemClock;
+import android.os.ThreadLocalWorkSource;
import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.ArrayMap;
@@ -78,8 +80,10 @@ public class BinderCallsStats implements BinderInternal.Observer {
private final Random mRandom;
private long mStartTime = System.currentTimeMillis();
private long mCallStatsCount = 0;
+ private boolean mAddDebugEntries = false;
private CachedDeviceState.Readonly mDeviceState;
+ private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch;
/** Injector for {@link BinderCallsStats}. */
public static class Injector {
@@ -93,7 +97,11 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
public void setDeviceState(@NonNull CachedDeviceState.Readonly deviceState) {
+ if (mBatteryStopwatch != null) {
+ mBatteryStopwatch.close();
+ }
mDeviceState = deviceState;
+ mBatteryStopwatch = deviceState.createTimeOnBatteryStopwatch();
}
@Override
@@ -155,8 +163,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
return;
}
- final boolean isWorkSourceSet = workSourceUid >= 0;
- final UidEntry uidEntry = getUidEntry(isWorkSourceSet ? workSourceUid : callingUid);
+ final UidEntry uidEntry = getUidEntry(workSourceUid);
uidEntry.callCount++;
if (recordCall) {
@@ -317,9 +324,30 @@ public class BinderCallsStats implements BinderInternal.Observer {
exported.methodName = methodName;
}
+ // Debug entries added to help validate the data.
+ if (mAddDebugEntries && mBatteryStopwatch != null) {
+ resultCallStats.add(createDebugEntry("start_time_millis", mStartTime));
+ resultCallStats.add(createDebugEntry("end_time_millis", System.currentTimeMillis()));
+ resultCallStats.add(
+ createDebugEntry("battery_time_millis", mBatteryStopwatch.getMillis()));
+ }
+
return resultCallStats;
}
+ private ExportedCallStat createDebugEntry(String variableName, long value) {
+ final int uid = Process.myUid();
+ final ExportedCallStat callStat = new ExportedCallStat();
+ callStat.className = "";
+ callStat.workSourceUid = uid;
+ callStat.callingUid = uid;
+ callStat.recordedCallCount = 1;
+ callStat.callCount = 1;
+ callStat.methodName = "__DEBUG_" + variableName;
+ callStat.latencyMicros = value;
+ return callStat;
+ }
+
/** @hide */
public ArrayMap<String, Integer> getExportedExceptionStats() {
synchronized (mLock) {
@@ -341,6 +369,8 @@ public class BinderCallsStats implements BinderInternal.Observer {
long totalCpuTime = 0;
pw.print("Start time: ");
pw.println(DateFormat.format("yyyy-MM-dd HH:mm:ss", mStartTime));
+ pw.print("On battery time (ms): ");
+ pw.println(mBatteryStopwatch != null ? mBatteryStopwatch.getMillis() : 0);
pw.println("Sampling interval period: " + mPeriodicSamplingInterval);
final List<UidEntry> entries = new ArrayList<>();
@@ -434,7 +464,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
protected int getWorkSourceUid() {
- return Binder.getCallingWorkSourceUid();
+ return ThreadLocalWorkSource.getUid();
}
protected long getElapsedRealtimeMicro() {
@@ -457,6 +487,10 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
}
+ public void setAddDebugEntries(boolean addDebugEntries) {
+ mAddDebugEntries = addDebugEntries;
+ }
+
/**
* Sets the maximum number of items to track.
*/
@@ -496,6 +530,9 @@ public class BinderCallsStats implements BinderInternal.Observer {
mUidEntries.clear();
mExceptionCounts.clear();
mStartTime = System.currentTimeMillis();
+ if (mBatteryStopwatch != null) {
+ mBatteryStopwatch.reset();
+ }
}
}
diff --git a/core/java/com/android/internal/os/CachedDeviceState.java b/core/java/com/android/internal/os/CachedDeviceState.java
index 8c90682ec281..334cca317c30 100644
--- a/core/java/com/android/internal/os/CachedDeviceState.java
+++ b/core/java/com/android/internal/os/CachedDeviceState.java
@@ -16,8 +16,14 @@
package com.android.internal.os;
+
+import android.os.SystemClock;
+
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.ArrayList;
+
/**
* Stores the device state (e.g. charging/on battery, screen on/off) to be shared with
* the System Server telemetry services.
@@ -27,6 +33,9 @@ import com.android.internal.annotations.VisibleForTesting;
public class CachedDeviceState {
private volatile boolean mScreenInteractive;
private volatile boolean mCharging;
+ private final Object mStopwatchesLock = new Object();
+ @GuardedBy("mStopwatchLock")
+ private final ArrayList<TimeInStateStopwatch> mOnBatteryStopwatches = new ArrayList<>();
public CachedDeviceState() {
mCharging = true;
@@ -44,7 +53,23 @@ public class CachedDeviceState {
}
public void setCharging(boolean charging) {
- mCharging = charging;
+ if (mCharging != charging) {
+ mCharging = charging;
+ updateStopwatches(/* shouldStart= */ !charging);
+ }
+ }
+
+ private void updateStopwatches(boolean shouldStart) {
+ synchronized (mStopwatchesLock) {
+ final int size = mOnBatteryStopwatches.size();
+ for (int i = 0; i < size; i++) {
+ if (shouldStart) {
+ mOnBatteryStopwatches.get(i).start();
+ } else {
+ mOnBatteryStopwatches.get(i).stop();
+ }
+ }
+ }
}
public Readonly getReadonlyClient() {
@@ -62,5 +87,74 @@ public class CachedDeviceState {
public boolean isScreenInteractive() {
return mScreenInteractive;
}
+
+ /** Creates a {@link TimeInStateStopwatch stopwatch} that tracks the time on battery. */
+ public TimeInStateStopwatch createTimeOnBatteryStopwatch() {
+ synchronized (mStopwatchesLock) {
+ final TimeInStateStopwatch stopwatch = new TimeInStateStopwatch();
+ mOnBatteryStopwatches.add(stopwatch);
+ if (!mCharging) {
+ stopwatch.start();
+ }
+ return stopwatch;
+ }
+ }
+ }
+
+ /** Tracks the time the device spent in a given state. */
+ public class TimeInStateStopwatch implements AutoCloseable {
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private long mStartTimeMillis;
+ @GuardedBy("mLock")
+ private long mTotalTimeMillis;
+
+ /** Returns the time in state since the last call to {@link TimeInStateStopwatch#reset}. */
+ public long getMillis() {
+ synchronized (mLock) {
+ return mTotalTimeMillis + elapsedTime();
+ }
+ }
+
+ /** Resets the time in state to 0 without stopping the timer if it's started. */
+ public void reset() {
+ synchronized (mLock) {
+ mTotalTimeMillis = 0;
+ mStartTimeMillis = isRunning() ? SystemClock.elapsedRealtime() : 0;
+ }
+ }
+
+ private void start() {
+ synchronized (mLock) {
+ if (!isRunning()) {
+ mStartTimeMillis = SystemClock.elapsedRealtime();
+ }
+ }
+ }
+
+ private void stop() {
+ synchronized (mLock) {
+ if (isRunning()) {
+ mTotalTimeMillis += elapsedTime();
+ mStartTimeMillis = 0;
+ }
+ }
+ }
+
+ private long elapsedTime() {
+ return isRunning() ? SystemClock.elapsedRealtime() - mStartTimeMillis : 0;
+ }
+
+ @VisibleForTesting
+ public boolean isRunning() {
+ return mStartTimeMillis > 0;
+ }
+
+ @Override
+ public void close() {
+ synchronized (mStopwatchesLock) {
+ mOnBatteryStopwatches.remove(this);
+ }
+ }
}
}
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index cf2a297bb6a5..01fd8ba58c74 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -49,6 +49,7 @@ public class LooperStats implements Looper.Observer {
private final int mEntriesSizeCap;
private int mSamplingInterval;
private CachedDeviceState.Readonly mDeviceState;
+ private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch;
private long mStartTime = System.currentTimeMillis();
private boolean mAddDebugEntries = false;
@@ -58,7 +59,12 @@ public class LooperStats implements Looper.Observer {
}
public void setDeviceState(@NonNull CachedDeviceState.Readonly deviceState) {
+ if (mBatteryStopwatch != null) {
+ mBatteryStopwatch.close();
+ }
+
mDeviceState = deviceState;
+ mBatteryStopwatch = deviceState.createTimeOnBatteryStopwatch();
}
public void setAddDebugEntries(boolean addDebugEntries) {
@@ -148,9 +154,11 @@ public class LooperStats implements Looper.Observer {
maybeAddSpecialEntry(exportedEntries, mOverflowEntry);
maybeAddSpecialEntry(exportedEntries, mHashCollisionEntry);
// Debug entries added to help validate the data.
- if (mAddDebugEntries) {
+ if (mAddDebugEntries && mBatteryStopwatch != null) {
exportedEntries.add(createDebugEntry("start_time_millis", mStartTime));
exportedEntries.add(createDebugEntry("end_time_millis", System.currentTimeMillis()));
+ exportedEntries.add(
+ createDebugEntry("battery_time_millis", mBatteryStopwatch.getMillis()));
}
return exportedEntries;
}
@@ -159,7 +167,7 @@ public class LooperStats implements Looper.Observer {
final Entry entry = new Entry("__DEBUG_" + variableName);
entry.messageCount = 1;
entry.recordedMessageCount = 1;
- entry.maxDelayMillis = value;
+ entry.totalLatencyMicro = value;
return new ExportedEntry(entry);
}
@@ -168,6 +176,10 @@ public class LooperStats implements Looper.Observer {
return mStartTime;
}
+ public long getBatteryTimeMillis() {
+ return mBatteryStopwatch != null ? mBatteryStopwatch.getMillis() : 0;
+ }
+
private void maybeAddSpecialEntry(List<ExportedEntry> exportedEntries, Entry specialEntry) {
synchronized (specialEntry) {
if (specialEntry.messageCount > 0 || specialEntry.exceptionCount > 0) {
@@ -188,6 +200,9 @@ public class LooperStats implements Looper.Observer {
mOverflowEntry.reset();
}
mStartTime = System.currentTimeMillis();
+ if (mBatteryStopwatch != null) {
+ mBatteryStopwatch.reset();
+ }
}
public void setSamplingInterval(int samplingInterval) {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 600b1b324257..53b56f2e937a 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -29,7 +29,7 @@ oneway interface IStatusBar
{
void setIcon(String slot, in StatusBarIcon icon);
void removeIcon(String slot);
- void disable(int state1, int state2);
+ void disable(int displayId, int state1, int state2);
void animateExpandNotificationsPanel();
void animateExpandSettingsPanel(String subPanel);
void animateCollapsePanels();
@@ -38,8 +38,9 @@ oneway interface IStatusBar
void showWirelessChargingAnimation(int batteryLevel);
/**
- * Notifies the status bar of a System UI visibility flag change.
+ * Notifies System UI side of a visibility flag change on the specified display.
*
+ * @param displayId the id of the display to notify
* @param vis the visibility flags except SYSTEM_UI_FLAG_LIGHT_STATUS_BAR which will be reported
* separately in fullscreenStackVis and dockedStackVis
* @param fullscreenStackVis the flags which only apply in the region of the fullscreen stack,
@@ -50,13 +51,13 @@ oneway interface IStatusBar
* @param fullscreenBounds the current bounds of the fullscreen stack, in screen coordinates
* @param dockedBounds the current bounds of the docked stack, in screen coordinates
*/
- void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
- in Rect fullscreenBounds, in Rect dockedBounds);
+ void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis,
+ int mask, in Rect fullscreenBounds, in Rect dockedBounds);
- void topAppWindowChanged(boolean menuVisible);
- void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
+ void topAppWindowChanged(int displayId, boolean menuVisible);
+ void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
- void setWindowState(int window, int state);
+ void setWindowState(int display, int window, int state);
void showRecentApps(boolean triggeredFromAltTab);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
@@ -70,30 +71,38 @@ oneway interface IStatusBar
void toggleKeyboardShortcutsMenu(int deviceId);
/**
- * Notifies the status bar that an app transition is pending to delay applying some flags with
- * visual impact until {@link #appTransitionReady} is called.
+ * Notifies System UI on the specified display that an app transition is pending to delay
+ * applying some flags with visual impact until {@link #appTransitionReady} is called.
+ *
+ * @param displayId the id of the display to notify
*/
- void appTransitionPending();
+ void appTransitionPending(int displayId);
/**
- * Notifies the status bar that a pending app transition has been cancelled.
+ * Notifies System UI on the specified display that a pending app transition has been cancelled.
+ *
+ * @param displayId the id of the display to notify
*/
- void appTransitionCancelled();
+ void appTransitionCancelled(int displayId);
/**
- * Notifies the status bar that an app transition is now being executed.
+ * Notifies System UI on the specified display that an app transition is now being executed.
*
+ * @param displayId the id of the display to notify
* @param statusBarAnimationsStartTime the desired start time for all visual animations in the
* status bar caused by this app transition in uptime millis
* @param statusBarAnimationsDuration the duration for all visual animations in the status
* bar caused by this app transition in millis
*/
- void appTransitionStarting(long statusBarAnimationsStartTime, long statusBarAnimationsDuration);
+ void appTransitionStarting(int displayId, long statusBarAnimationsStartTime,
+ long statusBarAnimationsDuration);
/**
- * Notifies the status bar that an app transition is done.
+ * Notifies System UI on the specified display that an app transition is done.
+ *
+ * @param displayId the id of the display to notify
*/
- void appTransitionFinished();
+ void appTransitionFinished(int displayId);
void showAssistDisclosure();
void startAssist(in Bundle args);
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index bf82dc610ad4..5118e5f0473e 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -41,6 +41,7 @@ interface IStatusBarService
void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription);
void setIconVisibility(String slot, boolean visible);
void removeIcon(String slot);
+ // TODO(b/117478341): support back button change when IME is showing on a external display.
void setImeWindowStatus(in IBinder token, int vis, int backDisposition,
boolean showImeSwitcher);
void expandSettingsPanel(String subPanel);
@@ -69,7 +70,7 @@ interface IStatusBarService
void onNotificationSmartRepliesAdded(in String key, in int replyCount);
void onNotificationSmartReplySent(in String key, in int replyIndex, in CharSequence reply, boolean generatedByAssistant);
void onNotificationSettingsViewed(String key);
- void setSystemUiVisibility(int vis, int mask, String cause);
+ void setSystemUiVisibility(int displayId, int vis, int mask, String cause);
void onGlobalActionsShown();
void onGlobalActionsHidden();
diff --git a/core/java/com/android/internal/widget/ImageMessageConsumer.java b/core/java/com/android/internal/widget/ImageMessageConsumer.java
new file mode 100644
index 000000000000..01613dcdf3fa
--- /dev/null
+++ b/core/java/com/android/internal/widget/ImageMessageConsumer.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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.widget;
+
+/**
+ * An interface for the class who will use the {@link ImageResolver} to resolve images.
+ */
+public interface ImageMessageConsumer {
+ /**
+ * Set the custom {@link ImageResolver} other than {@link LocalImageResolver}.
+ * @param resolver An image resolver that has custom implementation.
+ */
+ void setImageResolver(ImageResolver resolver);
+}
diff --git a/core/java/com/android/internal/widget/ImageResolver.java b/core/java/com/android/internal/widget/ImageResolver.java
new file mode 100644
index 000000000000..45885257ad8d
--- /dev/null
+++ b/core/java/com/android/internal/widget/ImageResolver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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.widget;
+
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+
+/**
+ * An interface for image resolvers that have custom implementations like cache mechanisms.
+ */
+public interface ImageResolver {
+ /**
+ * Load an image from specified uri.
+ * @param uri Uri of the target image.
+ * @return Target image in Drawable.
+ */
+ Drawable loadImage(Uri uri);
+}
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index 71d3bb5d6b5c..2302de2cd058 100644
--- a/core/java/com/android/internal/widget/LocalImageResolver.java
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -17,7 +17,6 @@
package com.android.internal.widget;
import android.annotation.Nullable;
-import android.app.Notification;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
diff --git a/core/java/com/android/internal/widget/MessagingImageMessage.java b/core/java/com/android/internal/widget/MessagingImageMessage.java
index 607a3a9ab542..64650a7ebc2f 100644
--- a/core/java/com/android/internal/widget/MessagingImageMessage.java
+++ b/core/java/com/android/internal/widget/MessagingImageMessage.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pools;
@@ -57,6 +58,7 @@ public class MessagingImageMessage extends ImageView implements MessagingMessage
private int mActualWidth;
private int mActualHeight;
private boolean mIsIsolated;
+ private ImageResolver mImageResolver;
public MessagingImageMessage(@NonNull Context context) {
this(context, null);
@@ -96,11 +98,16 @@ public class MessagingImageMessage extends ImageView implements MessagingMessage
MessagingMessage.super.setMessage(message);
Drawable drawable;
try {
- drawable = LocalImageResolver.resolveImage(message.getDataUri(), getContext());
+ Uri uri = message.getDataUri();
+ drawable = mImageResolver != null ? mImageResolver.loadImage(uri) :
+ LocalImageResolver.resolveImage(uri, getContext());
} catch (IOException | SecurityException e) {
e.printStackTrace();
return false;
}
+ if (drawable == null) {
+ return false;
+ }
int intrinsicHeight = drawable.getIntrinsicHeight();
if (intrinsicHeight == 0) {
Log.w(TAG, "Drawable with 0 intrinsic height was returned");
@@ -114,7 +121,7 @@ public class MessagingImageMessage extends ImageView implements MessagingMessage
}
static MessagingMessage createMessage(MessagingLayout layout,
- Notification.MessagingStyle.Message m) {
+ Notification.MessagingStyle.Message m, ImageResolver resolver) {
MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout();
MessagingImageMessage createdMessage = sInstancePool.acquire();
if (createdMessage == null) {
@@ -125,6 +132,7 @@ public class MessagingImageMessage extends ImageView implements MessagingMessage
false);
createdMessage.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
}
+ createdMessage.setImageResolver(resolver);
boolean created = createdMessage.setMessage(m);
if (!created) {
createdMessage.recycle();
@@ -133,6 +141,10 @@ public class MessagingImageMessage extends ImageView implements MessagingMessage
return createdMessage;
}
+ private void setImageResolver(ImageResolver resolver) {
+ mImageResolver = resolver;
+ }
+
@Override
protected void onDraw(Canvas canvas) {
canvas.save();
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 0f2e9c52add0..07d0d7d91997 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -57,7 +57,7 @@ import java.util.regex.Pattern;
* messages and adapts the layout accordingly.
*/
@RemoteViews.RemoteView
-public class MessagingLayout extends FrameLayout {
+public class MessagingLayout extends FrameLayout implements ImageMessageConsumer {
private static final float COLOR_SHIFT_AMOUNT = 60;
/**
@@ -95,6 +95,7 @@ public class MessagingLayout extends FrameLayout {
private Person mUser;
private CharSequence mNameReplacement;
private boolean mDisplayImagesAtEnd;
+ private ImageResolver mImageResolver;
public MessagingLayout(@NonNull Context context) {
super(context);
@@ -167,6 +168,11 @@ public class MessagingLayout extends FrameLayout {
bind(newMessages, newHistoricMessages, showSpinner);
}
+ @Override
+ public void setImageResolver(ImageResolver resolver) {
+ mImageResolver = resolver;
+ }
+
private void addRemoteInputHistoryToMessages(
List<Notification.MessagingStyle.Message> newMessages,
CharSequence[] remoteInputHistory) {
@@ -463,12 +469,12 @@ public class MessagingLayout extends FrameLayout {
*/
private List<MessagingMessage> createMessages(
List<Notification.MessagingStyle.Message> newMessages, boolean historic) {
- List<MessagingMessage> result = new ArrayList<>();;
+ List<MessagingMessage> result = new ArrayList<>();
for (int i = 0; i < newMessages.size(); i++) {
Notification.MessagingStyle.Message m = newMessages.get(i);
MessagingMessage message = findAndRemoveMatchingMessage(m);
if (message == null) {
- message = MessagingMessage.createMessage(this, m);
+ message = MessagingMessage.createMessage(this, m, mImageResolver);
}
message.setIsHistoric(historic);
result.add(message);
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index 74d0aae3634b..c32d3705bba7 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -33,9 +33,9 @@ public interface MessagingMessage extends MessagingLinearLayout.MessagingChild {
String IMAGE_MIME_TYPE_PREFIX = "image/";
static MessagingMessage createMessage(MessagingLayout layout,
- Notification.MessagingStyle.Message m) {
+ Notification.MessagingStyle.Message m, ImageResolver resolver) {
if (hasImage(m) && !ActivityManager.isLowRamDeviceStatic()) {
- return MessagingImageMessage.createMessage(layout, m);
+ return MessagingImageMessage.createMessage(layout, m, resolver);
} else {
return MessagingTextMessage.createMessage(layout, m);
}
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
index dcb787462a13..cfe742d0134d 100644
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
@@ -59,7 +59,7 @@ struct HarfBuzzFontData {
static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint, hb_position_t* width, hb_glyph_extents_t* extents)
{
ALOG_ASSERT(codepoint <= 0xFFFF);
- paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint->setTextEncoding(kGlyphID_SkTextEncoding);
SkScalar skWidth;
SkRect skBounds;
@@ -84,7 +84,7 @@ static hb_bool_t harfbuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoin
{
HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData);
SkPaint* paint = hbFontData->m_paint;
- paint->setTextEncoding(SkPaint::kUTF32_TextEncoding);
+ paint->setTextEncoding(kUTF32_SkTextEncoding);
if (unicode > 0x10ffff) {
unicode = 0xfffd;
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index a8b0640c3a73..c249e209b29f 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -71,7 +71,7 @@ static JMetricsID gFontMetricsInt_fieldID;
static void defaultSettingsForAndroid(Paint* paint) {
// GlyphID encoding is required because we are using Harfbuzz shaping
- paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
+ paint->setTextEncoding(kGlyphID_SkTextEncoding);
}
namespace PaintGlue {
@@ -321,7 +321,7 @@ namespace PaintGlue {
x += MinikinUtils::xOffsetForTextAlign(paint, layout);
Paint::Align align = paint->getTextAlign();
paint->setTextAlign(Paint::kLeft_Align);
- paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
+ paint->setTextEncoding(kGlyphID_SkTextEncoding);
GetTextFunctor f(layout, path, x, y, paint, glyphs, pos);
MinikinUtils::forFontRun(layout, paint, f);
paint->setTextAlign(align);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 8e9a0bf61517..02867304af36 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -102,6 +102,11 @@ enum MountExternalKind {
MOUNT_EXTERNAL_FULL = 4,
};
+// Must match values in com.android.internal.os.Zygote.
+enum RuntimeFlags : uint32_t {
+ DEBUG_ENABLE_JDWP = 1,
+};
+
static void RuntimeAbort(JNIEnv* env, int line, const char* msg) {
std::ostringstream oss;
oss << __FILE__ << ":" << line << ": " << msg;
@@ -254,6 +259,36 @@ static bool SetRLimits(JNIEnv* env, jobjectArray javaRlimits, std::string* error
return true;
}
+static void EnableDebugger() {
+ // To let a non-privileged gdbserver attach to this
+ // process, we must set our dumpable flag.
+ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
+ ALOGE("prctl(PR_SET_DUMPABLE) failed");
+ }
+
+ // A non-privileged native debugger should be able to attach to the debuggable app, even if Yama
+ // is enabled (see kernel/Documentation/security/Yama.txt).
+ if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0) == -1) {
+ // if Yama is off prctl(PR_SET_PTRACER) returns EINVAL - don't log in this
+ // case since it's expected behaviour.
+ if (errno != EINVAL) {
+ ALOGE("prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) failed");
+ }
+ }
+
+ // We don't want core dumps, though, so set the soft limit on core dump size
+ // to 0 without changing the hard limit.
+ rlimit rl;
+ if (getrlimit(RLIMIT_CORE, &rl) == -1) {
+ ALOGE("getrlimit(RLIMIT_CORE) failed");
+ } else {
+ rl.rlim_cur = 0;
+ if (setrlimit(RLIMIT_CORE, &rl) == -1) {
+ ALOGE("setrlimit(RLIMIT_CORE) failed");
+ }
+ }
+}
+
// The debug malloc library needs to know whether it's the zygote or a child.
extern "C" int gMallocLeakZygoteChild;
@@ -956,6 +991,11 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
}
}
+ // Set process properties to enable debugging if required.
+ if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_JDWP) != 0) {
+ EnableDebugger();
+ }
+
if (NeedsNoRandomizeWorkaround()) {
// Work around ARM kernel ASLR lossage (http://b/5817320).
int old_personality = personality(0xffffffff);
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 3a908dc28e4c..8e4eb0018999 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -38,6 +38,12 @@ enum PageId {
// Unknown page. Should not be used in production code.
PAGE_UNKNOWN = 0;
+ // OPEN: Settings > Connected Devices > Bluetooth > (click on details link for a paired device)
+ BLUETOOTH_DEVICE_DETAILS = 1009;
+
+ // OPEN: Settings > Connected devices > Bluetooth > Pair new device
+ BLUETOOTH_PAIRING = 1018;
+
// OPEN: Settings homepage
SETTINGS_HOMEPAGE = 1502;
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d917536b1715..4c1fc5c89b0d 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -761,6 +761,13 @@ message GlobalSettingsProto {
}
optional SmartSelection smart_selection = 108;
+ message SmartSuggestions {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto service_explicitly_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional SmartSuggestions smart_suggestions = 145;
+
message Sms {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -869,6 +876,8 @@ message GlobalSettingsProto {
// Temperature at which the high temperature warning notification should
// be shown.
optional SettingProto warning_temperature_level = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // USB temperature at which the high temperature alarm notification should be shown.
+ optional SettingProto usb_alarm_temperature_level = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional TemperatureWarning temperature_warning = 119;
@@ -991,5 +1000,5 @@ message GlobalSettingsProto {
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 145;
+ // Next tag = 146;
}
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index ab50ad147107..60561bd9dbc5 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -185,6 +185,7 @@ message ProcessRecordProto {
optional int32 app_id = 5;
optional int32 isolated_app_id = 6;
optional bool persistent = 7;
+ optional int32 lru_index = 8;
}
message BroadcastRecordProto {
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index e83a2bfac77a..231caabe0335 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -215,6 +215,34 @@ message ConstantsProto {
// The fraction of a prefetch job's running window that must pass before
// we consider matching it against a metered network.
optional double conn_prefetch_relax_frac = 22;
+ // Whether to use heartbeats or rolling window for quota management. True
+ // will use heartbeats, false will use a rolling window.
+ optional bool use_heartbeats = 23;
+
+ message QuotaController {
+ // How much time each app will have to run jobs within their standby bucket window.
+ optional int64 allowed_time_per_period_ms = 1;
+ // How much time the package should have before transitioning from out-of-quota to in-quota.
+ // This should not affect processing if the package is already in-quota.
+ optional int64 in_quota_buffer_ms = 2;
+ // The quota window size of the particular standby bucket. Apps in this standby bucket are
+ // expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ // WINDOW_SIZE_MS.
+ optional int64 active_window_size_ms = 3;
+ // The quota window size of the particular standby bucket. Apps in this standby bucket are
+ // expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ // WINDOW_SIZE_MS.
+ optional int64 working_window_size_ms = 4;
+ // The quota window size of the particular standby bucket. Apps in this standby bucket are
+ // expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ // WINDOW_SIZE_MS.
+ optional int64 frequent_window_size_ms = 5;
+ // The quota window size of the particular standby bucket. Apps in this standby bucket are
+ // expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ // WINDOW_SIZE_MS.
+ optional int64 rare_window_size_ms = 6;
+ }
+ optional QuotaController quota_controller = 24;
}
message StateControllerProto {
@@ -357,6 +385,65 @@ message StateControllerProto {
}
repeated TrackedJob tracked_jobs = 2;
}
+ message QuotaController {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional bool is_charging = 1;
+ optional bool is_in_parole = 2;
+
+ message TrackedJob {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional JobStatusShortInfoProto info = 1;
+ optional int32 source_uid = 2;
+ optional JobStatusDumpProto.Bucket effective_standby_bucket = 3;
+ optional bool has_quota = 4;
+ // The amount of time that this job has remaining in its quota. This
+ // can be negative if the job is out of quota.
+ optional int64 remaining_quota_ms = 5;
+ }
+ repeated TrackedJob tracked_jobs = 3;
+
+ message Package {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 user_id = 1;
+ optional string name = 2;
+ }
+
+ message TimingSession {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int64 start_time_elapsed = 1;
+ optional int64 end_time_elapsed = 2;
+ optional int32 job_count = 3;
+ }
+
+ message Timer {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional Package pkg = 1;
+ // True if the Timer is actively tracking jobs.
+ optional bool is_active = 2;
+ // The time this timer last became active. Only valid if is_active is true.
+ optional int64 start_time_elapsed = 3;
+ // How many are currently running. Valid only if the device is_active is true.
+ optional int32 job_count = 4;
+ // All of the jobs that the Timer is currently tracking.
+ repeated JobStatusShortInfoProto running_jobs = 5;
+ }
+
+ message PackageStats {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional Package pkg = 1;
+
+ optional Timer timer = 2;
+
+ repeated TimingSession saved_sessions = 3;
+ }
+ repeated PackageStats package_stats = 4;
+ }
message StorageController {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -403,8 +490,10 @@ message StateControllerProto {
ContentObserverController content_observer = 4;
DeviceIdleJobsController device_idle = 5;
IdleController idle = 6;
+ QuotaController quota = 9;
StorageController storage = 7;
TimeController time = 8;
+ // Next tag: 10
}
}
@@ -603,11 +692,13 @@ message JobStatusDumpProto {
CONSTRAINT_CONNECTIVITY = 7;
CONSTRAINT_CONTENT_TRIGGER = 8;
CONSTRAINT_DEVICE_NOT_DOZING = 9;
+ CONSTRAINT_WITHIN_QUOTA = 10;
}
repeated Constraint required_constraints = 7;
repeated Constraint satisfied_constraints = 8;
repeated Constraint unsatisfied_constraints = 9;
optional bool is_doze_whitelisted = 10;
+ optional bool is_uid_active = 26;
message ImplicitConstraints {
// The device isn't Dozing or this job will be in the foreground. This
@@ -627,6 +718,7 @@ message JobStatusDumpProto {
TRACKING_IDLE = 3;
TRACKING_STORAGE = 4;
TRACKING_TIME = 5;
+ TRACKING_QUOTA = 6;
}
// Controllers that are currently tracking the job.
repeated TrackingController tracking_controllers = 11;
@@ -660,6 +752,7 @@ message JobStatusDumpProto {
NEVER = 4;
}
optional Bucket standby_bucket = 17;
+ optional bool is_exempted_from_app_standby = 27;
optional int64 enqueue_duration_ms = 18;
// Can be negative if the earliest runtime deadline has passed.
@@ -674,5 +767,5 @@ message JobStatusDumpProto {
optional int64 internal_flags = 24;
- // Next tag: 26
+ // Next tag: 28
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index df17b4c453d9..3018614fee61 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3387,6 +3387,13 @@
<permission android:name="android.permission.CONTROL_DISPLAY_SATURATION"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to control display color transformations.
+ <p>Not for use by third-party applications.</p>
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows an application to collect usage infomation about brightness slider changes.
<p>Not for use by third-party applications.</p>
@hide
diff --git a/core/res/res/layout/notification_material_reply_text.xml b/core/res/res/layout/notification_material_reply_text.xml
index 71632a206e3c..2b15dceeb469 100644
--- a/core/res/res/layout/notification_material_reply_text.xml
+++ b/core/res/res/layout/notification_material_reply_text.xml
@@ -39,7 +39,7 @@
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:visibility="gone"
- android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
android:singleLine="true" />
<TextView
@@ -48,7 +48,7 @@
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:visibility="gone"
- android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
android:singleLine="true" />
<LinearLayout
@@ -64,7 +64,7 @@
android:layout_weight="1"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:layout_gravity="center"
- android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Reply"
android:singleLine="true" />
<ProgressBar
android:id="@+id/notification_material_reply_progress"
diff --git a/core/res/res/layout/notification_template_ambient_header.xml b/core/res/res/layout/notification_template_ambient_header.xml
index c00acd5bfc60..be5d9b436b79 100644
--- a/core/res/res/layout/notification_template_ambient_header.xml
+++ b/core/res/res/layout/notification_template_ambient_header.xml
@@ -24,5 +24,5 @@
android:layout_height="wrap_content">
<include
layout="@layout/notification_template_header"
- android:theme="@style/Theme.Material.Notification.Ambient"/>
+ android:theme="@style/Theme.DeviceDefault.Notification.Ambient"/>
</FrameLayout>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 4bf1ad6651ee..5ba1cf259551 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -17,7 +17,7 @@
<!-- extends ViewGroup -->
<NotificationHeaderView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:theme="@style/Theme.Material.Notification"
+ android:theme="@style/Theme.DeviceDefault.Notification"
android:id="@+id/notification_header"
android:orientation="horizontal"
android:layout_width="wrap_content"
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index c8864c2f829d..2c6064ea6243 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -24,7 +24,7 @@
android:paddingEnd="@dimen/notification_extra_margin_ambient"
>
<include layout="@layout/notification_template_ambient_header"
- android:theme="@style/Theme.Material.Notification.Ambient" />
+ android:theme="@style/Theme.DeviceDefault.Notification.Ambient" />
<LinearLayout
android:id="@+id/notification_action_list_margin_target"
@@ -51,8 +51,7 @@
android:orientation="vertical"
>
<TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.Material.Notification.Title"
- android:fontFamily="sans-serif"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top|center_horizontal"
@@ -65,7 +64,7 @@
<TextView android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:textAppearance="@style/TextAppearance.Material.Notification"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification"
android:singleLine="false"
android:layout_weight="1"
android:gravity="top|center_horizontal"
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index 26eb4e7b2c6c..d5ea96f6bc16 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -53,7 +53,7 @@
android:layout_marginTop="@dimen/notification_progress_margin_top"
android:layout_marginBottom="6dp"/>
<com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
- style="@style/Widget.Material.Notification.Text"
+ style="@style/Widget.DeviceDefault.Notification.Text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/notification_text_margin_top"
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index d6f0e1df430e..eb8925819cd3 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -53,7 +53,7 @@
android:layout_marginTop="@dimen/notification_progress_margin_top"
android:layout_marginBottom="2dp"/>
<TextView android:id="@+id/inbox_text0"
- style="@style/Widget.Material.Notification.Text"
+ style="@style/Widget.DeviceDefault.Notification.Text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:singleLine="true"
@@ -62,7 +62,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text1"
- style="@style/Widget.Material.Notification.Text"
+ style="@style/Widget.DeviceDefault.Notification.Text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:singleLine="true"
@@ -71,7 +71,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text2"
- style="@style/Widget.Material.Notification.Text"
+ style="@style/Widget.DeviceDefault.Notification.Text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:singleLine="true"
@@ -80,7 +80,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text3"
- style="@style/Widget.Material.Notification.Text"
+ style="@style/Widget.DeviceDefault.Notification.Text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:singleLine="true"
@@ -89,7 +89,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text4"
- style="@style/Widget.Material.Notification.Text"
+ style="@style/Widget.DeviceDefault.Notification.Text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:singleLine="true"
@@ -98,7 +98,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text5"
- style="@style/Widget.Material.Notification.Text"
+ style="@style/Widget.DeviceDefault.Notification.Text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:singleLine="true"
@@ -107,7 +107,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text6"
- style="@style/Widget.Material.Notification.Text"
+ style="@style/Widget.DeviceDefault.Notification.Text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:singleLine="true"
diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml
index 0717d962d69f..483b479538a1 100644
--- a/core/res/res/layout/notification_template_messaging_group.xml
+++ b/core/res/res/layout/notification_template_messaging_group.xml
@@ -34,7 +34,7 @@
android:orientation="vertical">
<com.android.internal.widget.ImageFloatingTextView
android:id="@+id/message_name"
- style="@style/Widget.Material.Notification.MessagingName"
+ style="@style/Widget.DeviceDefault.Notification.MessagingName"
android:layout_width="wrap_content"
android:textAlignment="viewStart"
/>
diff --git a/core/res/res/layout/notification_template_messaging_text_message.xml b/core/res/res/layout/notification_template_messaging_text_message.xml
index 3611186e279b..26c081e1f3d7 100644
--- a/core/res/res/layout/notification_template_messaging_text_message.xml
+++ b/core/res/res/layout/notification_template_messaging_text_message.xml
@@ -18,5 +18,5 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/message_text"
android:textAlignment="viewStart"
- style="@style/Widget.Material.Notification.MessagingText"
+ style="@style/Widget.DeviceDefault.Notification.MessagingText"
/>
diff --git a/core/res/res/layout/notification_template_part_line1.xml b/core/res/res/layout/notification_template_part_line1.xml
index 6459bb8019b4..622f080653a4 100644
--- a/core/res/res/layout/notification_template_part_line1.xml
+++ b/core/res/res/layout/notification_template_part_line1.xml
@@ -22,7 +22,7 @@
android:orientation="horizontal"
>
<TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.Material.Notification.Title"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
@@ -31,7 +31,7 @@
android:textAlignment="viewStart"
/>
<TextView android:id="@+id/text_line_1"
- style="@style/Widget.Material.Notification.Text"
+ style="@style/Widget.DeviceDefault.Notification.Text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end|bottom"
diff --git a/core/res/res/layout/notification_template_text.xml b/core/res/res/layout/notification_template_text.xml
index 3b27666ef6ff..01b14ae0592d 100644
--- a/core/res/res/layout/notification_template_text.xml
+++ b/core/res/res/layout/notification_template_text.xml
@@ -15,7 +15,7 @@
~ limitations under the License
-->
<com.android.internal.widget.ImageFloatingTextView xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/Widget.Material.Notification.Text"
+ style="@style/Widget.DeviceDefault.Notification.Text"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0cd6bc5cd700..c62071bdf552 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3350,6 +3350,14 @@
-->
<string name="config_defaultTextClassifierPackage" translatable="false"></string>
+ <!-- The package name for the system's smart suggestion service.
+ This service must be trusted, as it can be activated without explicit consent of the user.
+ If no service with the specified name exists on the device, content capture and
+ smart suggestions will be disabled.
+ Example: "com.android.intelligence/.SmartSuggestionsService"
+ -->
+ <string name="config_defaultSmartSuggestionsService" translatable="false"></string>
+
<!-- Whether the device uses the default focus highlight when focus state isn't specified. -->
<bool name="config_useDefaultFocusHighlight">true</bool>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index d722961981c5..c03d570001d6 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -113,6 +113,15 @@ easier.
<style name="Widget.DeviceDefault.ListView.White" parent="Widget.Material.ListView.White"/>
<style name="Widget.DeviceDefault.MediaRouteButton" parent="Widget.Material.MediaRouteButton" />
<style name="Widget.DeviceDefault.NumberPicker" parent="Widget.Material.NumberPicker"/>
+ <style name="Widget.DeviceDefault.Notification.Text" parent="Widget.Material.Notification.Text">
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault.Notification</item>
+ </style>
+ <style name="Widget.DeviceDefault.Notification.MessagingText" parent="Widget.Material.Notification.MessagingText">
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault.Notification</item>
+ </style>
+ <style name="Widget.DeviceDefault.Notification.MessagingName" parent="Widget.Material.Notification.MessagingName">
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault.Notification.Title</item>
+ </style>
<style name="Widget.DeviceDefault.PreferenceFrameLayout" parent="Widget.Material.PreferenceFrameLayout"/>
<style name="Widget.DeviceDefault.ProgressBar.Inverse" parent="Widget.Material.ProgressBar.Inverse"/>
<style name="Widget.DeviceDefault.ProgressBar.Large.Inverse" parent="Widget.Material.ProgressBar.Large.Inverse"/>
@@ -250,6 +259,16 @@ easier.
<style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title" parent="TextAppearance.Material.Widget.ActionBar.Title">
<item name="fontFamily">@string/config_headlineFontFamilyMedium</item>
</style>
+
+ <!-- Notification Styles -->
+ <style name="TextAppearance.DeviceDefault.Notification" parent="TextAppearance.Material.Notification">
+ <item name="fontFamily">@string/config_headlineFontFamily</item>
+ </style>
+ <style name="TextAppearance.DeviceDefault.Notification.Title" parent="TextAppearance.Material.Notification.Title">
+ <item name="fontFamily">@string/config_headlineFontFamilyMedium</item>
+ </style>
+ <style name="TextAppearance.DeviceDefault.Notification.Reply" parent="TextAppearance.Material.Notification.Reply" />
+
<style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle" parent="TextAppearance.Material.Widget.ActionBar.Subtitle"/>
<style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title" parent="TextAppearance.Material.Widget.ActionMode.Title"/>
<style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle" parent="TextAppearance.Material.Widget.ActionMode.Subtitle"/>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 67b3c92e69db..5a7199d6f445 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -1313,4 +1313,5 @@ please see styles_device_defaults.xml.
<item name="gravity">top|center_horizontal</item>
</style>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 01422c8ffd97..6854a84e950a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3265,6 +3265,7 @@
<java-symbol type="string" name="notification_channel_do_not_disturb" />
<java-symbol type="string" name="config_defaultAutofillService" />
<java-symbol type="string" name="config_defaultTextClassifierPackage" />
+ <java-symbol type="string" name="config_defaultSmartSuggestionsService" />
<java-symbol type="string" name="notification_channel_foreground_service" />
<java-symbol type="string" name="foreground_service_app_in_background" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index fa009bd60c72..fec101a6fff3 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1724,4 +1724,10 @@ easier.
<item name="layout_gravity">center</item>
</style>
+ <style name="Theme.DeviceDefault.Notification" parent="@style/Theme.Material.Notification">
+ </style>
+
+ <style name="Theme.DeviceDefault.Notification.Ambient" parent="@style/Theme.Material.Notification.Ambient">
+ </style>
+
</resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index a8f9e8a5891b..ed9c3d5b2b70 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -415,6 +415,7 @@ public class SettingsBackupTest {
Settings.Global.SHOW_TEMPERATURE_WARNING,
Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
+ Settings.Global.SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED,
Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED,
Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT,
@@ -477,6 +478,7 @@ public class SettingsBackupTest {
Settings.Global.USER_SWITCHER_ENABLED,
Settings.Global.NETWORK_ACCESS_TIMEOUT_MS,
Settings.Global.WARNING_TEMPERATURE,
+ Settings.Global.USB_ALARM_TEMPERATURE,
Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED,
Settings.Global.WEBVIEW_MULTIPROCESS,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index fbcb629f043f..aec4571252e7 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -373,7 +373,7 @@ public class TextClassifierTest {
public void testSuggestConversationActions_textReplyOnly_maxThree() {
if (isTextClassifierDisabled()) return;
ConversationActions.Message message =
- new ConversationActions.Message.Builder().setText("Hello").build();
+ new ConversationActions.Message.Builder().setText("Where are you?").build();
ConversationActions.TypeConfig typeConfig =
new ConversationActions.TypeConfig.Builder().includeTypesFromTextClassifier(false)
.setIncludedTypes(
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index 8691e73f82fb..e2618191235d 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -17,6 +17,7 @@
package com.android.internal.os;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
@@ -387,8 +388,7 @@ public class BinderCallsStatsTest {
@Test
public void testNoDataCollectedBeforeInitialDeviceStateSet() {
- TestBinderCallsStats bcs = new TestBinderCallsStats();
- bcs.setDeviceState(null);
+ TestBinderCallsStats bcs = new TestBinderCallsStats(null);
bcs.setDetailedTracking(true);
Binder binder = new Binder();
CallSession callSession = bcs.callStarted(binder, 1);
@@ -528,22 +528,6 @@ public class BinderCallsStatsTest {
}
@Test
- public void testCallingUidUsedWhenWorkSourceNotSet() {
- TestBinderCallsStats bcs = new TestBinderCallsStats();
- bcs.setDetailedTracking(true);
- bcs.workSourceUid = -1;
-
- Binder binder = new Binder();
- CallSession callSession = bcs.callStarted(binder, 1);
- bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE);
-
- assertEquals(1, bcs.getExportedCallStats().size());
- BinderCallsStats.ExportedCallStat stat = bcs.getExportedCallStats().get(0);
- assertEquals(CALLING_UID, stat.workSourceUid);
- assertEquals(CALLING_UID, stat.callingUid);
- }
-
- @Test
public void testGetExportedStatsWithoutCalls() {
TestBinderCallsStats bcs = new TestBinderCallsStats();
Binder binder = new Binder();
@@ -613,6 +597,27 @@ public class BinderCallsStatsTest {
assertEquals(CALLING_UID, callStats.callingUid);
}
+ @Test
+ public void testAddsDebugEntries() {
+ long startTime = System.currentTimeMillis();
+ TestBinderCallsStats bcs = new TestBinderCallsStats();
+ bcs.setAddDebugEntries(true);
+ ArrayList<BinderCallsStats.ExportedCallStat> callStats = bcs.getExportedCallStats();
+ assertEquals(3, callStats.size());
+ BinderCallsStats.ExportedCallStat debugEntry1 = callStats.get(0);
+ assertEquals("", debugEntry1.className);
+ assertEquals("__DEBUG_start_time_millis", debugEntry1.methodName);
+ assertTrue(startTime <= debugEntry1.latencyMicros);
+ BinderCallsStats.ExportedCallStat debugEntry2 = callStats.get(1);
+ assertEquals("", debugEntry2.className);
+ assertEquals("__DEBUG_end_time_millis", debugEntry2.methodName);
+ assertTrue(debugEntry1.latencyMicros <= debugEntry2.latencyMicros);
+ BinderCallsStats.ExportedCallStat debugEntry3 = callStats.get(2);
+ assertEquals("", debugEntry3.className);
+ assertEquals("__DEBUG_battery_time_millis", debugEntry3.methodName);
+ assertTrue(debugEntry3.latencyMicros >= 0);
+ }
+
class TestBinderCallsStats extends BinderCallsStats {
public int callingUid = CALLING_UID;
public int workSourceUid = WORKSOURCE_UID;
@@ -620,6 +625,10 @@ public class BinderCallsStatsTest {
public long elapsedTime = 0;
TestBinderCallsStats() {
+ this(mDeviceState);
+ }
+
+ TestBinderCallsStats(CachedDeviceState deviceState) {
// Make random generator not random.
super(new Injector() {
public Random getRandomGenerator() {
@@ -633,7 +642,10 @@ public class BinderCallsStatsTest {
}
});
setSamplingInterval(1);
- setDeviceState(mDeviceState.getReadonlyClient());
+ setAddDebugEntries(false);
+ if (deviceState != null) {
+ setDeviceState(deviceState.getReadonlyClient());
+ }
}
@Override
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 31dde5c79f27..f26dfad0b037 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -273,8 +273,7 @@ public final class LooperStatsTest {
@Test
public void testDataNotCollectedBeforeDeviceStateSet() {
- TestableLooperStats looperStats = new TestableLooperStats(1, 100);
- looperStats.setDeviceState(null);
+ TestableLooperStats looperStats = new TestableLooperStats(1, 100, null);
Object token1 = looperStats.messageDispatchStarting();
looperStats.messageDispatched(token1, mHandlerFirst.obtainMessage(1000));
@@ -439,15 +438,19 @@ public final class LooperStatsTest {
looperStats.messageDispatched(token, message);
List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
- assertThat(entries).hasSize(3);
+ assertThat(entries).hasSize(4);
LooperStats.ExportedEntry debugEntry1 = entries.get(1);
assertThat(debugEntry1.handlerClassName).isEqualTo("");
assertThat(debugEntry1.messageName).isEqualTo("__DEBUG_start_time_millis");
- assertThat(debugEntry1.maxDelayMillis).isEqualTo(looperStats.getStartTimeMillis());
+ assertThat(debugEntry1.totalLatencyMicros).isEqualTo(looperStats.getStartTimeMillis());
LooperStats.ExportedEntry debugEntry2 = entries.get(2);
assertThat(debugEntry2.handlerClassName).isEqualTo("");
assertThat(debugEntry2.messageName).isEqualTo("__DEBUG_end_time_millis");
- assertThat(debugEntry2.maxDelayMillis).isAtLeast(looperStats.getStartTimeMillis());
+ assertThat(debugEntry2.totalLatencyMicros).isAtLeast(looperStats.getStartTimeMillis());
+ LooperStats.ExportedEntry debugEntry3 = entries.get(3);
+ assertThat(debugEntry3.handlerClassName).isEqualTo("");
+ assertThat(debugEntry3.messageName).isEqualTo("__DEBUG_battery_time_millis");
+ assertThat(debugEntry3.totalLatencyMicros).isAtLeast(0L);
}
private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
@@ -468,10 +471,16 @@ public final class LooperStatsTest {
private int mSamplingInterval;
TestableLooperStats(int samplingInterval, int sizeCap) {
+ this(samplingInterval, sizeCap, mDeviceState);
+ }
+
+ TestableLooperStats(int samplingInterval, int sizeCap, CachedDeviceState deviceState) {
super(samplingInterval, sizeCap);
- this.mSamplingInterval = samplingInterval;
- this.setDeviceState(mDeviceState.getReadonlyClient());
- this.setAddDebugEntries(false);
+ mSamplingInterval = samplingInterval;
+ setAddDebugEntries(false);
+ if (deviceState != null) {
+ setDeviceState(deviceState.getReadonlyClient());
+ }
}
void tickRealtime(long micros) {
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 9e4ea32ed605..f2373446924a 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -281,6 +281,7 @@ applications that come with the platform
<permission name="android.permission.WRITE_APN_SETTINGS"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
</privapp-permissions>
<privapp-permissions package="com.android.settings.intelligence">
@@ -408,6 +409,7 @@ applications that come with the platform
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
<permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/>
+ <permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
</privapp-permissions>
<privapp-permissions package="com.android.tv">
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index dea2f45e9d33..cb12a7c6ba6b 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -19,6 +19,7 @@ package android.graphics.drawable;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.app.ActivityThread;
import android.content.pm.ActivityInfo.Config;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -150,11 +151,14 @@ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback
*/
AdaptiveIconDrawable(@Nullable LayerState state, @Nullable Resources res) {
mLayerState = createConstantState(state, res);
-
- if (sMask == null) {
- sMask = PathParser.createPathFromPathData(
- Resources.getSystem().getString(R.string.config_icon_mask));
- }
+ // config_icon_mask from context bound resource may have been chaged using
+ // OverlayManager. Read that one first.
+ Resources r = ActivityThread.currentActivityThread() == null
+ ? Resources.getSystem()
+ : ActivityThread.currentActivityThread().getApplication().getResources();
+ // TODO: either make sMask update only when config_icon_mask changes OR
+ // get rid of it all-together in layoutlib
+ sMask = PathParser.createPathFromPathData(r.getString(R.string.config_icon_mask));
mMask = new Path(sMask);
mMaskScaleOnly = new Path(mMask);
mMaskMatrix = new Matrix();
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 68d216d286cf..c20c720eadbb 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -583,7 +583,65 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
loaded_package->dynamic_package_map_.emplace_back(std::move(package_name),
dtohl(entry_iter->packageId));
}
+ } break;
+
+ case RES_TABLE_OVERLAYABLE_TYPE: {
+ const ResTable_overlayable_header* header =
+ child_chunk.header<ResTable_overlayable_header>();
+ if (header == nullptr) {
+ LOG(ERROR) << "RES_TABLE_OVERLAYABLE_TYPE too small.";
+ return {};
+ }
+
+ // Iterate over the overlayable policy chunks
+ ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
+ while (overlayable_iter.HasNext()) {
+ const Chunk overlayable_child_chunk = overlayable_iter.Next();
+
+ switch (overlayable_child_chunk.type()) {
+ case RES_TABLE_OVERLAYABLE_POLICY_TYPE: {
+ const ResTable_overlayable_policy_header* policy_header =
+ overlayable_child_chunk.header<ResTable_overlayable_policy_header>();
+ if (policy_header == nullptr) {
+ LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small.";
+ return {};
+ }
+
+ if ((overlayable_child_chunk.data_size() / sizeof(ResTable_ref))
+ < dtohl(policy_header->entry_count)) {
+ LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small to hold entries.";
+ return {};
+ }
+
+ // Retrieve all the ids belonging to this policy
+ std::unordered_set<uint32_t> ids;
+ const auto ids_begin =
+ reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr());
+ const auto ids_end = ids_begin + dtohl(policy_header->entry_count);
+ for (auto id_iter = ids_begin; id_iter != ids_end; ++id_iter) {
+ ids.insert(dtohl(id_iter->ident));
+ }
+
+ // Add the pairing of overlayable properties to resource ids to the package
+ OverlayableInfo overlayable_info;
+ overlayable_info.policy_flags = policy_header->policy_flags;
+ loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
+ break;
+ }
+
+ default:
+ LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+ break;
+ }
+ }
+ if (overlayable_iter.HadError()) {
+ LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_POLICY_TYPE: %s",
+ overlayable_iter.GetLastError().c_str());
+ if (overlayable_iter.HadFatalError()) {
+ return {};
+ }
+ }
} break;
default:
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 2fe98b00f3a2..63b25270f116 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -7076,7 +7076,7 @@ public:
}
}
- const auto& getTypeMapping() const {
+ const std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>>& getTypeMapping() const {
return mTypeMapping->mData;
}
@@ -7137,9 +7137,6 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
const PackageGroup* packageGroup = mPackageGroups[0];
- // the number of resources overlaid that were not explicitly marked overlayable
- size_t forcedOverlayCount = 0u;
-
// find the resources that exist in both packages
auto typeMapping = std::make_unique<IdmapTypeMapping>();
for (size_t typeIndex = 0; typeIndex < packageGroup->types.size(); ++typeIndex) {
@@ -7170,11 +7167,6 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
continue;
}
- if ((dtohl(typeConfigs->typeSpecFlags[entryIndex]) &
- ResTable_typeSpec::SPEC_OVERLAYABLE) == 0) {
- ++forcedOverlayCount;
- }
-
typeMapping->add(target_resid, overlay_resid);
}
}
@@ -7243,10 +7235,6 @@ status_t ResTable::createIdmap(const ResTable& targetResTable,
typeData += entryCount * 2;
}
- if (forcedOverlayCount > 0) {
- ALOGW("idmap: overlaid %zu resources not marked overlayable", forcedOverlayCount);
- }
-
return NO_ERROR;
}
diff --git a/libs/androidfw/include/androidfw/Chunk.h b/libs/androidfw/include/androidfw/Chunk.h
index 99a52dc9244e..a0f23433c676 100644
--- a/libs/androidfw/include/androidfw/Chunk.h
+++ b/libs/androidfw/include/androidfw/Chunk.h
@@ -89,7 +89,9 @@ class ChunkIterator {
len_(len),
last_error_(nullptr) {
CHECK(next_chunk_ != nullptr) << "data can't be nullptr";
- VerifyNextChunk();
+ if (len_ != 0) {
+ VerifyNextChunk();
+ }
}
Chunk Next();
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 349b379778a6..8c5c3b7d3858 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -20,6 +20,7 @@
#include <memory>
#include <set>
#include <vector>
+#include <unordered_set>
#include "android-base/macros.h"
@@ -76,6 +77,10 @@ struct TypeSpec {
// TypeSpecPtr is a managed pointer that knows how to delete itself.
using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+struct OverlayableInfo {
+ uint32_t policy_flags;
+};
+
class LoadedPackage {
public:
class iterator {
@@ -216,6 +221,18 @@ class LoadedPackage {
}
}
+ // Retrieve the overlayable properties of the specified resource. If the resource is not
+ // overlayable, this will return a null pointer.
+ const OverlayableInfo* GetOverlayableInfo(uint32_t resid) const {
+ for (const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>& overlayable_info_ids
+ : overlayable_infos_) {
+ if (overlayable_info_ids.second.find(resid) != overlayable_info_ids.second.end()) {
+ return &overlayable_info_ids.first;
+ }
+ }
+ return nullptr;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
@@ -233,6 +250,7 @@ class LoadedPackage {
ByteBucketArray<TypeSpecPtr> type_specs_;
ByteBucketArray<uint32_t> resource_ids_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
+ std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
};
// Read-only view into a resource table. This class validates all data
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index ad33fcfa2429..91261aa3e4f9 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -234,7 +234,9 @@ enum {
RES_TABLE_PACKAGE_TYPE = 0x0200,
RES_TABLE_TYPE_TYPE = 0x0201,
RES_TABLE_TYPE_SPEC_TYPE = 0x0202,
- RES_TABLE_LIBRARY_TYPE = 0x0203
+ RES_TABLE_LIBRARY_TYPE = 0x0203,
+ RES_TABLE_OVERLAYABLE_TYPE = 0x0204,
+ RES_TABLE_OVERLAYABLE_POLICY_TYPE = 0x0205,
};
/**
@@ -1354,10 +1356,6 @@ struct ResTable_typeSpec
enum : uint32_t {
// Additional flag indicating an entry is public.
SPEC_PUBLIC = 0x40000000u,
-
- // Additional flag indicating an entry is overlayable at runtime.
- // Added in Android-P.
- SPEC_OVERLAYABLE = 0x80000000u,
};
};
@@ -1607,6 +1605,49 @@ struct ResTable_lib_entry
uint16_t packageName[128];
};
+/**
+ * Specifies the set of resources that are explicitly allowed to be overlaid by RROs.
+ */
+struct ResTable_overlayable_header
+{
+ struct ResChunk_header header;
+};
+
+/**
+ * Holds a list of resource ids that are protected from being overlaid by a set of policies. If
+ * the overlay fulfils at least one of the policies, then the overlay can overlay the list of
+ * resources.
+ */
+struct ResTable_overlayable_policy_header
+{
+ struct ResChunk_header header;
+
+ enum PolicyFlags {
+ // Any overlay can overlay these resources.
+ POLICY_PUBLIC = 0x00000001,
+
+ // The overlay must reside of the system partition or must have existed on the system partition
+ // before an upgrade to overlay these resources.
+ POLICY_SYSTEM_PARTITION = 0x00000002,
+
+ // The overlay must reside of the vendor partition or must have existed on the vendor partition
+ // before an upgrade to overlay these resources.
+ POLICY_VENDOR_PARTITION = 0x00000004,
+
+ // The overlay must reside of the product partition or must have existed on the product
+ // partition before an upgrade to overlay these resources.
+ POLICY_PRODUCT_PARTITION = 0x00000008,
+
+ // The overlay must reside of the product services partition or must have existed on the product
+ // services partition before an upgrade to overlay these resources.
+ POLICY_PRODUCT_SERVICES_PARTITION = 0x00000010,
+ };
+ uint32_t policy_flags;
+
+ // The number of ResTable_ref that follow this header.
+ uint32_t entry_count;
+};
+
struct alignas(uint32_t) Idmap_header {
// Always 0x504D4449 ('IDMP')
uint32_t magic;
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index ffa48367c252..441356b95d36 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -22,12 +22,14 @@
#include "TestHelpers.h"
#include "data/basic/R.h"
#include "data/libclient/R.h"
+#include "data/overlayable/R.h"
#include "data/sparse/R.h"
#include "data/styles/R.h"
namespace app = com::android::app;
namespace basic = com::android::basic;
namespace libclient = com::android::libclient;
+namespace overlayable = com::android::overlayable;
namespace sparse = com::android::sparse;
using ::android::base::ReadFileToString;
@@ -273,10 +275,44 @@ TEST(LoadedArscTest, LoadOverlay) {
ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0000), NotNull());
}
-// structs with size fields (like Res_value, ResTable_entry) should be
-// backwards and forwards compatible (aka checking the size field against
-// sizeof(Res_value) might not be backwards compatible.
-TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
+TEST(LoadedArscTest, LoadOverlayable) {
+ std::string contents;
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
+ "resources.arsc", &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc =
+ LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/,
+ false /*load_as_shared_library*/);
+
+ ASSERT_THAT(loaded_arsc, NotNull());
+ const LoadedPackage* package = loaded_arsc->GetPackageById(
+ get_package_id(overlayable::R::string::not_overlayable));
+
+ const OverlayableInfo* info = package->GetOverlayableInfo(
+ overlayable::R::string::not_overlayable);
+ ASSERT_THAT(info, IsNull());
+
+ info = package->GetOverlayableInfo(overlayable::R::string::overlayable1);
+ ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
+
+ info = package->GetOverlayableInfo(overlayable::R::string::overlayable2);
+ ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->policy_flags,
+ Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION
+ | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
+
+ info = package->GetOverlayableInfo(overlayable::R::string::overlayable3);
+ ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->policy_flags,
+ Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION
+ | ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION
+ | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
+
+ info = package->GetOverlayableInfo(overlayable::R::string::overlayable4);
+ ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
+}
TEST(LoadedArscTest, ResourceIdentifierIterator) {
std::string contents;
@@ -326,4 +362,9 @@ TEST(LoadedArscTest, ResourceIdentifierIterator) {
ASSERT_EQ(end, iter);
}
+// structs with size fields (like Res_value, ResTable_entry) should be
+// backwards and forwards compatible (aka checking the size field against
+// sizeof(Res_value) might not be backwards compatible.
+TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
+
} // namespace android
diff --git a/libs/androidfw/tests/data/overlay/overlay.apk b/libs/androidfw/tests/data/overlay/overlay.apk
index 33f961117c44..d37874dcbb40 100644
--- a/libs/androidfw/tests/data/overlay/overlay.apk
+++ b/libs/androidfw/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/AndroidManifest.xml b/libs/androidfw/tests/data/overlayable/AndroidManifest.xml
new file mode 100644
index 000000000000..abc2a454e845
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlayable">
+ <application>
+ </application>
+</manifest>
diff --git a/libs/androidfw/tests/data/overlayable/R.h b/libs/androidfw/tests/data/overlayable/R.h
new file mode 100644
index 000000000000..e46e264da318
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/R.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef TESTS_DATA_OVERLAYABLE_R_H_
+#define TESTS_DATA_OVERLAYABLE_R_H_
+
+#include <cstdint>
+
+namespace com {
+namespace android {
+namespace overlayable {
+
+struct R {
+ struct string {
+ enum : uint32_t {
+ not_overlayable = 0x7f010000,
+ overlayable1 = 0x7f010001,
+ overlayable2 = 0x7f010002,
+ overlayable3 = 0x7f010003,
+ overlayable4 = 0x7f010004,
+ };
+ };
+};
+
+} // namespace overlayable
+} // namespace android
+} // namespace com
+
+#endif /* TESTS_DATA_OVERLAYABLE_R_H_ */
diff --git a/libs/androidfw/tests/data/overlayable/build b/libs/androidfw/tests/data/overlayable/build
new file mode 100755
index 000000000000..98fdc5101160
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/build
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 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.
+#
+
+set -e
+
+aapt2 compile --dir res -o compiled.flata
+aapt2 link --manifest AndroidManifest.xml -o overlayable.apk compiled.flata
+rm compiled.flata
diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk
new file mode 100644
index 000000000000..85ab4be7a2e5
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/overlayable.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
new file mode 100644
index 000000000000..11aa7354901d
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+<overlayable>
+ <!-- Any overlay can overlay the value of @string/overlayable1 -->
+ <item type="string" name="overlayable1" />
+
+ <!-- Any overlay on the product or system partition can overlay the value of
+ @string/overlayable2 -->
+ <policy type="product|system">
+ <item type="string" name="overlayable2" />
+ </policy>
+
+ <!-- Any overlay can overlay the value of @string/overlayable4 -->
+ <policy type="public">
+ <item type="string" name="overlayable4" />
+ </policy>
+</overlayable>
+
+<overlayable>
+ <!-- Any overlay on the product_services, vendor, or product partition can overlay the value of
+ @string/overlayable3 -->
+ <policy type="product_services|vendor|product">
+ <item type="string" name="overlayable3" />
+ </policy>
+</overlayable>
+</resources> \ No newline at end of file
diff --git a/libs/androidfw/tests/data/overlayable/res/values/public.xml b/libs/androidfw/tests/data/overlayable/res/values/public.xml
new file mode 100644
index 000000000000..5676d7cc64c9
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/res/values/public.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <public type="string" name="not_overlayable" id="0x7f010000" />
+ <public type="string" name="overlayable1" id="0x7f010001" />
+ <public type="string" name="overlayable2" id="0x7f010002" />
+ <public type="string" name="overlayable3" id="0x7f010003" />
+ <public type="string" name="overlayable4" id="0x7f010004" />
+</resources> \ No newline at end of file
diff --git a/libs/androidfw/tests/data/overlayable/res/values/values.xml b/libs/androidfw/tests/data/overlayable/res/values/values.xml
new file mode 100644
index 000000000000..a86b31282bc9
--- /dev/null
+++ b/libs/androidfw/tests/data/overlayable/res/values/values.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="not_overlayable">Not overlayable</string>
+ <string name="overlayable1">Overlayable One</string>
+ <string name="overlayable2">Overlayable Two</string>
+ <string name="overlayable3">Overlayable Three</string>
+ <string name="overlayable4">Overlayable Four</string>
+</resources>
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index da77b99e6e53..ed7d5e578693 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -171,6 +171,7 @@ cc_defaults {
"pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/SkiaVulkanPipeline.cpp",
"pipeline/skia/VectorDrawableAtlas.cpp",
+ "pipeline/skia/VkFunctorDrawable.cpp",
"pipeline/skia/VkInteropFunctorDrawable.cpp",
"renderstate/RenderState.cpp",
"renderthread/CacheManager.cpp",
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 4a3e10c54cef..8067313b2cb2 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -29,8 +29,6 @@
namespace android {
namespace uirenderer {
-bool Properties::drawDeferDisabled = false;
-bool Properties::drawReorderDisabled = false;
bool Properties::debugLayersUpdates = false;
bool Properties::debugOverdraw = false;
bool Properties::showDirtyRegions = false;
@@ -40,7 +38,6 @@ bool Properties::enablePartialUpdates = true;
DebugLevel Properties::debugLevel = kDebugDisabled;
OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default;
-StencilClipDebug Properties::debugStencilClip = StencilClipDebug::Hide;
float Properties::overrideLightRadius = -1.0f;
float Properties::overrideLightPosY = -1.0f;
@@ -85,7 +82,6 @@ bool Properties::load() {
char property[PROPERTY_VALUE_MAX];
bool prevDebugLayersUpdates = debugLayersUpdates;
bool prevDebugOverdraw = debugOverdraw;
- StencilClipDebug prevDebugStencilClip = debugStencilClip;
debugOverdraw = false;
if (property_get(PROPERTY_DEBUG_OVERDRAW, property, nullptr) > 0) {
@@ -99,20 +95,6 @@ bool Properties::load() {
}
}
- // See Properties.h for valid values
- if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, nullptr) > 0) {
- INIT_LOGD(" Stencil clip debug enabled: %s", property);
- if (!strcmp(property, "hide")) {
- debugStencilClip = StencilClipDebug::Hide;
- } else if (!strcmp(property, "highlight")) {
- debugStencilClip = StencilClipDebug::ShowHighlight;
- } else if (!strcmp(property, "region")) {
- debugStencilClip = StencilClipDebug::ShowRegion;
- }
- } else {
- debugStencilClip = StencilClipDebug::Hide;
- }
-
sProfileType = ProfileType::None;
if (property_get(PROPERTY_PROFILE, property, "") > 0) {
if (!strcmp(property, PROPERTY_PROFILE_VISUALIZE_BARS)) {
@@ -125,12 +107,6 @@ bool Properties::load() {
debugLayersUpdates = property_get_bool(PROPERTY_DEBUG_LAYERS_UPDATES, false);
INIT_LOGD(" Layers updates debug enabled: %d", debugLayersUpdates);
- drawDeferDisabled = property_get_bool(PROPERTY_DISABLE_DRAW_DEFER, false);
- INIT_LOGD(" Draw defer %s", drawDeferDisabled ? "disabled" : "enabled");
-
- drawReorderDisabled = property_get_bool(PROPERTY_DISABLE_DRAW_REORDER, false);
- INIT_LOGD(" Draw reorder %s", drawReorderDisabled ? "disabled" : "enabled");
-
showDirtyRegions = property_get_bool(PROPERTY_DEBUG_SHOW_DIRTY_REGIONS, false);
debugLevel = (DebugLevel)property_get_int(PROPERTY_DEBUG, kDebugDisabled);
@@ -152,8 +128,7 @@ bool Properties::load() {
enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, true);
- return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) ||
- (prevDebugStencilClip != debugStencilClip);
+ return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw);
}
void Properties::overrideProperty(const char* name, const char* value) {
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index da53f6657ff7..0a7f4e7eb41c 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -95,20 +95,6 @@ enum DebugLevel {
#define PROPERTY_PROFILE_VISUALIZE_BARS "visual_bars"
/**
- * Used to enable/disable non-rectangular clipping debugging.
- *
- * The accepted values are:
- * "highlight", drawing commands clipped by the stencil will
- * be colored differently
- * "region", renders the clipping region on screen whenever
- * the stencil is set
- * "hide", don't show the clip
- *
- * The default value is "hide".
- */
-#define PROPERTY_DEBUG_STENCIL_CLIP "debug.hwui.show_non_rect_clip"
-
-/**
* Turn on to draw dirty regions every other frame.
*
* Possible values:
@@ -118,19 +104,6 @@ enum DebugLevel {
#define PROPERTY_DEBUG_SHOW_DIRTY_REGIONS "debug.hwui.show_dirty_regions"
/**
- * Disables draw operation deferral if set to "true", forcing draw
- * commands to be issued to OpenGL in order, and processed in sequence
- * with state-manipulation canvas commands.
- */
-#define PROPERTY_DISABLE_DRAW_DEFER "debug.hwui.disable_draw_defer"
-
-/**
- * Used to disable draw operation reordering when deferring draw operations
- * Has no effect if PROPERTY_DISABLE_DRAW_DEFER is set to "true"
- */
-#define PROPERTY_DISABLE_DRAW_REORDER "debug.hwui.disable_draw_reorder"
-
-/**
* Setting this property will enable or disable the dropping of frames with
* empty damage. Default is "true".
*/
@@ -207,8 +180,6 @@ enum class ProfileType { None, Console, Bars };
enum class OverdrawColorSet { Default = 0, Deuteranomaly };
-enum class StencilClipDebug { Hide, ShowHighlight, ShowRegion };
-
enum class RenderPipelineType { SkiaGL, SkiaVulkan, NotInitialized = 128 };
/**
@@ -220,8 +191,6 @@ class Properties {
public:
static bool load();
- static bool drawDeferDisabled;
- static bool drawReorderDisabled;
static bool debugLayersUpdates;
static bool debugOverdraw;
static bool showDirtyRegions;
@@ -235,7 +204,6 @@ public:
static DebugLevel debugLevel;
static OverdrawColorSet overdrawColorSet;
- static StencilClipDebug debugStencilClip;
// Override the value for a subset of properties in this class
static void overrideProperty(const char* name, const char* value);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index ba343841d760..6be7ef72cf5d 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -681,7 +681,7 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p
if (mPaintFilter) {
mPaintFilter->filter(&paintCopy);
}
- SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
+ SkASSERT(paintCopy.getTextEncoding() == kGlyphID_SkTextEncoding);
// Stroke with a hairline is drawn on HW with a fill style for compatibility with Android O and
// older.
if (!mCanvasOwned && sApiLevel <= 27 && paintCopy.getStrokeWidth() <= 0 &&
@@ -708,7 +708,7 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset,
if (mPaintFilter) {
mPaintFilter->filter(&paintCopy);
}
- SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
+ SkASSERT(paintCopy.getTextEncoding() == kGlyphID_SkTextEncoding);
const int N = end - start;
SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 769fce498a70..84292c8768c1 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -43,7 +43,7 @@ MinikinFontSkia::MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontDat
static void MinikinFontSkia_SetSkiaPaint(const minikin::MinikinFont* font, SkPaint* skPaint,
const minikin::MinikinPaint& paint,
const minikin::FontFakery& fakery) {
- skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ skPaint->setTextEncoding(kGlyphID_SkTextEncoding);
skPaint->setTextSize(paint.size);
skPaint->setTextScaleX(paint.scaleX);
skPaint->setTextSkewX(paint.skewX);
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index b682ab0256dd..b56c3ef94791 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -25,6 +25,7 @@
#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/GLFunctorDrawable.h"
#include "pipeline/skia/VkInteropFunctorDrawable.h"
+#include "pipeline/skia/VkFunctorDrawable.h"
namespace android {
namespace uirenderer {
@@ -124,6 +125,8 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
uirenderer::GlFunctorLifecycleListener* listener) {
FunctorDrawable* functorDrawable;
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the
+ // interop is disabled/moved.
functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor,
listener, asSkCanvas());
} else {
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
new file mode 100644
index 000000000000..71ad5e17301a
--- /dev/null
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VkFunctorDrawable.h"
+#include <private/hwui/DrawVkInfo.h>
+
+#include "thread/ThreadBase.h"
+#include "utils/TimeUtils.h"
+#include <GrBackendDrawableInfo.h>
+#include <thread>
+#include <utils/Color.h>
+#include <utils/Trace.h>
+#include <utils/TraceUtils.h>
+#include <SkImage.h>
+#include <vk/GrVkTypes.h>
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+VkFunctorDrawHandler::VkFunctorDrawHandler(Functor *functor)
+ : INHERITED()
+ , mFunctor(functor) {}
+
+VkFunctorDrawHandler::~VkFunctorDrawHandler() {
+ // TODO(cblume) Fill in the DrawVkInfo parameters.
+ (*mFunctor)(DrawVkInfo::kModePostComposite, nullptr);
+}
+
+void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) {
+ ATRACE_CALL();
+
+ GrVkDrawableInfo vulkan_info;
+ if (!info.getVkDrawableInfo(&vulkan_info)) {
+ return;
+ }
+
+ DrawVkInfo draw_vk_info;
+ // TODO(cblume) Fill in the rest of the parameters and test the actual call.
+ draw_vk_info.isLayer = true;
+
+ (*mFunctor)(DrawVkInfo::kModeComposite, &draw_vk_info);
+}
+
+VkFunctorDrawable::VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener,
+ SkCanvas* canvas)
+ : FunctorDrawable(functor, listener, canvas) {}
+
+VkFunctorDrawable::~VkFunctorDrawable() = default;
+
+void VkFunctorDrawable::syncFunctor() const {
+ (*mFunctor)(DrawVkInfo::kModeSync, nullptr);
+}
+
+void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) {
+ LOG_ALWAYS_FATAL("VkFunctorDrawable::onDraw() should never be called.");
+ // Instead of calling onDraw(), the call should come from onSnapGpuDrawHandler.
+}
+
+std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDrawHandler(
+ GrBackendApi backendApi, const SkMatrix& matrix) {
+ if (backendApi != GrBackendApi::kVulkan) {
+ return nullptr;
+ }
+ std::unique_ptr<VkFunctorDrawHandler> draw(new VkFunctorDrawHandler(mFunctor));
+ return std::move(draw);
+}
+
+} // namespace skiapipeline
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
new file mode 100644
index 000000000000..5cd131405d15
--- /dev/null
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include "FunctorDrawable.h"
+
+#include <utils/RefBase.h>
+#include <ui/GraphicBuffer.h>
+#include <SkImageInfo.h>
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+/**
+ * This draw handler will be returned by VkFunctorDrawable's onSnapGpuDrawHandler. It allows us to
+ * issue Vulkan commands while the command buffer is being flushed.
+ */
+class VkFunctorDrawHandler : public FunctorDrawable::GpuDrawHandler {
+public:
+ explicit VkFunctorDrawHandler(Functor* functor);
+ ~VkFunctorDrawHandler() override;
+
+ void draw(const GrBackendDrawableInfo& info) override;
+private:
+ typedef GpuDrawHandler INHERITED;
+
+ Functor* mFunctor;
+};
+
+/**
+ * This drawable wraps a Vulkan functor enabling it to be recorded into a list of Skia drawing
+ * commands.
+ */
+class VkFunctorDrawable : public FunctorDrawable {
+public:
+ VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener,
+ SkCanvas* canvas);
+ ~VkFunctorDrawable() override;
+
+ void syncFunctor() const override;
+
+protected:
+ // SkDrawable functions:
+ void onDraw(SkCanvas* canvas) override;
+ std::unique_ptr<FunctorDrawable::GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi backendApi,
+ const SkMatrix& matrix) override;
+};
+
+} // namespace skiapipeline
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index 004a558dd9d0..82285501cb63 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -46,7 +46,7 @@ public:
ScopedDrawRequest() { beginDraw(); }
private:
void beginDraw() {
- std::lock_guard{sLock};
+ std::lock_guard _lock{sLock};
if (!sGLDrawThread) {
sGLDrawThread = new ThreadBase{};
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
new file mode 100644
index 000000000000..019950fcbc02
--- /dev/null
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef ANDROID_HWUI_DRAW_VK_INFO_H
+#define ANDROID_HWUI_DRAW_VK_INFO_H
+
+#include <vulkan/vulkan.h>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Structure used by VulkanRenderer::callDrawVKFunction() to pass and receive data from Vulkan
+ * functors.
+ */
+struct DrawVkInfo {
+ // Input: current width/height of destination surface
+ int width;
+ int height;
+
+ // Input: is the render target an FBO
+ bool isLayer;
+
+ // Input: current transform matrix, in OpenGL format
+ float transform[16];
+
+ // Input: WebView should do its main compositing draws into this. It cannot do anything that
+ // would require stopping the render pass.
+ VkCommandBuffer secondaryCommandBuffer;
+
+ // Input: The main color attachment index where secondaryCommandBuffer will eventually be
+ // submitted.
+ uint32_t colorAttachmentIndex;
+
+ // Input: A render pass which will be compatible to the one which the secondaryCommandBuffer
+ // will be submitted into.
+ VkRenderPass compatibleRenderPass;
+
+ // Input: Format of the destination surface.
+ VkFormat format;
+
+ // Input: Color space transfer params
+ float G;
+ float A;
+ float B;
+ float C;
+ float D;
+ float E;
+ float F;
+
+ // Input: Color space transformation from linear RGB to D50-adapted XYZ
+ float matrix[9];
+
+ // Input: current clip rect
+ int clipLeft;
+ int clipTop;
+ int clipRight;
+ int clipBottom;
+
+ /**
+ * Values used as the "what" parameter of the functor.
+ */
+ enum Mode {
+ // Called once at WebView start
+ kModeInit,
+ // Called when things need to be re-created
+ kModeReInit,
+ // Notifies the app that the composite functor will be called soon. This allows WebView to
+ // begin work early.
+ kModePreComposite,
+ // Do the actual composite work
+ kModeComposite,
+ // This allows WebView to begin using the previously submitted objects in future work.
+ kModePostComposite,
+ // Invoked every time the UI thread pushes over a frame to the render thread and the owning
+ // view has a dirty display list*. This is a signal to sync any data that needs to be
+ // shared between the UI thread and the render thread. During this time the UI thread is
+ // blocked.
+ kModeSync
+ };
+
+ /**
+ * Values used by Vulkan functors to tell the framework what to do next.
+ */
+ enum Status {
+ // The functor is done
+ kStatusDone = 0x0,
+ };
+}; // struct DrawVkInfo
+
+} // namespace uirenderer
+} // namespace android
+
+#endif // ANDROID_HWUI_DRAW_VK_INFO_H
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index e1f8307343a7..2abb3d5179a0 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -745,7 +745,7 @@ bool VulkanManager::createSwapchain(VulkanSurface* surface) {
surface->mWindowWidth = extent.width;
surface->mWindowHeight = extent.height;
- uint32_t imageCount = caps.minImageCount + 2;
+ uint32_t imageCount = std::max<uint32_t>(3, caps.minImageCount);
if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
// Application must settle for fewer images than desired:
imageCount = caps.maxImageCount;
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 8a1bc4d2f7f2..f81202292a49 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -81,7 +81,7 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint
auto utf16 = asciiToUtf16(text);
uint32_t length = strlen(text);
SkPaint glyphPaint(paint);
- glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding);
canvas->drawText(
utf16.get(), length, // text buffer
0, length, // draw range
@@ -94,7 +94,7 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint
const SkPath& path) {
auto utf16 = asciiToUtf16(text);
SkPaint glyphPaint(paint);
- glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding);
canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, glyphPaint,
nullptr);
}
diff --git a/media/OWNERS b/media/OWNERS
index 0abf9aeb6101..03b751c07c6c 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,12 +1,13 @@
+chz@google.com
+dwkang@google.com
elaurent@google.com
etalvala@google.com
gkasten@google.com
hunga@google.com
+jaewan@google.com
jmtrivi@google.com
+jsharkey@android.com
lajos@google.com
marcone@google.com
sungsoo@google.com
wjia@google.com
-jaewan@google.com
-chz@google.com
-dwkang@google.com
diff --git a/media/java/android/media/CallbackDataSourceDesc.java b/media/java/android/media/CallbackDataSourceDesc.java
index 0e8e6ceeaa15..cb9669bb653d 100644
--- a/media/java/android/media/CallbackDataSourceDesc.java
+++ b/media/java/android/media/CallbackDataSourceDesc.java
@@ -19,7 +19,6 @@ package android.media;
import android.annotation.NonNull;
/**
- * @hide
* Structure of data source descriptor for sources using callback.
*
* Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)},
diff --git a/media/java/android/media/DataSourceCallback.java b/media/java/android/media/DataSourceCallback.java
index 9b27baf32204..0d4d53106c78 100644
--- a/media/java/android/media/DataSourceCallback.java
+++ b/media/java/android/media/DataSourceCallback.java
@@ -21,7 +21,6 @@ import java.io.Closeable;
import java.io.IOException;
/**
- * @hide
* For supplying media data to the framework. Implement this if your app has
* special requirements for the way media data is obtained.
*
diff --git a/media/java/android/media/DataSourceDesc.java b/media/java/android/media/DataSourceDesc.java
index 702034e987ca..9109ea5bdab2 100644
--- a/media/java/android/media/DataSourceDesc.java
+++ b/media/java/android/media/DataSourceDesc.java
@@ -19,7 +19,6 @@ package android.media;
import android.annotation.NonNull;
/**
- * @hide
* Base class of data source descriptor.
*
* Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)},
@@ -36,6 +35,9 @@ public class DataSourceDesc {
// keep consistent with native code
public static final long LONG_MAX_TIME_MS = LONG_MAX / 1000;
+ /**
+ * @hide
+ */
public static final long LONG_MAX_TIME_US = LONG_MAX_TIME_MS * 1000;
public static final long POSITION_UNKNOWN = LONG_MAX_TIME_MS;
@@ -172,7 +174,8 @@ public class DataSourceDesc {
/**
* Sets the end position in milliseconds at which the playback will end.
- * Any negative number is treated as maximum length of the data source.
+ * Any negative number is treated as maximum duration {@link #LONG_MAX_TIME_MS}
+ * of the data source
*
* @param position the end position in milliseconds at which the playback will end
* @return the same Builder instance.
diff --git a/media/java/android/media/FileDataSourceDesc.java b/media/java/android/media/FileDataSourceDesc.java
index 763a81f53765..14ef18029233 100644
--- a/media/java/android/media/FileDataSourceDesc.java
+++ b/media/java/android/media/FileDataSourceDesc.java
@@ -23,7 +23,6 @@ import android.util.Log;
import java.io.IOException;
/**
- * @hide
* Structure of data source descriptor for sources using file descriptor.
*
* Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)},
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 3d13c5f72f55..b7743c9db4c0 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -1045,11 +1045,11 @@ public final class MediaFormat {
/**
* Returns the value of a numeric key. This is provided as a convenience method for keys
- * that may take multiple numeric types, such as {@link KEY_FRAME_RATE}, or {@link
- * KEY_I_FRAME_INTERVAL}.
+ * that may take multiple numeric types, such as {@link #KEY_FRAME_RATE}, or {@link
+ * #KEY_I_FRAME_INTERVAL}.
*
* @return null if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is ByteBuffer or String
+ * @throws ClassCastException if the stored value for the key is ByteBuffer or String
*/
public final @Nullable Number getNumber(@NonNull String name) {
return ((Number)mMap.get(name));
@@ -1059,7 +1059,7 @@ public final class MediaFormat {
* Returns the value of a numeric key, or the default value if the key is missing.
*
* @return defaultValue if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is ByteBuffer or String
+ * @throws ClassCastException if the stored value for the key is ByteBuffer or String
*/
public final @NonNull Number getNumber(@NonNull String name, @NonNull Number defaultValue) {
Number ret = getNumber(name);
@@ -1069,9 +1069,10 @@ public final class MediaFormat {
/**
* Returns the value of an integer key.
*
- * @throw NullPointerException if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is long, float, ByteBuffer or
- * String
+ * @throws NullPointerException if the key does not exist or the stored value for the key is
+ * null
+ * @throws ClassCastException if the stored value for the key is long, float, ByteBuffer or
+ * String
*/
public final int getInteger(@NonNull String name) {
return ((Integer)mMap.get(name)).intValue();
@@ -1081,8 +1082,8 @@ public final class MediaFormat {
* Returns the value of an integer key, or the default value if the key is missing.
*
* @return defaultValue if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is long, float, ByteBuffer or
- * String
+ * @throws ClassCastException if the stored value for the key is long, float, ByteBuffer or
+ * String
*/
public final int getInteger(@NonNull String name, int defaultValue) {
try {
@@ -1096,9 +1097,10 @@ public final class MediaFormat {
/**
* Returns the value of a long key.
*
- * @throw NullPointerException if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is int, float, ByteBuffer or
- * String
+ * @throws NullPointerException if the key does not exist or the stored value for the key is
+ * null
+ * @throws ClassCastException if the stored value for the key is int, float, ByteBuffer or
+ * String
*/
public final long getLong(@NonNull String name) {
return ((Long)mMap.get(name)).longValue();
@@ -1108,8 +1110,8 @@ public final class MediaFormat {
* Returns the value of an long key, or the default value if the key is missing.
*
* @return defaultValue if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is int, float, ByteBuffer or
- * String
+ * @throws ClassCastException if the stored value for the key is int, float, ByteBuffer or
+ * String
*/
public final long getLong(@NonNull String name, long defaultValue) {
try {
@@ -1123,9 +1125,10 @@ public final class MediaFormat {
/**
* Returns the value of a float key.
*
- * @throw NullPointerException if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is int, long, ByteBuffer or
- * String
+ * @throws NullPointerException if the key does not exist or the stored value for the key is
+ * null
+ * @throws ClassCastException if the stored value for the key is int, long, ByteBuffer or
+ * String
*/
public final float getFloat(@NonNull String name) {
return ((Float)mMap.get(name)).floatValue();
@@ -1135,8 +1138,8 @@ public final class MediaFormat {
* Returns the value of an float key, or the default value if the key is missing.
*
* @return defaultValue if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is int, long, ByteBuffer or
- * String
+ * @throws ClassCastException if the stored value for the key is int, long, ByteBuffer or
+ * String
*/
public final float getFloat(@NonNull String name, float defaultValue) {
try {
@@ -1151,7 +1154,7 @@ public final class MediaFormat {
* Returns the value of a string key.
*
* @return null if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is int, long, float or ByteBuffer
+ * @throws ClassCastException if the stored value for the key is int, long, float or ByteBuffer
*/
public final @Nullable String getString(@NonNull String name) {
return (String)mMap.get(name);
@@ -1161,7 +1164,7 @@ public final class MediaFormat {
* Returns the value of an string key, or the default value if the key is missing.
*
* @return defaultValue if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is int, long, float or ByteBuffer
+ * @throws ClassCastException if the stored value for the key is int, long, float or ByteBuffer
*/
public final @NonNull String getString(@NonNull String name, @NonNull String defaultValue) {
String ret = getString(name);
@@ -1172,7 +1175,7 @@ public final class MediaFormat {
* Returns the value of a ByteBuffer key.
*
* @return null if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is int, long, float or String
+ * @throws ClassCastException if the stored value for the key is int, long, float or String
*/
public final @Nullable ByteBuffer getByteBuffer(@NonNull String name) {
return (ByteBuffer)mMap.get(name);
@@ -1182,7 +1185,7 @@ public final class MediaFormat {
* Returns the value of a ByteBuffer key, or the default value if the key is missing.
*
* @return defaultValue if the key does not exist or the stored value for the key is null
- * @throw ClassCastException if the stored value for the key is int, long, float or String
+ * @throws ClassCastException if the stored value for the key is int, long, float or String
*/
public final @NonNull ByteBuffer getByteBuffer(
@NonNull String name, @NonNull ByteBuffer defaultValue) {
@@ -1197,7 +1200,7 @@ public final class MediaFormat {
* @param feature the name of a {@link MediaCodecInfo.CodecCapabilities} feature.
*
* @throws IllegalArgumentException if the feature was neither set to be enabled
- * nor to be disabled.
+ * nor to be disabled.
*/
public boolean getFeatureEnabled(@NonNull String feature) {
Integer enabled = (Integer)mMap.get(KEY_FEATURE_ + feature);
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index a10b2123a70c..e6ad4441401a 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -21,9 +21,6 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
-import android.annotation.UnsupportedAppUsage;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
@@ -81,8 +78,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
- * @hide
- *
* MediaPlayer2 class can be used to control playback of audio/video files and streams.
*
* <p>Topics covered here are:
@@ -776,7 +771,7 @@ public class MediaPlayer2 implements AutoCloseable
*
* @return the current DataSourceDesc
*/
- public DataSourceDesc getCurrentDataSource() {
+ public @Nullable DataSourceDesc getCurrentDataSource() {
synchronized (mSrcLock) {
return mCurrentSourceInfo == null ? null : mCurrentSourceInfo.mDSD;
}
@@ -1252,19 +1247,18 @@ public class MediaPlayer2 implements AutoCloseable
*
* <p>This function has the MediaPlayer2 access the low-level power manager
* service to control the device's power usage while playing is occurring.
- * The parameter is a combination of {@link android.os.PowerManager} wake flags.
+ * The parameter is a {@link android.os.PowerManager.WakeLock}.
* Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
* permission.
* By default, no attempt is made to keep the device awake during playback.
*
- * @param context the Context to use
- * @param mode the power/wake mode to set
+ * @param wakeLock the power wake lock used during playback.
* @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
* @see android.os.PowerManager
*/
// This is an asynchronous call.
- public Object setWakeMode(Context context, int mode) {
- return addTask(new Task(CALL_COMPLETED_SET_WAKE_MODE, false) {
+ public Object setWakeLock(@NonNull PowerManager.WakeLock wakeLock) {
+ return addTask(new Task(CALL_COMPLETED_SET_WAKE_LOCK, false) {
@Override
void process() {
boolean washeld = false;
@@ -1274,28 +1268,15 @@ public class MediaPlayer2 implements AutoCloseable
washeld = true;
mWakeLock.release();
}
- mWakeLock = null;
}
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- ActivityManager am =
- (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- List<RunningAppProcessInfo> runningAppsProcInfo = am.getRunningAppProcesses();
- int pid = android.os.Process.myPid();
- String name = "pid " + String.valueOf(pid);
- if (runningAppsProcInfo != null) {
- for (RunningAppProcessInfo procInfo : runningAppsProcInfo) {
- if (procInfo.pid == pid) {
- name = procInfo.processName;
- break;
- }
+ mWakeLock = wakeLock;
+ if (mWakeLock != null) {
+ mWakeLock.setReferenceCounted(false);
+ if (washeld) {
+ mWakeLock.acquire();
}
}
- mWakeLock = pm.newWakeLock(mode | PowerManager.ON_AFTER_RELEASE, name);
- mWakeLock.setReferenceCounted(false);
- if (washeld) {
- mWakeLock.acquire();
- }
}
});
}
@@ -1303,7 +1284,7 @@ public class MediaPlayer2 implements AutoCloseable
/**
* Control whether we should use the attached SurfaceHolder to keep the
* screen on while video playback is occurring. This is the preferred
- * method over {@link #setWakeMode} where possible, since it doesn't
+ * method over {@link #setWakeLock} where possible, since it doesn't
* require that the application have permission for low-level wake lock
* access.
*
@@ -1350,9 +1331,13 @@ public class MediaPlayer2 implements AutoCloseable
*
* @param token the command to be canceled. This is the returned Object when command is issued.
* @return {@code false} if the task could not be cancelled; {@code true} otherwise.
+ * @throws IllegalArgumentException if argument token is null.
*/
// This is a synchronous call.
- public boolean cancelCommand(Object token) {
+ public boolean cancelCommand(@NonNull Object token) {
+ if (token == null) {
+ throw new IllegalArgumentException("command token should not be null");
+ }
synchronized (mTaskLock) {
return mPendingTasks.remove(token);
}
@@ -1891,7 +1876,6 @@ public class MediaPlayer2 implements AutoCloseable
* Gets the track type.
* @return TrackType which indicates if the track is video, audio, timed text.
*/
- @UnsupportedAppUsage
public int getTrackType() {
return mTrackType;
}
@@ -1902,7 +1886,6 @@ public class MediaPlayer2 implements AutoCloseable
* When the language is unknown or could not be determined,
* ISO-639-2 language code, "und", is returned.
*/
- @UnsupportedAppUsage
public String getLanguage() {
String language = mFormat.getString(MediaFormat.KEY_LANGUAGE);
return language == null ? "und" : language;
@@ -1933,19 +1916,20 @@ public class MediaPlayer2 implements AutoCloseable
final int mTrackType;
final MediaFormat mFormat;
- TrackInfo(Iterator<Value> in) {
- mTrackType = in.next().getInt32Value();
+ static TrackInfo create(Iterator<Value> in) {
+ int trackType = in.next().getInt32Value();
// TODO: build the full MediaFormat; currently we are using createSubtitleFormat
// even for audio/video tracks, meaning we only set the mime and language.
String mime = in.next().getStringValue();
String language = in.next().getStringValue();
- mFormat = MediaFormat.createSubtitleFormat(mime, language);
+ MediaFormat format = MediaFormat.createSubtitleFormat(mime, language);
- if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.next().getInt32Value());
- mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.next().getInt32Value());
- mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.next().getInt32Value());
+ if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+ format.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.next().getInt32Value());
+ format.setInteger(MediaFormat.KEY_IS_DEFAULT, in.next().getInt32Value());
+ format.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.next().getInt32Value());
}
+ return new TrackInfo(trackType, format);
}
/** @hide */
@@ -1990,9 +1974,9 @@ public class MediaPlayer2 implements AutoCloseable
* addTimedTextSource method is called.
* @throws IllegalStateException if it is called in an invalid state.
*/
- public List<TrackInfo> getTrackInfo() {
+ public @NonNull List<TrackInfo> getTrackInfo() {
TrackInfo[] trackInfo = getInbandTrackInfo();
- return Arrays.asList(trackInfo);
+ return (trackInfo != null ? Arrays.asList(trackInfo) : new ArrayList<TrackInfo>(0));
}
private TrackInfo[] getInbandTrackInfo() throws IllegalStateException {
@@ -2010,7 +1994,7 @@ public class MediaPlayer2 implements AutoCloseable
}
TrackInfo[] trackInfo = new TrackInfo[size];
for (int i = 0; i < size; ++i) {
- trackInfo[i] = new TrackInfo(in);
+ trackInfo[i] = TrackInfo.create(in);
}
return trackInfo;
}
@@ -2505,7 +2489,7 @@ public class MediaPlayer2 implements AutoCloseable
Log.w(TAG, "MEDIA_DRM_INFO failed to parse msg.obj " + obj);
break;
}
- DrmInfo drmInfo = new DrmInfo(playerMsg);
+ DrmInfo drmInfo = DrmInfo.create(playerMsg);
synchronized (sourceInfo) {
sourceInfo.mDrmInfo = drmInfo;
}
@@ -2556,7 +2540,7 @@ public class MediaPlayer2 implements AutoCloseable
* @param size the size of the video
*/
public void onVideoSizeChanged(
- MediaPlayer2 mp, DataSourceDesc dsd, VideoSize size) { }
+ @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd, @NonNull VideoSize size) { }
/**
* Called to indicate an avaliable timed text
@@ -2567,7 +2551,8 @@ public class MediaPlayer2 implements AutoCloseable
* needed to be displayed and the display format.
* @hide
*/
- public void onTimedText(MediaPlayer2 mp, DataSourceDesc dsd, TimedText text) { }
+ public void onTimedText(
+ @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd, @NonNull TimedText text) { }
/**
* Called to indicate avaliable timed metadata
@@ -2588,7 +2573,8 @@ public class MediaPlayer2 implements AutoCloseable
* @param data the timed metadata sample associated with this event
*/
public void onTimedMetaDataAvailable(
- MediaPlayer2 mp, DataSourceDesc dsd, TimedMetaData data) { }
+ @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @NonNull TimedMetaData data) { }
/**
* Called to indicate an error.
@@ -2600,7 +2586,8 @@ public class MediaPlayer2 implements AutoCloseable
* implementation dependent.
*/
public void onError(
- MediaPlayer2 mp, DataSourceDesc dsd, @MediaError int what, int extra) { }
+ @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @MediaError int what, int extra) { }
/**
* Called to indicate an info or a warning.
@@ -2611,7 +2598,9 @@ public class MediaPlayer2 implements AutoCloseable
* @param extra an extra code, specific to the info. Typically
* implementation dependent.
*/
- public void onInfo(MediaPlayer2 mp, DataSourceDesc dsd, @MediaInfo int what, int extra) { }
+ public void onInfo(
+ @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @MediaInfo int what, int extra) { }
/**
* Called to acknowledge an API call.
@@ -2622,7 +2611,7 @@ public class MediaPlayer2 implements AutoCloseable
* @param status the returned status code for the call.
*/
public void onCallCompleted(
- MediaPlayer2 mp, DataSourceDesc dsd, @CallCompleted int what,
+ @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd, @CallCompleted int what,
@CallStatus int status) { }
/**
@@ -2633,7 +2622,8 @@ public class MediaPlayer2 implements AutoCloseable
* @param timestamp the new media clock.
*/
public void onMediaTimeDiscontinuity(
- MediaPlayer2 mp, DataSourceDesc dsd, MediaTimestamp timestamp) { }
+ @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @NonNull MediaTimestamp timestamp) { }
/**
* Called to indicate {@link #notifyWhenCommandLabelReached(Object)} has been processed.
@@ -2642,7 +2632,7 @@ public class MediaPlayer2 implements AutoCloseable
* @param label the application specific Object given by
* {@link #notifyWhenCommandLabelReached(Object)}.
*/
- public void onCommandLabelReached(MediaPlayer2 mp, @NonNull Object label) { }
+ public void onCommandLabelReached(@NonNull MediaPlayer2 mp, @NonNull Object label) { }
/**
* Called when when a player subtitle track has new subtitle data available.
@@ -2651,7 +2641,8 @@ public class MediaPlayer2 implements AutoCloseable
* @param data the subtitle data
*/
public void onSubtitleData(
- MediaPlayer2 mp, DataSourceDesc dsd, @NonNull SubtitleData data) { }
+ @NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @NonNull SubtitleData data) { }
}
private final Object mEventCbLock = new Object();
@@ -3046,10 +3037,10 @@ public class MediaPlayer2 implements AutoCloseable
*/
public static final int CALL_COMPLETED_SET_DISPLAY = 33;
- /** The player just completed a call {@link #setWakeMode}.
+ /** The player just completed a call {@link #setWakeLock}.
* @see EventCallback#onCallCompleted
*/
- public static final int CALL_COMPLETED_SET_WAKE_MODE = 34;
+ public static final int CALL_COMPLETED_SET_WAKE_LOCK = 34;
/** The player just completed a call {@link #setScreenOnWhilePlaying}.
* @see EventCallback#onCallCompleted
@@ -3102,7 +3093,7 @@ public class MediaPlayer2 implements AutoCloseable
CALL_COMPLETED_CLEAR_NEXT_DATA_SOURCES,
CALL_COMPLETED_SET_BUFFERING_PARAMS,
CALL_COMPLETED_SET_DISPLAY,
- CALL_COMPLETED_SET_WAKE_MODE,
+ CALL_COMPLETED_SET_WAKE_LOCK,
CALL_COMPLETED_SET_SCREEN_ON_WHILE_PLAYING,
CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED,
CALL_COMPLETED_PREPARE_DRM,
@@ -3179,6 +3170,7 @@ public class MediaPlayer2 implements AutoCloseable
* The only allowed DRM calls in this listener are
* {@link MediaPlayer2#getDrmPropertyString(DataSourceDesc, String)}
* and {@link MediaPlayer2#setDrmPropertyString(DataSourceDesc, String, String)}.
+ * @hide
*/
public interface OnDrmConfigHelper {
/**
@@ -3197,6 +3189,7 @@ public class MediaPlayer2 implements AutoCloseable
* of {@link #prepareDrm(DataSourceDesc, UUID)}.
*
* @param listener the callback that will be run
+ * @hide
*/
// This is a synchronous call.
public void setOnDrmConfigHelper(OnDrmConfigHelper listener) {
@@ -3208,6 +3201,7 @@ public class MediaPlayer2 implements AutoCloseable
/**
* Interface definition for callbacks to be invoked when the player has the corresponding
* DRM events.
+ * @hide
*/
public static class DrmEventCallback {
/**
@@ -3241,6 +3235,7 @@ public class MediaPlayer2 implements AutoCloseable
*
* @param eventCallback the callback that will be run
* @param executor the executor through which the callback should be invoked
+ * @hide
*/
// This is a synchronous call.
public void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
@@ -3261,6 +3256,7 @@ public class MediaPlayer2 implements AutoCloseable
* Unregisters the {@link DrmEventCallback}.
*
* @param eventCallback the callback to be unregistered
+ * @hide
*/
// This is a synchronous call.
public void unregisterDrmEventCallback(DrmEventCallback eventCallback) {
@@ -3278,31 +3274,37 @@ public class MediaPlayer2 implements AutoCloseable
* <p>
*
* DRM preparation has succeeded.
+ * @hide
*/
public static final int PREPARE_DRM_STATUS_SUCCESS = 0;
/**
* The device required DRM provisioning but couldn't reach the provisioning server.
+ * @hide
*/
public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1;
/**
* The device required DRM provisioning but the provisioning server denied the request.
+ * @hide
*/
public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2;
/**
* The DRM preparation has failed .
+ * @hide
*/
public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3;
/**
* The crypto scheme UUID is not supported by the device.
+ * @hide
*/
public static final int PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME = 4;
/**
* The hardware resources are not available, due to being in use.
+ * @hide
*/
public static final int PREPARE_DRM_STATUS_RESOURCE_BUSY = 5;
@@ -3343,6 +3345,7 @@ public class MediaPlayer2 implements AutoCloseable
* @param dsd The DRM protected data source
*
* @throws IllegalStateException if called before being prepared
+ * @hide
*/
public DrmInfo getDrmInfo(@NonNull DataSourceDesc dsd) {
final SourceInfo sourceInfo = getSourceInfo(dsd);
@@ -3398,6 +3401,7 @@ public class MediaPlayer2 implements AutoCloseable
* {@link DrmEventCallback#onDrmInfo}.
*
* @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
+ * @hide
*/
// This is an asynchronous call.
public Object prepareDrm(@NonNull DataSourceDesc dsd, @NonNull UUID uuid) {
@@ -3491,6 +3495,7 @@ public class MediaPlayer2 implements AutoCloseable
* @param dsd The DRM protected data source
*
* @throws NoDrmSchemeException if there is no active DRM session to release
+ * @hide
*/
// This is a synchronous call.
public void releaseDrm(@NonNull DataSourceDesc dsd)
@@ -3501,7 +3506,7 @@ public class MediaPlayer2 implements AutoCloseable
}
}
- private native void native_releaseDrm();
+ private native void native_releaseDrm(long mSrcId);
/**
* A key request/response exchange occurs between the app and a license server
@@ -3541,6 +3546,7 @@ public class MediaPlayer2 implements AutoCloseable
* This may be {@code null} if no additional parameters are to be sent.
*
* @throws NoDrmSchemeException if there is no active DRM session
+ * @hide
*/
public MediaDrm.KeyRequest getDrmKeyRequest(
@NonNull DataSourceDesc dsd,
@@ -3581,6 +3587,7 @@ public class MediaPlayer2 implements AutoCloseable
* @throws NoDrmSchemeException if there is no active DRM session
* @throws DeniedByServerException if the response indicates that the
* server rejected the request
+ * @hide
*/
// This is a synchronous call.
public byte[] provideDrmKeyResponse(
@@ -3606,6 +3613,7 @@ public class MediaPlayer2 implements AutoCloseable
* @param keySetId identifies the saved key set to restore
*
* @throws NoDrmSchemeException if there is no active DRM session
+ * @hide
*/
// This is a synchronous call.
public void restoreDrmKeys(
@@ -3633,6 +3641,7 @@ public class MediaPlayer2 implements AutoCloseable
* {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
*
* @throws NoDrmSchemeException if there is no active DRM session
+ * @hide
*/
public String getDrmPropertyString(
@NonNull DataSourceDesc dsd,
@@ -3659,6 +3668,7 @@ public class MediaPlayer2 implements AutoCloseable
* {@link MediaDrm#PROPERTY_DESCRIPTION}, {@link MediaDrm#PROPERTY_ALGORITHMS}
*
* @throws NoDrmSchemeException if there is no active DRM session
+ * @hide
*/
// This is a synchronous call.
public void setDrmPropertyString(
@@ -3676,6 +3686,7 @@ public class MediaPlayer2 implements AutoCloseable
/**
* Encapsulates the DRM properties of the source.
+ * @hide
*/
public static final class DrmInfo {
private Map<UUID, byte[]> mMapPssh;
@@ -3702,36 +3713,37 @@ public class MediaPlayer2 implements AutoCloseable
mSupportedSchemes = supportedSchemes;
}
- private DrmInfo(PlayerMessage msg) {
- Log.v(TAG, "DrmInfo(" + msg + ")");
+ private static DrmInfo create(PlayerMessage msg) {
+ Log.v(TAG, "DrmInfo.create(" + msg + ")");
Iterator<Value> in = msg.getValuesList().iterator();
byte[] pssh = in.next().getBytesValue().toByteArray();
- Log.v(TAG, "DrmInfo() PSSH: " + arrToHex(pssh));
- mMapPssh = parsePSSH(pssh, pssh.length);
- Log.v(TAG, "DrmInfo() PSSH: " + mMapPssh);
+ Log.v(TAG, "DrmInfo.create() PSSH: " + DrmInfo.arrToHex(pssh));
+ Map<UUID, byte[]> mapPssh = DrmInfo.parsePSSH(pssh, pssh.length);
+ Log.v(TAG, "DrmInfo.create() PSSH: " + mapPssh);
int supportedDRMsCount = in.next().getInt32Value();
- mSupportedSchemes = new UUID[supportedDRMsCount];
+ UUID[] supportedSchemes = new UUID[supportedDRMsCount];
for (int i = 0; i < supportedDRMsCount; i++) {
byte[] uuid = new byte[16];
in.next().getBytesValue().copyTo(uuid, 0);
- mSupportedSchemes[i] = bytesToUUID(uuid);
+ supportedSchemes[i] = DrmInfo.bytesToUUID(uuid);
- Log.v(TAG, "DrmInfo() supportedScheme[" + i + "]: " + mSupportedSchemes[i]);
+ Log.v(TAG, "DrmInfo() supportedScheme[" + i + "]: " + supportedSchemes[i]);
}
- Log.v(TAG, "DrmInfo() psshsize: " + pssh.length
+ Log.v(TAG, "DrmInfo.create() psshsize: " + pssh.length
+ " supportedDRMsCount: " + supportedDRMsCount);
+ return new DrmInfo(mapPssh, supportedSchemes);
}
private DrmInfo makeCopy() {
return new DrmInfo(this.mMapPssh, this.mSupportedSchemes);
}
- private String arrToHex(byte[] bytes) {
+ private static String arrToHex(byte[] bytes) {
String out = "0x";
for (int i = 0; i < bytes.length; i++) {
out += String.format("%02x", bytes[i]);
@@ -3740,7 +3752,7 @@ public class MediaPlayer2 implements AutoCloseable
return out;
}
- private UUID bytesToUUID(byte[] uuid) {
+ private static UUID bytesToUUID(byte[] uuid) {
long msb = 0, lsb = 0;
for (int i = 0; i < 8; i++) {
msb |= (((long) uuid[i] & 0xff) << (8 * (7 - i)));
@@ -3750,7 +3762,7 @@ public class MediaPlayer2 implements AutoCloseable
return new UUID(msb, lsb);
}
- private Map<UUID, byte[]> parsePSSH(byte[] pssh, int psshsize) {
+ private static Map<UUID, byte[]> parsePSSH(byte[] pssh, int psshsize) {
Map<UUID, byte[]> result = new HashMap<UUID, byte[]>();
final int uuidSize = 16;
@@ -3814,6 +3826,7 @@ public class MediaPlayer2 implements AutoCloseable
* Thrown when a DRM method is called before preparing a DRM scheme through
* {@link MediaPlayer2#prepareDrm(DataSourceDesc, UUID)}.
* Extends MediaDrm.MediaDrmException
+ * @hide
*/
public static final class NoDrmSchemeException extends MediaDrmException {
public NoDrmSchemeException(String detailMessage) {
@@ -3821,7 +3834,8 @@ public class MediaPlayer2 implements AutoCloseable
}
}
- private native void native_prepareDrm(@NonNull byte[] uuid, @NonNull byte[] drmSessionId);
+ private native void native_prepareDrm(
+ long srcId, @NonNull byte[] uuid, @NonNull byte[] drmSessionId);
// Instantiated from the native side
@SuppressWarnings("unused")
@@ -4064,6 +4078,7 @@ public class MediaPlayer2 implements AutoCloseable
static final int PROVISION_TIMEOUT_MS = 60000;
final DataSourceDesc mDSD;
+ final long mSrcId;
//--- guarded by |this| start
MediaDrm mDrmObj;
@@ -4075,8 +4090,9 @@ public class MediaPlayer2 implements AutoCloseable
Future<?> mProvisionResult;
//--- guarded by |this| end
- DrmHandle(DataSourceDesc dsd) {
+ DrmHandle(DataSourceDesc dsd, long srcId) {
mDSD = dsd;
+ mSrcId = srcId;
}
void prepare(UUID uuid) throws UnsupportedSchemeException,
@@ -4186,7 +4202,8 @@ public class MediaPlayer2 implements AutoCloseable
// Sending it down to native/mediaserver to create the crypto object
// This call could simply fail due to bad player state, e.g., after play().
- MediaPlayer2.this.native_prepareDrm(getByteArrayFromUUID(uuid), mDrmSessionId);
+ final MediaPlayer2 mp2 = MediaPlayer2.this;
+ mp2.native_prepareDrm(mSrcId, getByteArrayFromUUID(uuid), mDrmSessionId);
Log.v(TAG, "prepareDrm_openSessionStep: native_prepareDrm/Crypto succeeded");
} catch (Exception e) { //ResourceBusyException, NotProvisionedException
@@ -4367,7 +4384,7 @@ public class MediaPlayer2 implements AutoCloseable
// exception if we're in a non-stopped/prepared state.
// for cleaning native/mediaserver crypto object
- native_releaseDrm();
+ native_releaseDrm(mSrcId);
// for cleaning client-side MediaDrm object; only called if above has succeeded
cleanDrmObj();
@@ -4573,7 +4590,7 @@ public class MediaPlayer2 implements AutoCloseable
SourceInfo(DataSourceDesc dsd) {
this.mDSD = dsd;
- mDrmHandle = new DrmHandle(dsd);
+ mDrmHandle = new DrmHandle(dsd, mId);
}
void close() {
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 0950a2497866..90cfc534877e 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1015,12 +1015,6 @@ public class MediaScanner implements AutoCloseable {
// exif is null
}
if (exif != null) {
- float[] latlng = new float[2];
- if (exif.getLatLong(latlng)) {
- values.put(Images.Media.LATITUDE, latlng[0]);
- values.put(Images.Media.LONGITUDE, latlng[1]);
- }
-
long time = exif.getGpsDateTime();
if (time != -1) {
values.put(Images.Media.DATE_TAKEN, time);
diff --git a/media/java/android/media/SubtitleData.java b/media/java/android/media/SubtitleData.java
index ba37b9b66360..852babe1ecea 100644
--- a/media/java/android/media/SubtitleData.java
+++ b/media/java/android/media/SubtitleData.java
@@ -17,8 +17,11 @@
package android.media;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
+import java.util.Arrays;
+
/**
* Class encapsulating subtitle data, as received through the
* {@link MediaPlayer.OnSubtitleDataListener} interface.
@@ -80,11 +83,11 @@ public final class SubtitleData
}
/** @hide */
- public SubtitleData(int trackIndex, long startTimeUs, long durationUs, byte[] data) {
+ public SubtitleData(int trackIndex, long startTimeUs, long durationUs, @NonNull byte[] data) {
mTrackIndex = trackIndex;
mStartTimeUs = startTimeUs;
mDurationUs = durationUs;
- mData = data;
+ mData = (data != null ? data : new byte[0]);
}
/**
@@ -138,4 +141,80 @@ public final class SubtitleData
return true;
}
+
+ /**
+ * Builder class for {@link SubtitleData} objects.
+ * <p> Here is an example where <code>Builder</code> is used to define the
+ * {@link SubtitleData}:
+ *
+ * <pre class="prettyprint">
+ * SubtitleData sd = new SubtitleData.Builder()
+ * .setSubtitleData(trackIndex, startTime, duration, data)
+ * .build();
+ * </pre>
+ * @hide
+ */
+ @SystemApi
+ public static class Builder {
+ private int mTrackIndex;
+ private long mStartTimeUs;
+ private long mDurationUs;
+ private byte[] mData = new byte[0];
+
+ /**
+ * Constructs a new Builder with the defaults.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Constructs a new Builder from a given {@link SubtitleData} instance
+ * @param sd the {@link SubtitleData} object whose data will be reused
+ * in the new Builder. It should not be null. The data array is copied.
+ */
+ public Builder(@NonNull SubtitleData sd) {
+ if (sd == null) {
+ throw new IllegalArgumentException("null SubtitleData is not allowed");
+ }
+ mTrackIndex = sd.mTrackIndex;
+ mStartTimeUs = sd.mStartTimeUs;
+ mDurationUs = sd.mDurationUs;
+ if (sd.mData != null) {
+ mData = Arrays.copyOf(sd.mData, sd.mData.length);
+ }
+ }
+
+ /**
+ * Combines all of the fields that have been set and return a new
+ * {@link SubtitleData} object. <code>IllegalStateException</code> will be
+ * thrown if there is conflict between fields.
+ *
+ * @return a new {@link SubtitleData} object
+ */
+ public @NonNull SubtitleData build() {
+ return new SubtitleData(mTrackIndex, mStartTimeUs, mDurationUs, mData);
+ }
+
+ /**
+ * Sets the info of subtitle data.
+ *
+ * @param trackIndex the ParcelFileDescriptor for the file to play
+ * @param startTimeUs the start time in microsecond for the subtile data
+ * @param durationUs the duration in microsecond for the subtile data
+ * @param data the data array for the subtile data. It should not be null.
+ * No data copying is made.
+ * @return the same Builder instance.
+ */
+ public @NonNull Builder setSubtitleData(
+ int trackIndex, long startTimeUs, long durationUs, @NonNull byte[] data) {
+ if (data == null) {
+ throw new IllegalArgumentException("null data is not allowed");
+ }
+ mTrackIndex = trackIndex;
+ mStartTimeUs = startTimeUs;
+ mDurationUs = durationUs;
+ mData = data;
+ return this;
+ }
+ }
}
diff --git a/media/java/android/media/TimedMetaData.java b/media/java/android/media/TimedMetaData.java
index 97e6bfa170d8..bcc18ef92f94 100644
--- a/media/java/android/media/TimedMetaData.java
+++ b/media/java/android/media/TimedMetaData.java
@@ -16,8 +16,12 @@
package android.media;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
+import java.util.Arrays;
+
/**
* Class that embodies one timed metadata access unit, including
*
@@ -50,7 +54,10 @@ public final class TimedMetaData {
/**
* @hide
*/
- public TimedMetaData(long timestampUs, byte[] metaData) {
+ public TimedMetaData(long timestampUs, @NonNull byte[] metaData) {
+ if (metaData == null) {
+ throw new IllegalArgumentException("null metaData is not allowed");
+ }
mTimestampUs = timestampUs;
mMetaData = metaData;
}
@@ -83,4 +90,71 @@ public final class TimedMetaData {
return true;
}
+
+ /**
+ * Builder class for {@link TimedMetaData} objects.
+ * <p> Here is an example where <code>Builder</code> is used to define the
+ * {@link TimedMetaData}:
+ *
+ * <pre class="prettyprint">
+ * TimedMetaData tmd = new TimedMetaData.Builder()
+ * .setTimedMetaData(timestamp, metaData)
+ * .build();
+ * </pre>
+ * @hide
+ */
+ @SystemApi
+ public static class Builder {
+ private long mTimestampUs;
+ private byte[] mMetaData = new byte[0];
+
+ /**
+ * Constructs a new Builder with the defaults.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Constructs a new Builder from a given {@link TimedMetaData} instance
+ * @param tmd the {@link TimedMetaData} object whose data will be reused
+ * in the new Builder. It should not be null. The metadata array is copied.
+ */
+ public Builder(@NonNull TimedMetaData tmd) {
+ if (tmd == null) {
+ throw new IllegalArgumentException("null TimedMetaData is not allowed");
+ }
+ mTimestampUs = tmd.mTimestampUs;
+ if (tmd.mMetaData != null) {
+ mMetaData = Arrays.copyOf(tmd.mMetaData, tmd.mMetaData.length);
+ }
+ }
+
+ /**
+ * Combines all of the fields that have been set and return a new
+ * {@link TimedMetaData} object. <code>IllegalStateException</code> will be
+ * thrown if there is conflict between fields.
+ *
+ * @return a new {@link TimedMetaData} object
+ */
+ public @NonNull TimedMetaData build() {
+ return new TimedMetaData(mTimestampUs, mMetaData);
+ }
+
+ /**
+ * Sets the info of timed metadata.
+ *
+ * @param timestamp the timestamp in microsecond for the timed metadata
+ * @param metaData the metadata array for the timed metadata. No data copying is made.
+ * It should not be null.
+ * @return the same Builder instance.
+ */
+ public @NonNull Builder setTimedMetaData(int timestamp, @NonNull byte[] metaData) {
+ if (metaData == null) {
+ throw new IllegalArgumentException("null metaData is not allowed");
+ }
+ mTimestampUs = timestamp;
+ mMetaData = metaData;
+ return this;
+ }
+ }
}
diff --git a/media/java/android/media/UriDataSourceDesc.java b/media/java/android/media/UriDataSourceDesc.java
index 6a83dab14aa4..e39f53c9e19b 100644
--- a/media/java/android/media/UriDataSourceDesc.java
+++ b/media/java/android/media/UriDataSourceDesc.java
@@ -30,7 +30,6 @@ import java.util.List;
import java.util.Map;
/**
- * @hide
* Structure of data source descriptor for sources using URI.
*
* Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)},
diff --git a/media/java/android/media/VideoSize.java b/media/java/android/media/VideoSize.java
index 7e5cb1f457c8..19631e09853d 100644
--- a/media/java/android/media/VideoSize.java
+++ b/media/java/android/media/VideoSize.java
@@ -18,8 +18,6 @@ package android.media;
/**
* Immutable class for describing width and height dimensions.
- *
- * @hide
*/
public final class VideoSize {
/**
@@ -28,7 +26,7 @@ public final class VideoSize {
* @param width The width of the video size
* @param height The height of the video size
*/
- public VideoSize(int width, int height) {
+ VideoSize(int width, int height) {
mWidth = width;
mHeight = height;
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 8215779d2b13..d91cf8732674 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -96,9 +96,15 @@ public final class MediaSessionManager {
* @return The binder object from the system
* @hide
*/
+ @SystemApi
public @NonNull ISession createSession(@NonNull MediaSession.CallbackStub cbStub,
- @NonNull String tag, int userId) throws RemoteException {
- return mService.createSession(mContext.getPackageName(), cbStub, tag, userId);
+ @NonNull String tag, int userId) {
+ try {
+ return mService.createSession(mContext.getPackageName(), cbStub, tag, userId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return null;
}
/**
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 456749279696..8b6009e749ce 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -1192,7 +1192,7 @@ static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArr
}
static void android_media_MediaPlayer2_prepareDrm(JNIEnv *env, jobject thiz,
- jbyteArray uuidObj, jbyteArray drmSessionIdObj)
+ jlong srcId, jbyteArray uuidObj, jbyteArray drmSessionIdObj)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
@@ -1225,7 +1225,7 @@ static void android_media_MediaPlayer2_prepareDrm(JNIEnv *env, jobject thiz,
return;
}
- status_t err = mp->prepareDrm(uuid.array(), drmSessionId);
+ status_t err = mp->prepareDrm(srcId, uuid.array(), drmSessionId);
if (err != OK) {
if (err == INVALID_OPERATION) {
jniThrowException(
@@ -1243,7 +1243,7 @@ static void android_media_MediaPlayer2_prepareDrm(JNIEnv *env, jobject thiz,
}
}
-static void android_media_MediaPlayer2_releaseDrm(JNIEnv *env, jobject thiz)
+static void android_media_MediaPlayer2_releaseDrm(JNIEnv *env, jobject thiz, jlong srcId)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
@@ -1251,7 +1251,7 @@ static void android_media_MediaPlayer2_releaseDrm(JNIEnv *env, jobject thiz)
return;
}
- status_t err = mp->releaseDrm();
+ status_t err = mp->releaseDrm(srcId);
if (err != OK) {
if (err == INVALID_OPERATION) {
jniThrowException(
@@ -1425,8 +1425,8 @@ static const JNINativeMethod gMethods[] = {
{"native_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer2_setAuxEffectSendLevel},
{"native_attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer2_attachAuxEffect},
// Modular DRM
- { "native_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer2_prepareDrm },
- { "native_releaseDrm", "()V", (void *)android_media_MediaPlayer2_releaseDrm },
+ { "native_prepareDrm", "(J[B[B)V", (void *)android_media_MediaPlayer2_prepareDrm },
+ { "native_releaseDrm", "(J)V", (void *)android_media_MediaPlayer2_releaseDrm },
// AudioRouting
{"native_setPreferredDevice", "(Landroid/media/AudioDeviceInfo;)Z", (void *)android_media_MediaPlayer2_setPreferredDevice},
diff --git a/native/webview/plat_support/Android.bp b/native/webview/plat_support/Android.bp
index d8c5ac969128..96c9c1c85a60 100644
--- a/native/webview/plat_support/Android.bp
+++ b/native/webview/plat_support/Android.bp
@@ -23,6 +23,8 @@ cc_library_shared {
srcs: [
"draw_gl_functor.cpp",
+ "draw_vk_functor.cpp",
+ "functor_utils.cpp",
"jni_entry_point.cpp",
"graphics_utils.cpp",
"graphic_buffer_impl.cpp",
@@ -36,6 +38,7 @@ cc_library_shared {
"liblog",
"libui",
"libutils",
+ "libvulkan",
],
// To remove warnings from skia header files
diff --git a/native/webview/plat_support/draw_gl_functor.cpp b/native/webview/plat_support/draw_gl_functor.cpp
index e3e52b1ea1f1..be36b6742037 100644
--- a/native/webview/plat_support/draw_gl_functor.cpp
+++ b/native/webview/plat_support/draw_gl_functor.cpp
@@ -21,15 +21,13 @@
#include "draw_gl.h"
-#include <errno.h>
#include <jni.h>
#include <private/hwui/DrawGlInfo.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <sys/time.h>
#include <utils/Functor.h>
#include <utils/Log.h>
+#include "functor_utils.h"
+
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#define COMPILE_ASSERT(expr, err) \
__unused static const char (err)[(expr) ? 1 : -1] = "";
@@ -98,27 +96,6 @@ class DrawGLFunctor : public Functor {
intptr_t view_context_;
};
-// Raise the file handle soft limit to the hard limit since gralloc buffers
-// uses file handles.
-void RaiseFileNumberLimit() {
- static bool have_raised_limit = false;
- if (have_raised_limit)
- return;
-
- have_raised_limit = true;
- struct rlimit limit_struct;
- limit_struct.rlim_cur = 0;
- limit_struct.rlim_max = 0;
- if (getrlimit(RLIMIT_NOFILE, &limit_struct) == 0) {
- limit_struct.rlim_cur = limit_struct.rlim_max;
- if (setrlimit(RLIMIT_NOFILE, &limit_struct) != 0) {
- ALOGE("setrlimit failed: %s", strerror(errno));
- }
- } else {
- ALOGE("getrlimit failed: %s", strerror(errno));
- }
-}
-
jlong CreateGLFunctor(JNIEnv*, jclass, jlong view_context) {
RaiseFileNumberLimit();
return reinterpret_cast<jlong>(new DrawGLFunctor(view_context));
diff --git a/native/webview/plat_support/draw_vk.h b/native/webview/plat_support/draw_vk.h
new file mode 100644
index 000000000000..6b7d8d0b9118
--- /dev/null
+++ b/native/webview/plat_support/draw_vk.h
@@ -0,0 +1,125 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+//******************************************************************************
+// This is a copy of the coresponding android_webview/public/browser header.
+// Any changes to the interface should be made there.
+//
+// The purpose of having the copy is twofold:
+// - it removes the need to have Chromium sources present in the tree in order
+// to build the plat_support library,
+// - it captures API that the corresponding Android release supports.
+//******************************************************************************
+
+#ifndef ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_VK_H_
+#define ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_VK_H_
+
+#include <vulkan/vulkan.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static const int kAwDrawVKInfoVersion = 1;
+
+// Holds the information required to trigger initialization of the Vulkan
+// functor.
+struct InitParams {
+ // All params are input
+ VkInstance instance;
+ VkPhysicalDevice physical_device;
+ VkDevice device;
+ VkQueue queue;
+ uint32_t graphics_queue_index;
+ uint32_t instance_version;
+ const char* const* enabled_extension_names;
+ // Only one of device_features and device_features_2 should be non-null.
+ // If both are null then no features are enabled.
+ VkPhysicalDeviceFeatures* device_features;
+ VkPhysicalDeviceFeatures2* device_features_2;
+};
+
+// Holds the information required to trigger an Vulkan composite operation.
+struct CompositeParams {
+ // Input: current width/height of destination surface.
+ int width;
+ int height;
+
+ // Input: is the render target a FBO
+ bool is_layer;
+
+ // Input: current transform matrix
+ float transform[16];
+
+ // Input WebView should do its main compositing draws into this. It cannot do
+ // anything that would require stopping the render pass.
+ VkCommandBuffer secondary_command_buffer;
+
+ // Input: The main color attachment index where secondary_command_buffer will
+ // eventually be submitted.
+ uint32_t color_attachment_index;
+
+ // Input: A render pass which will be compatible to the one which the
+ // secondary_command_buffer will be submitted into.
+ VkRenderPass compatible_render_pass;
+
+ // Input: Format of the destination surface.
+ VkFormat format;
+
+ // Input: Color space transfer params
+ float G;
+ float A;
+ float B;
+ float C;
+ float D;
+ float E;
+ float F;
+
+ // Input: Color space transformation from linear RGB to D50-adapted XYZ
+ float matrix[9];
+
+ // Input: current clip rect
+ int clip_left;
+ int clip_top;
+ int clip_right;
+ int clip_bottom;
+};
+
+// Holds the information for the post-submission callback of main composite
+// draw.
+struct PostCompositeParams {
+ // Input: Fence for the composite command buffer to signal it has finished its
+ // work on the GPU.
+ int fd;
+};
+
+// Holds the information required to trigger an Vulkan operation.
+struct AwDrawVKInfo {
+ int version; // The AwDrawVKInfo this struct was built with.
+
+ // Input: tells the draw function what action to perform.
+ enum Mode {
+ kModeInit = 0,
+ kModeReInit = 1,
+ kModePreComposite = 2,
+ kModeComposite = 3,
+ kModePostComposite = 4,
+ kModeSync = 5,
+ } mode;
+
+ // Input: The parameters for the functor being called
+ union ParamUnion {
+ struct InitParams init_params;
+ struct CompositeParams composite_params;
+ struct PostCompositeParams post_composite_params;
+ } info;
+};
+
+typedef void(AwDrawVKFunction)(long view_context, AwDrawVKInfo* draw_info);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // ANDROID_WEBVIEW_PUBLIC_BROWSER_DRAW_VK_H_
diff --git a/native/webview/plat_support/draw_vk_functor.cpp b/native/webview/plat_support/draw_vk_functor.cpp
new file mode 100644
index 000000000000..1ba559d9afdf
--- /dev/null
+++ b/native/webview/plat_support/draw_vk_functor.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+// Provides a webviewchromium glue layer adapter from the internal Android
+// Vulkan Functor data types into the types the chromium stack expects, and
+// back.
+
+#define LOG_TAG "webviewchromium_plat_support"
+
+#include "draw_vk.h"
+
+#include <jni.h>
+#include <private/hwui/DrawVkInfo.h>
+#include <utils/Functor.h>
+#include <utils/Log.h>
+
+#include "functor_utils.h"
+
+#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+
+namespace android {
+namespace {
+
+AwDrawVKFunction* g_aw_drawvk_function = NULL;
+
+class DrawVKFunctor : public Functor {
+ public:
+ explicit DrawVKFunctor(jlong view_context) : view_context_(view_context) {}
+ ~DrawVKFunctor() override {}
+
+ // Functor
+ status_t operator ()(int what, void* data) override {
+ using uirenderer::DrawVkInfo;
+ if (!g_aw_drawvk_function) {
+ ALOGE("Cannot draw: no DrawVK Function installed");
+ return DrawVkInfo::kStatusDone;
+ }
+
+ AwDrawVKInfo aw_info;
+ aw_info.version = kAwDrawVKInfoVersion;
+ switch (what) {
+ case DrawVkInfo::kModeComposite: {
+ aw_info.mode = AwDrawVKInfo::kModeComposite;
+ DrawVkInfo* vk_info = reinterpret_cast<DrawVkInfo*>(data);
+
+ // Map across the input values.
+ CompositeParams& params = aw_info.info.composite_params;
+ params.width = vk_info->width;
+ params.height = vk_info->height;
+ params.is_layer = vk_info->isLayer;
+ for (size_t i = 0; i < 16; i++) {
+ params.transform[i] = vk_info->transform[i];
+ }
+ params.secondary_command_buffer = vk_info->secondaryCommandBuffer;
+ params.color_attachment_index = vk_info->colorAttachmentIndex;
+ params.compatible_render_pass = vk_info->compatibleRenderPass;
+ params.format = vk_info->format;
+ params.G = vk_info->G;
+ params.A = vk_info->A;
+ params.B = vk_info->B;
+ params.C = vk_info->C;
+ params.D = vk_info->D;
+ params.E = vk_info->E;
+ params.F = vk_info->F;
+ for (size_t i = 0; i < 9; i++) {
+ params.matrix[i] = vk_info->matrix[i];
+ }
+ params.clip_left = vk_info->clipLeft;
+ params.clip_top = vk_info->clipTop;
+ params.clip_right = vk_info->clipRight;
+ params.clip_bottom = vk_info->clipBottom;
+
+ break;
+ }
+ case DrawVkInfo::kModePostComposite:
+ break;
+ case DrawVkInfo::kModeSync:
+ aw_info.mode = AwDrawVKInfo::kModeSync;
+ break;
+ default:
+ ALOGE("Unexpected DrawVKInfo type %d", what);
+ return DrawVkInfo::kStatusDone;
+ }
+
+ // Invoke the DrawVK method.
+ g_aw_drawvk_function(view_context_, &aw_info);
+
+ return DrawVkInfo::kStatusDone;
+ }
+
+ private:
+ intptr_t view_context_;
+};
+
+jlong CreateVKFunctor(JNIEnv*, jclass, jlong view_context) {
+ RaiseFileNumberLimit();
+ return reinterpret_cast<jlong>(new DrawVKFunctor(view_context));
+}
+
+void DestroyVKFunctor(JNIEnv*, jclass, jlong functor) {
+ delete reinterpret_cast<DrawVKFunctor*>(functor);
+}
+
+void SetChromiumAwDrawVKFunction(JNIEnv*, jclass, jlong draw_function) {
+ g_aw_drawvk_function = reinterpret_cast<AwDrawVKFunction*>(draw_function);
+}
+
+const char kClassName[] = "com/android/webview/chromium/DrawVKFunctor";
+const JNINativeMethod kJniMethods[] = {
+ { "nativeCreateVKFunctor", "(J)J",
+ reinterpret_cast<void*>(CreateVKFunctor) },
+ { "nativeDestroyVKFunctor", "(J)V",
+ reinterpret_cast<void*>(DestroyVKFunctor) },
+ { "nativeSetChromiumAwDrawVKFunction", "(J)V",
+ reinterpret_cast<void*>(SetChromiumAwDrawVKFunction) },
+};
+
+} // namespace
+
+void RegisterDrawVKFunctor(JNIEnv* env) {
+ jclass clazz = env->FindClass(kClassName);
+ LOG_ALWAYS_FATAL_IF(!clazz, "Unable to find class '%s'", kClassName);
+
+ int res = env->RegisterNatives(clazz, kJniMethods, NELEM(kJniMethods));
+ LOG_ALWAYS_FATAL_IF(res < 0, "register native methods failed: res=%d", res);
+}
+
+} // namespace android
diff --git a/native/webview/plat_support/functor_utils.cpp b/native/webview/plat_support/functor_utils.cpp
new file mode 100644
index 000000000000..235762dc2679
--- /dev/null
+++ b/native/webview/plat_support/functor_utils.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "functor_utils.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <utils/Log.h>
+
+namespace android {
+
+void RaiseFileNumberLimit() {
+ static bool have_raised_limit = false;
+ if (have_raised_limit)
+ return;
+
+ have_raised_limit = true;
+ struct rlimit limit_struct;
+ limit_struct.rlim_cur = 0;
+ limit_struct.rlim_max = 0;
+ if (getrlimit(RLIMIT_NOFILE, &limit_struct) == 0) {
+ limit_struct.rlim_cur = limit_struct.rlim_max;
+ if (setrlimit(RLIMIT_NOFILE, &limit_struct) != 0) {
+ ALOGE("setrlimit failed: %s", strerror(errno));
+ }
+ } else {
+ ALOGE("getrlimit failed: %s", strerror(errno));
+ }
+}
+
+} // namespace android
diff --git a/native/webview/plat_support/functor_utils.h b/native/webview/plat_support/functor_utils.h
new file mode 100644
index 000000000000..76c0bb67d275
--- /dev/null
+++ b/native/webview/plat_support/functor_utils.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+namespace android {
+
+// Raise the file handle soft limit to the hard limit since gralloc buffers
+// uses file handles.
+void RaiseFileNumberLimit();
+
+} // namespace android
diff --git a/packages/SystemUI/res/anim/car_arrow_fade_in_rotate_down.xml b/packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_down.xml
index 74f38d4f9946..74f38d4f9946 100644
--- a/packages/SystemUI/res/anim/car_arrow_fade_in_rotate_down.xml
+++ b/packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_down.xml
diff --git a/packages/SystemUI/res/anim/car_arrow_fade_in_rotate_up.xml b/packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_up.xml
index 0f28297f0214..0f28297f0214 100644
--- a/packages/SystemUI/res/anim/car_arrow_fade_in_rotate_up.xml
+++ b/packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_up.xml
diff --git a/packages/SystemUI/res/anim/car_arrow_fade_out.xml b/packages/CarSystemUI/res/anim/car_arrow_fade_out.xml
index e6757d2862b1..e6757d2862b1 100644
--- a/packages/SystemUI/res/anim/car_arrow_fade_out.xml
+++ b/packages/CarSystemUI/res/anim/car_arrow_fade_out.xml
diff --git a/packages/SystemUI/res/anim/car_user_switcher_close_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_close_animation.xml
index ed637a7adcbf..6f12338d8db8 100644
--- a/packages/SystemUI/res/anim/car_user_switcher_close_animation.xml
+++ b/packages/CarSystemUI/res/anim/car_user_switcher_close_animation.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/anim/car_user_switcher_close_icon_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_close_icon_animation.xml
index 227c981cb72a..9f8c12ef16b5 100644
--- a/packages/SystemUI/res/anim/car_user_switcher_close_icon_animation.xml
+++ b/packages/CarSystemUI/res/anim/car_user_switcher_close_icon_animation.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/anim/car_user_switcher_close_name_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_close_name_animation.xml
index 5901ff41735c..adc1f720e91b 100644
--- a/packages/SystemUI/res/anim/car_user_switcher_close_name_animation.xml
+++ b/packages/CarSystemUI/res/anim/car_user_switcher_close_name_animation.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/anim/car_user_switcher_close_pages_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_close_pages_animation.xml
index 41cbe4b104c3..dec5c05dbce8 100644
--- a/packages/SystemUI/res/anim/car_user_switcher_close_pages_animation.xml
+++ b/packages/CarSystemUI/res/anim/car_user_switcher_close_pages_animation.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/anim/car_user_switcher_close_pod_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_close_pod_animation.xml
index 341e7e0cdfe9..986a9cb06459 100644
--- a/packages/SystemUI/res/anim/car_user_switcher_close_pod_animation.xml
+++ b/packages/CarSystemUI/res/anim/car_user_switcher_close_pod_animation.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/anim/car_user_switcher_open_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_open_animation.xml
index 6ae74131584d..80b38b388aed 100644
--- a/packages/SystemUI/res/anim/car_user_switcher_open_animation.xml
+++ b/packages/CarSystemUI/res/anim/car_user_switcher_open_animation.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/anim/car_user_switcher_open_icon_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_open_icon_animation.xml
index 06ac9e359b57..721376cae960 100644
--- a/packages/SystemUI/res/anim/car_user_switcher_open_icon_animation.xml
+++ b/packages/CarSystemUI/res/anim/car_user_switcher_open_icon_animation.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/anim/car_user_switcher_open_name_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_open_name_animation.xml
index 4baefb83a4ef..246099ef7b35 100644
--- a/packages/SystemUI/res/anim/car_user_switcher_open_name_animation.xml
+++ b/packages/CarSystemUI/res/anim/car_user_switcher_open_name_animation.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/anim/car_user_switcher_open_pages_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_open_pages_animation.xml
index 2d0deb95da59..9a1c642363d0 100644
--- a/packages/SystemUI/res/anim/car_user_switcher_open_pages_animation.xml
+++ b/packages/CarSystemUI/res/anim/car_user_switcher_open_pages_animation.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/anim/car_user_switcher_open_pod_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_open_pod_animation.xml
index 3315220a60ef..1414b6688c8f 100644
--- a/packages/SystemUI/res/anim/car_user_switcher_open_pod_animation.xml
+++ b/packages/CarSystemUI/res/anim/car_user_switcher_open_pod_animation.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/drawable/car_add_circle_round.xml b/packages/CarSystemUI/res/drawable/car_add_circle_round.xml
index 13c7dd12f940..13c7dd12f940 100644
--- a/packages/SystemUI/res/drawable/car_add_circle_round.xml
+++ b/packages/CarSystemUI/res/drawable/car_add_circle_round.xml
diff --git a/packages/SystemUI/res/drawable/car_ic_add_white.xml b/packages/CarSystemUI/res/drawable/car_ic_add_white.xml
index d6818607ec08..d6818607ec08 100644
--- a/packages/SystemUI/res/drawable/car_ic_add_white.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_add_white.xml
diff --git a/packages/SystemUI/res/drawable/car_ic_arrow.xml b/packages/CarSystemUI/res/drawable/car_ic_arrow.xml
index d400ed8c7707..cfacbf98354f 100644
--- a/packages/SystemUI/res/drawable/car_ic_arrow.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_arrow.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2017 The Android Open Source Project
+ ~ Copyright (C) 2018 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/packages/SystemUI/res/drawable/car_ic_arrow_drop_up.xml b/packages/CarSystemUI/res/drawable/car_ic_arrow_drop_up.xml
index 33a512e31675..81e7262c7cea 100644
--- a/packages/SystemUI/res/drawable/car_ic_arrow_drop_up.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_arrow_drop_up.xml
@@ -1,5 +1,5 @@
<!--
- ~ Copyright (C) 2015 The Android Open Source Project
+ ~ Copyright (C) 2018 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/packages/SystemUI/res/drawable/car_ic_hvac.xml b/packages/CarSystemUI/res/drawable/car_ic_hvac.xml
index bdc44b38a176..bdc44b38a176 100644
--- a/packages/SystemUI/res/drawable/car_ic_hvac.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_hvac.xml
diff --git a/packages/SystemUI/res/drawable/car_ic_keyboard_arrow_down.xml b/packages/CarSystemUI/res/drawable/car_ic_keyboard_arrow_down.xml
index 3709aa546766..3709aa546766 100644
--- a/packages/SystemUI/res/drawable/car_ic_keyboard_arrow_down.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_keyboard_arrow_down.xml
diff --git a/packages/SystemUI/res/drawable/car_ic_navigation.xml b/packages/CarSystemUI/res/drawable/car_rounded_bg_bottom.xml
index 328efa08abdd..eb501e5c26eb 100644
--- a/packages/SystemUI/res/drawable/car_ic_navigation.xml
+++ b/packages/CarSystemUI/res/drawable/car_rounded_bg_bottom.xml
@@ -14,15 +14,14 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32dp"
- android:height="37dp"
- android:viewportWidth="32.0"
- android:viewportHeight="37.0">
- <path
- android:pathData="M16.62,0.61L31.33,35.21C31.55,35.72 31.31,36.3 30.8,36.52C30.48,36.66 30.12,36.62 29.83,36.42L15.7,26.44L1.58,36.42C1.13,36.73 0.5,36.63 0.18,36.18C-0.02,35.89 -0.06,35.53 0.08,35.21L14.78,0.61C15,0.1 15.59,-0.14 16.1,0.08C16.33,0.18 16.52,0.37 16.62,0.61Z"
- android:strokeColor="#00000000"
- android:fillType="evenOdd"
- android:fillColor="@color/car_grey_50"
- android:strokeWidth="1"/>
-</vector> \ No newline at end of file
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="?android:attr/colorBackgroundFloating" />
+ <corners
+ android:bottomLeftRadius="@dimen/car_radius_3"
+ android:topLeftRadius="0dp"
+ android:bottomRightRadius="@dimen/car_radius_3"
+ android:topRightRadius="0dp"
+ />
+</shape>
diff --git a/packages/CarSystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml b/packages/CarSystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml
new file mode 100644
index 000000000000..34578fe252d4
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="18.0"
+ android:viewportHeight="18.0">
+ <group
+ android:translateY="0.5"
+ android:translateX="0.5" >
+ <path
+ android:pathData="M9.57,8.5l2.79,-2.78c0.3,-0.3 0.3,-0.8 0,-1.1L9.04,1.29L9.02,1.27C8.7,0.98 8.21,1 7.91,1.31C7.78,1.45 7.71,1.64 7.71,1.84v4.79L4.69,3.61c-0.3,-0.3 -0.79,-0.3 -1.09,0s-0.3,0.79 0,1.09L7.39,8.5L3.6,12.29c-0.3,0.3 -0.3,0.79 0,1.09s0.79,0.3 1.09,0l3.01,-3.01v4.8c0,0.42 0.35,0.77 0.77,0.77c0.19,0 0.39,-0.07 0.53,-0.21l0.04,-0.04l3.32,-3.32c0.3,-0.3 0.3,-0.8 0,-1.1L9.57,8.5zM9.19,6.77v-3.2l1.6,1.6L9.19,6.77zM9.19,13.42v-3.2l1.6,1.6L9.19,13.42zM4.03,9.29c-0.44,0.44 -1.15,0.44 -1.58,0C2.02,8.86 2.02,8.16 2.45,7.72l0.01,-0.01C2.89,7.27 3.59,7.27 4.02,7.7l0.01,0.01C4.47,8.15 4.47,8.85 4.03,9.29zM14.44,7.71c0.44,0.44 0.44,1.15 0,1.58c-0.44,0.44 -1.15,0.44 -1.58,0c-0.44,-0.43 -0.44,-1.13 -0.01,-1.57l0.01,-0.01C13.3,7.28 14,7.27 14.43,7.7C14.44,7.7 14.44,7.71 14.44,7.71z"
+ android:fillColor="#FFFFFF"/>
+ </group>
+</vector>
diff --git a/packages/CarSystemUI/res/drawable/ic_mic_white.xml b/packages/CarSystemUI/res/drawable/ic_mic_white.xml
index f5a91b5ded32..e1e389d7f472 100644
--- a/packages/CarSystemUI/res/drawable/ic_mic_white.xml
+++ b/packages/CarSystemUI/res/drawable/ic_mic_white.xml
@@ -1,3 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
diff --git a/packages/SystemUI/res/layout/car_facet_button.xml b/packages/CarSystemUI/res/layout/car_facet_button.xml
index ad8604935628..8e7ebad7d7ec 100644
--- a/packages/SystemUI/res/layout/car_facet_button.xml
+++ b/packages/CarSystemUI/res/layout/car_facet_button.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
-** Copyright 2017, The Android Open Source Project
+** Copyright 2018, 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/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/CarSystemUI/res/layout/car_fullscreen_user_pod.xml
index ee8d357a0b80..1d6728689933 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
+++ b/packages/CarSystemUI/res/layout/car_fullscreen_user_pod.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2018 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/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
index c9f51486e983..6cd70d62b4f7 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2018 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/packages/SystemUI/res/layout/car_left_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
index 02be45788761..141b28a9ae28 100644
--- a/packages/SystemUI/res/layout/car_left_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
-** Copyright 2016, The Android Open Source Project
+** Copyright 2018, 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/packages/SystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml
index 708f5955f306..708f5955f306 100644
--- a/packages/SystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml
+++ b/packages/CarSystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml
diff --git a/packages/SystemUI/res/layout/car_navigation_button.xml b/packages/CarSystemUI/res/layout/car_navigation_button.xml
index 4062eb8068fa..6d8cca990fa1 100644
--- a/packages/SystemUI/res/layout/car_navigation_button.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_button.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
-** Copyright 2016, The Android Open Source Project
+** Copyright 2018, 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/packages/SystemUI/res/layout/car_qs_footer.xml b/packages/CarSystemUI/res/layout/car_qs_footer.xml
index 3afd4ea33039..6f19cfcfa345 100644
--- a/packages/SystemUI/res/layout/car_qs_footer.xml
+++ b/packages/CarSystemUI/res/layout/car_qs_footer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/CarSystemUI/res/layout/car_qs_panel.xml
index e7413de342fa..dfa48c30b0c8 100644
--- a/packages/SystemUI/res/layout/car_qs_panel.xml
+++ b/packages/CarSystemUI/res/layout/car_qs_panel.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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/packages/SystemUI/res/layout/car_right_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
index 91ba02622e9a..141b28a9ae28 100644
--- a/packages/SystemUI/res/layout/car_right_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
-** Copyright 2016, The Android Open Source Project
+** Copyright 2018, 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.
@@ -58,7 +58,6 @@
android:paddingTop="30dp"
android:paddingBottom="30dp"
/>
-
</LinearLayout>
<LinearLayout
@@ -79,7 +78,6 @@
android:alpha="0.7"
/>
-
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
diff --git a/packages/SystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml
index 708f5955f306..708f5955f306 100644
--- a/packages/SystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml
+++ b/packages/CarSystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml
diff --git a/packages/SystemUI/res/values/colors_car.xml b/packages/CarSystemUI/res/values/colors_car.xml
index 49bfb250acab..2f720f5aba65 100644
--- a/packages/SystemUI/res/values/colors_car.xml
+++ b/packages/CarSystemUI/res/values/colors_car.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
- * Copyright 2017, The Android Open Source Project
+ * Copyright 2018, 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/packages/SystemUI/res/values/dimens_car.xml b/packages/CarSystemUI/res/values/dimens_car.xml
index afbe17632346..c027f81eb8bd 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/CarSystemUI/res/values/dimens_car.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- * Copyright (c) 2016, The Android Open Source Project
+ * Copyright (c) 2018, 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/packages/SystemUI/res/values/ids_car.xml b/packages/CarSystemUI/res/values/ids_car.xml
index 27ed2e250d9f..27ed2e250d9f 100644
--- a/packages/SystemUI/res/values/ids_car.xml
+++ b/packages/CarSystemUI/res/values/ids_car.xml
diff --git a/packages/SystemUI/res/values/integers_car.xml b/packages/CarSystemUI/res/values/integers_car.xml
index fc3623cb69fb..472c957ab568 100644
--- a/packages/SystemUI/res/values/integers_car.xml
+++ b/packages/CarSystemUI/res/values/integers_car.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (c) 2017, The Android Open Source Project
+ Copyright (c) 2018, 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/packages/SystemUI/res/values/strings_car.xml b/packages/CarSystemUI/res/values/strings_car.xml
index 2890cf275b37..83e91c57ccc3 100644
--- a/packages/SystemUI/res/values/strings_car.xml
+++ b/packages/CarSystemUI/res/values/strings_car.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/**
- * Copyright (c) 2016, The Android Open Source Project
+ * Copyright (c) 2018, 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/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
index dfe57044e4e0..f57f26db118c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
@@ -28,6 +28,8 @@ import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
import com.android.systemui.statusbar.car.hvac.HvacController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.volume.CarVolumeDialogComponent;
+import com.android.systemui.volume.VolumeDialogComponent;
/**
* Class factory to provide car specific SystemUI components.
@@ -39,6 +41,10 @@ public class CarSystemUIFactory extends SystemUIFactory {
return new CarStatusBarKeyguardViewManager(context, viewMediatorCallback, lockPatternUtils);
}
+ public VolumeDialogComponent createVolumeDialogComponent(SystemUI systemUi, Context context) {
+ return new CarVolumeDialogComponent(systemUi, context);
+ }
+
@Override
public void injectDependencies(ArrayMap<Object, DependencyProvider> providers,
Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index 50fefe948aa8..0563418e5fb9 100644
--- a/packages/SystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -11,8 +11,9 @@
* 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
+ * limitations under the License.
*/
+
package com.android.systemui.car;
import android.content.Context;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
index 0389030a17b2..b74f1998bf9e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
+++ b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFooter.java
@@ -1,16 +1,19 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
+
package com.android.systemui.qs.car;
import android.content.Context;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
index 3e82c54dc811..41c37d3bbc19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
+++ b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
@@ -1,16 +1,19 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
+
package com.android.systemui.qs.car;
import android.animation.Animator;
@@ -223,7 +226,7 @@ public class CarQSFragment extends Fragment implements QS {
private void animateHeightChange(boolean opening) {
// Animation in progress; cancel it to avoid contention.
- if (mAnimatorSet != null){
+ if (mAnimatorSet != null) {
mAnimatorSet.cancel();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
index 083a7471c3c1..d5dd3c3eaca0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
+++ b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
@@ -1,16 +1,19 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
+
package com.android.systemui.qs.car;
import android.content.Context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
index fc39648b7ac0..58f80a4ed968 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
@@ -58,28 +58,31 @@ public class CarBatteryController extends BroadcastReceiver implements BatteryCo
private final Context mContext;
private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
- private BluetoothHeadsetClient mBluetoothHeadsetClient;
-
private final ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
+ private BluetoothHeadsetClient mBluetoothHeadsetClient;
+ private final ServiceListener mHfpServiceListener = new ServiceListener() {
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (profile == BluetoothProfile.HEADSET_CLIENT) {
+ mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
+ }
+ }
+ @Override
+ public void onServiceDisconnected(int profile) {
+ if (profile == BluetoothProfile.HEADSET_CLIENT) {
+ mBluetoothHeadsetClient = null;
+ }
+ }
+ };
private int mLevel;
-
- /**
- * An interface indicating the container of a View that will display what the information
- * in the {@link CarBatteryController}.
- */
- public interface BatteryViewHandler {
- void hideBatteryView();
- void showBatteryView();
- }
-
private BatteryViewHandler mBatteryViewHandler;
public CarBatteryController(Context context) {
mContext = context;
if (mAdapter == null) {
- return;
+ return;
}
mAdapter.getProfileProxy(context.getApplicationContext(), mHfpServiceListener,
@@ -159,7 +162,7 @@ public class CarBatteryController extends BroadcastReceiver implements BatteryCo
}
BluetoothDevice device =
- (BluetoothDevice)intent.getExtra(BluetoothDevice.EXTRA_DEVICE);
+ (BluetoothDevice) intent.getExtra(BluetoothDevice.EXTRA_DEVICE);
updateBatteryIcon(device, newState);
}
}
@@ -261,20 +264,14 @@ public class CarBatteryController extends BroadcastReceiver implements BatteryCo
}
}
- private final ServiceListener mHfpServiceListener = new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (profile == BluetoothProfile.HEADSET_CLIENT) {
- mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
- }
- }
+ /**
+ * An interface indicating the container of a View that will display what the information
+ * in the {@link CarBatteryController}.
+ */
+ public interface BatteryViewHandler {
+ void hideBatteryView();
- @Override
- public void onServiceDisconnected(int profile) {
- if (profile == BluetoothProfile.HEADSET_CLIENT) {
- mBluetoothHeadsetClient = null;
- }
- }
- };
+ void showBatteryView();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
index 20986adbfe9f..56db242f1eb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 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.car;
import android.app.ActivityManager;
@@ -34,7 +50,6 @@ public class CarFacetButtonController {
* Add facet button to this controller. The expected use is for the facet button
* to get a reference to this controller via {@link com.android.systemui.Dependency}
* and self add.
- * @param facetButton
*/
public void addFacetButton(CarFacetButton facetButton) {
String[] categories = facetButton.getCategories();
@@ -70,15 +85,16 @@ public class CarFacetButtonController {
* They will then be compared with the supplied StackInfo list.
* The StackInfo is expected to be supplied in order of recency and StackInfo will only be used
* for consideration if it has the same displayId as the CarFacetButtons.
- * @param taskInfo of the currently running application
+ *
+ * @param stackInfoList of the currently running application
*/
public void taskChanged(List<ActivityManager.StackInfo> stackInfoList) {
int displayId = getDisplayId();
ActivityManager.StackInfo validStackInfo = null;
- for (ActivityManager.StackInfo stackInfo :stackInfoList) {
+ for (ActivityManager.StackInfo stackInfo : stackInfoList) {
// If the display id is unknown or it matches the stack, it's valid for use
- if ((displayId == -1 || displayId == stackInfo.displayId) &&
- stackInfo.topActivity != null) {
+ if ((displayId == -1 || displayId == stackInfo.displayId)
+ && stackInfo.topActivity != null) {
validStackInfo = stackInfo;
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
index 81f7846b357d..81f7846b357d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 084c136fc555..e640baa4327a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 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.car;
import android.content.Context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 4bff5ba3de7f..2d90f8f0afd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -35,6 +35,8 @@ import com.android.systemui.R;
import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.qs.car.CarQSFragment;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.StatusBarState;
@@ -252,6 +254,11 @@ public class CarStatusBar extends StatusBar implements
addTemperatureViewToController(mStatusBarWindow);
}
+ @Override
+ protected QS createDefaultQSFragment() {
+ return new CarQSFragment();
+ }
+
private BatteryController createBatteryController() {
mCarBatteryController = new CarBatteryController(mContext);
mCarBatteryController.addBatteryViewHandler(this);
@@ -549,7 +556,7 @@ public class CarStatusBar extends StatusBar implements
*/
public void dismissKeyguard() {
executeRunnableDismissingKeyguard(null/* runnable */, null /* cancelAction */,
- true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
+ true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
index d0f06296545b..8c6b9b0107a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 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.car;
import android.content.Context;
@@ -16,13 +32,13 @@ public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManage
ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils) {
super(context, callback, lockPatternUtils);
- mShouldHideNavBar =context.getResources()
+ mShouldHideNavBar = context.getResources()
.getBoolean(R.bool.config_hideNavWhenKeyguardBouncerShown);
}
@Override
protected void updateNavigationBarVisibility(boolean navBarVisible) {
- if(!mShouldHideNavBar) {
+ if (!mShouldHideNavBar) {
return;
}
CarStatusBar statusBar = (CarStatusBar) mStatusBar;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
index f2923f7df248..3288927bf730 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 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.car;
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
@@ -29,7 +45,7 @@ import com.android.systemui.statusbar.policy.BluetoothController;
*/
public class ConnectedDeviceSignalController extends BroadcastReceiver implements
BluetoothController.Callback {
- private final static String TAG = "DeviceSignalCtlr";
+ private static final String TAG = "DeviceSignalCtlr";
/**
* The value that indicates if a network is unavailable. This value is according ot the
@@ -70,6 +86,21 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver implement
private final SignalDrawable mSignalDrawable;
private BluetoothHeadsetClient mBluetoothHeadsetClient;
+ private final ServiceListener mHfpServiceListener = new ServiceListener() {
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (profile == BluetoothProfile.HEADSET_CLIENT) {
+ mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(int profile) {
+ if (profile == BluetoothProfile.HEADSET_CLIENT) {
+ mBluetoothHeadsetClient = null;
+ }
+ }
+ };
public ConnectedDeviceSignalController(Context context, View signalsView) {
mContext = context;
@@ -87,7 +118,7 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver implement
new ScalingDrawableWrapper(mSignalDrawable, mIconScaleFactor));
if (mAdapter == null) {
- return;
+ return;
}
mAdapter.getProfileProxy(context.getApplicationContext(), mHfpServiceListener,
@@ -236,20 +267,4 @@ public class ConnectedDeviceSignalController extends BroadcastReceiver implement
mSignalsView.setVisibility(View.GONE);
}
}
-
- private final ServiceListener mHfpServiceListener = new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (profile == BluetoothProfile.HEADSET_CLIENT) {
- mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- if (profile == BluetoothProfile.HEADSET_CLIENT) {
- mBluetoothHeadsetClient = null;
- }
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
index 47941bf22941..730c3e3440ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
@@ -124,4 +124,4 @@ public class DrivingStateHelper {
Log.d(TAG, message);
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 2ebf5eb39bf6..23fe5944573e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.systemui.statusbar.car;
@@ -44,7 +44,7 @@ public class FullscreenUserSwitcher {
// Initialize user grid.
mUserGridView = container.findViewById(R.id.user_grid);
GridLayoutManager layoutManager = new GridLayoutManager(context,
- context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
+ context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
mUserGridView.getRecyclerView().setLayoutManager(layoutManager);
mUserGridView.buildAdapter();
mUserGridView.setUserSelectionListener(this::onUserSelected);
@@ -54,7 +54,7 @@ public class FullscreenUserSwitcher {
hide();
mShortAnimDuration = container.getResources()
- .getInteger(android.R.integer.config_shortAnimTime);
+ .getInteger(android.R.integer.config_shortAnimTime);
}
/**
@@ -108,4 +108,4 @@ public class FullscreenUserSwitcher {
});
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/SwitchToGuestTimer.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/SwitchToGuestTimer.java
index 0c91cba43390..0c91cba43390 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/SwitchToGuestTimer.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/SwitchToGuestTimer.java
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index d802ed8d6e3a..fb2b57b6d490 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.systemui.statusbar.car;
@@ -210,7 +210,7 @@ public class UserGridRecyclerView extends PagedListView implements
public void onBindViewHolder(UserAdapterViewHolder holder, int position) {
UserRecord userRecord = mUsers.get(position);
RoundedBitmapDrawable circleIcon = RoundedBitmapDrawableFactory.create(mRes,
- getUserRecordIcon(userRecord));
+ getUserRecordIcon(userRecord));
circleIcon.setCircular(true);
holder.mUserAvatarImageView.setImageDrawable(circleIcon);
holder.mUserNameTextView.setText(userRecord.mInfo.name);
@@ -254,13 +254,13 @@ public class UserGridRecyclerView extends PagedListView implements
private void showMaxUserLimitReachedDialog() {
AlertDialog maxUsersDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert)
- .setTitle(R.string.user_limit_reached_title)
- .setMessage(getResources().getQuantityString(
- R.plurals.user_limit_reached_message,
- mCarUserManagerHelper.getMaxSupportedRealUsers(),
- mCarUserManagerHelper.getMaxSupportedRealUsers()))
- .setPositiveButton(android.R.string.ok, null)
- .create();
+ .setTitle(R.string.user_limit_reached_title)
+ .setMessage(getResources().getQuantityString(
+ R.plurals.user_limit_reached_message,
+ mCarUserManagerHelper.getMaxSupportedRealUsers(),
+ mCarUserManagerHelper.getMaxSupportedRealUsers()))
+ .setPositiveButton(android.R.string.ok, null)
+ .create();
// Sets window flags for the SysUI dialog
SystemUIDialog.applyFlags(maxUsersDialog);
maxUsersDialog.show();
@@ -268,17 +268,17 @@ public class UserGridRecyclerView extends PagedListView implements
private void showConfirmAddUserDialog() {
String message = mRes.getString(R.string.user_add_user_message_setup)
- .concat(System.getProperty("line.separator"))
- .concat(System.getProperty("line.separator"))
- .concat(mRes.getString(R.string.user_add_user_message_update));
+ .concat(System.getProperty("line.separator"))
+ .concat(System.getProperty("line.separator"))
+ .concat(mRes.getString(R.string.user_add_user_message_update));
AlertDialog addUserDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert)
- .setTitle(R.string.user_add_user_title)
- .setMessage(message)
- .setNegativeButton(android.R.string.cancel, this)
- .setPositiveButton(android.R.string.ok, this)
- .setOnCancelListener(this)
- .create();
+ .setTitle(R.string.user_add_user_title)
+ .setMessage(message)
+ .setNegativeButton(android.R.string.cancel, this)
+ .setPositiveButton(android.R.string.ok, this)
+ .setOnCancelListener(this)
+ .create();
// Sets window flags for the SysUI dialog
SystemUIDialog.applyFlags(addUserDialog);
addUserDialog.show();
@@ -298,7 +298,7 @@ public class UserGridRecyclerView extends PagedListView implements
if (userRecord.mIsAddUser) {
return UserIcons.convertToBitmap(mContext
- .getDrawable(R.drawable.car_add_circle_round));
+ .getDrawable(R.drawable.car_add_circle_round));
}
return mCarUserManagerHelper.getUserIcon(userRecord.mInfo);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
index 6c924e3c2c16..aec31ee4bfdd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
@@ -41,31 +41,58 @@ import java.util.Objects;
public class HvacController {
public static final String TAG = "HvacController";
- public final static int BIND_TO_HVAC_RETRY_DELAY = 5000;
+ public static final int BIND_TO_HVAC_RETRY_DELAY = 5000;
private Context mContext;
private Handler mHandler;
private Car mCar;
private CarHvacManager mHvacManager;
private HashMap<HvacKey, List<TemperatureView>> mTempComponents = new HashMap<>();
-
- public HvacController(Context context) {
- mContext = context;
- }
-
/**
- * Create connection to the Car service. Note: call backs from the Car service
- * ({@link CarHvacManager}) will happen on the same thread this method was called from.
+ * Callback for getting changes from {@link CarHvacManager} and setting the UI elements to
+ * match.
*/
- public void connectToCarService() {
- mHandler = new Handler();
- mCar = Car.createCar(mContext, mServiceConnection, mHandler);
- if (mCar != null) {
- // note: this connect call handles the retries
- mCar.connect();
+ private final CarHvacEventCallback mHardwareCallback = new CarHvacEventCallback() {
+ @Override
+ public void onChangeEvent(final CarPropertyValue val) {
+ try {
+ int areaId = val.getAreaId();
+ int propertyId = val.getPropertyId();
+ List<TemperatureView> temperatureViews = mTempComponents.get(
+ new HvacKey(propertyId, areaId));
+ if (temperatureViews != null && !temperatureViews.isEmpty()) {
+ float value = (float) val.getValue();
+ for (TemperatureView tempView : temperatureViews) {
+ tempView.setTemp(value);
+ }
+ } // else the data is not of interest
+ } catch (Exception e) {
+ // catch all so we don't take down the sysui if a new data type is
+ // introduced.
+ Log.e(TAG, "Failed handling hvac change event", e);
+ }
}
- }
+ @Override
+ public void onErrorEvent(final int propertyId, final int zone) {
+ Log.d(TAG, "HVAC error event, propertyId: " + propertyId
+ + " zone: " + zone);
+ }
+ };
+ /**
+ * If the connection to car service goes away then restart it.
+ */
+ private final IBinder.DeathRecipient mRestart = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ Log.d(TAG, "Death of HVAC triggering a restart");
+ if (mCar != null) {
+ mCar.disconnect();
+ }
+ destroyHvacManager();
+ mHandler.postDelayed(() -> mCar.connect(), BIND_TO_HVAC_RETRY_DELAY);
+ }
+ };
/**
* Registers callbacks and initializes components upon connection.
*/
@@ -88,6 +115,23 @@ public class HvacController {
}
};
+ public HvacController(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Create connection to the Car service. Note: call backs from the Car service
+ * ({@link CarHvacManager}) will happen on the same thread this method was called from.
+ */
+ public void connectToCarService() {
+ mHandler = new Handler();
+ mCar = Car.createCar(mContext, mServiceConnection, mHandler);
+ if (mCar != null) {
+ // note: this connect call handles the retries
+ mCar.connect();
+ }
+ }
+
private void destroyHvacManager() {
if (mHvacManager != null) {
mHvacManager.unregisterCallback(mHardwareCallback);
@@ -96,23 +140,7 @@ public class HvacController {
}
/**
- * If the connection to car service goes away then restart it.
- */
- private final IBinder.DeathRecipient mRestart = new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- Log.d(TAG, "Death of HVAC triggering a restart");
- if (mCar != null) {
- mCar.disconnect();
- }
- destroyHvacManager();
- mHandler.postDelayed(() -> mCar.connect(), BIND_TO_HVAC_RETRY_DELAY);
- }
- };
-
- /**
* Add component to list and initialize it if the connection is up.
- * @param temperatureView
*/
public void addHvacTextView(TemperatureView temperatureView) {
@@ -136,7 +164,6 @@ public class HvacController {
}
}
-
private void initComponent(TemperatureView view) {
int id = view.getPropertyId();
int zone = view.getAreaId();
@@ -153,38 +180,6 @@ public class HvacController {
}
/**
- * Callback for getting changes from {@link CarHvacManager} and setting the UI elements to
- * match.
- */
- private final CarHvacEventCallback mHardwareCallback = new CarHvacEventCallback() {
- @Override
- public void onChangeEvent(final CarPropertyValue val) {
- try {
- int areaId = val.getAreaId();
- int propertyId = val.getPropertyId();
- List<TemperatureView> temperatureViews = mTempComponents.get(
- new HvacKey(propertyId, areaId));
- if (temperatureViews != null && !temperatureViews.isEmpty()) {
- float value = (float) val.getValue();
- for (TemperatureView tempView : temperatureViews) {
- tempView.setTemp(value);
- }
- } // else the data is not of interest
- } catch (Exception e) {
- // catch all so we don't take down the sysui if a new data type is
- // introduced.
- Log.e(TAG, "Failed handling hvac change event", e);
- }
- }
-
- @Override
- public void onErrorEvent(final int propertyId, final int zone) {
- Log.d(TAG, "HVAC error event, propertyId: " + propertyId +
- " zone: " + zone);
- }
- };
-
- /**
* Removes all registered components. This is useful if you need to rebuild the UI since
* components self register.
*/
@@ -200,7 +195,7 @@ public class HvacController {
int mPropertyId;
int mAreaId;
- public HvacKey(int propertyId, int areaId) {
+ private HvacKey(int propertyId, int areaId) {
mPropertyId = propertyId;
mAreaId = areaId;
}
@@ -210,8 +205,8 @@ public class HvacController {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HvacKey hvacKey = (HvacKey) o;
- return mPropertyId == hvacKey.mPropertyId &&
- mAreaId == hvacKey.mAreaId;
+ return mPropertyId == hvacKey.mPropertyId
+ && mAreaId == hvacKey.mAreaId;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java
index 4d8ce4348319..507c60f87b1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java
@@ -40,7 +40,7 @@ public class TemperatureTextView extends TextView implements TemperatureView {
public TemperatureTextView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
- mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId,-1);
+ mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId, -1);
mPropertyId = typedArray.getInt(R.styleable.TemperatureView_hvacPropertyId, -1);
String format = typedArray.getString(R.styleable.TemperatureView_hvacTempFormat);
mTempFormat = (format == null) ? "%.1f\u00B0" : format;
@@ -48,6 +48,7 @@ public class TemperatureTextView extends TextView implements TemperatureView {
/**
* Formats the float for display
+ *
* @param temp - The current temp or NaN
*/
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
index 7651356f98a3..7651356f98a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
new file mode 100644
index 000000000000..71cc19b63ac1
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.content.Context;
+
+import com.android.systemui.SystemUI;
+import com.android.systemui.plugins.VolumeDialog;
+
+/**
+ * Allows for adding car specific dialog when the volume dialog is created.
+ */
+public class CarVolumeDialogComponent extends VolumeDialogComponent {
+
+ public CarVolumeDialogComponent(SystemUI sysui, Context context) {
+ super(sysui, context);
+ }
+
+ protected VolumeDialog createDefault() {
+ return new CarVolumeDialogImpl(mContext);
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
new file mode 100644
index 000000000000..12df263ffede
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.annotation.DrawableRes;
+import android.annotation.Nullable;
+import android.app.Dialog;
+import android.app.KeyguardManager;
+import android.car.Car;
+import android.car.CarNotConnectedException;
+import android.car.media.CarAudioManager;
+import android.car.media.ICarVolumeCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.ServiceConnection;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
+import android.os.Debug;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.Xml;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+
+import androidx.car.widget.ListItem;
+import androidx.car.widget.ListItemAdapter;
+import androidx.car.widget.ListItemAdapter.BackgroundStyle;
+import androidx.car.widget.ListItemProvider.ListProvider;
+import androidx.car.widget.PagedListView;
+import androidx.car.widget.SeekbarListItem;
+
+import com.android.systemui.R;
+import com.android.systemui.plugins.VolumeDialog;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Car version of the volume dialog.
+ *
+ * Methods ending in "H" must be called on the (ui) handler.
+ */
+public class CarVolumeDialogImpl implements VolumeDialog {
+
+ private static final String TAG = Util.logTag(CarVolumeDialogImpl.class);
+
+ private static final String XML_TAG_VOLUME_ITEMS = "carVolumeItems";
+ private static final String XML_TAG_VOLUME_ITEM = "item";
+ private static final int HOVERING_TIMEOUT = 16000;
+ private static final int NORMAL_TIMEOUT = 3000;
+ private static final int LISTVIEW_ANIMATION_DURATION_IN_MILLIS = 250;
+ private static final int DISMISS_DELAY_IN_MILLIS = 50;
+ private static final int ARROW_FADE_IN_START_DELAY_IN_MILLIS = 100;
+
+ private final Context mContext;
+ private final H mHandler = new H();
+ // All the volume items.
+ private final SparseArray<VolumeItem> mVolumeItems = new SparseArray<>();
+ // Available volume items in car audio manager.
+ private final List<VolumeItem> mAvailableVolumeItems = new ArrayList<>();
+ // Volume items in the PagedListView.
+ private final List<ListItem> mVolumeLineItems = new ArrayList<>();
+ private final KeyguardManager mKeyguard;
+ private Window mWindow;
+ private CustomDialog mDialog;
+ private PagedListView mListView;
+ private ListItemAdapter mPagedListAdapter;
+ private Car mCar;
+ private CarAudioManager mCarAudioManager;
+ private final ICarVolumeCallback mVolumeChangeCallback = new ICarVolumeCallback.Stub() {
+ @Override
+ public void onGroupVolumeChanged(int groupId, int flags) {
+ VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
+ int value = getSeekbarValue(mCarAudioManager, groupId);
+ // Do not update the progress if it is the same as before. When car audio manager sets
+ // its group volume caused by the seekbar progress changed, it also triggers this
+ // callback. Updating the seekbar at the same time could block the continuous seeking.
+ if (value != volumeItem.progress) {
+ volumeItem.listItem.setProgress(value);
+ volumeItem.progress = value;
+ }
+ if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
+ mHandler.obtainMessage(H.SHOW, Events.SHOW_REASON_VOLUME_CHANGED).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onMasterMuteChanged(int flags) {
+ // ignored
+ }
+ };
+ private boolean mHovering;
+ private boolean mShowing;
+ private boolean mExpanded;
+ private final ServiceConnection mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ try {
+ mExpanded = false;
+ mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
+ int volumeGroupCount = mCarAudioManager.getVolumeGroupCount();
+ // Populates volume slider items from volume groups to UI.
+ for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
+ VolumeItem volumeItem = getVolumeItemForUsages(
+ mCarAudioManager.getUsagesForVolumeGroupId(groupId));
+ mAvailableVolumeItems.add(volumeItem);
+ // The first one is the default item.
+ if (groupId == 0) {
+ volumeItem.defaultItem = true;
+ addSeekbarListItem(volumeItem, groupId,
+ R.drawable.car_ic_keyboard_arrow_down,
+ new ExpandIconListener());
+ }
+ }
+
+ // If list is already initiated, update its content.
+ if (mPagedListAdapter != null) {
+ mPagedListAdapter.notifyDataSetChanged();
+ }
+ mCarAudioManager.registerVolumeCallback(mVolumeChangeCallback.asBinder());
+ } catch (CarNotConnectedException e) {
+ Log.e(TAG, "Car is not connected!", e);
+ }
+ }
+
+ /**
+ * This does not get called when service is properly disconnected.
+ * So we need to also handle cleanups in destroy().
+ */
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ cleanupAudioManager();
+ }
+ };
+
+ public CarVolumeDialogImpl(Context context) {
+ mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
+ mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ mCar = Car.createCar(mContext, mServiceConnection);
+ }
+
+ private static int getSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
+ try {
+ return carAudioManager.getGroupVolume(volumeGroupId);
+ } catch (CarNotConnectedException e) {
+ Log.e(TAG, "Car is not connected!", e);
+ }
+ return 0;
+ }
+
+ private static int getMaxSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
+ try {
+ return carAudioManager.getGroupMaxVolume(volumeGroupId);
+ } catch (CarNotConnectedException e) {
+ Log.e(TAG, "Car is not connected!", e);
+ }
+ return 0;
+ }
+
+ /**
+ * Build the volume window and connect to the CarService which registers with car audio
+ * manager.
+ */
+ @Override
+ public void init(int windowType, Callback callback) {
+ initDialog();
+
+ mCar.connect();
+ }
+
+ @Override
+ public void destroy() {
+ mHandler.removeCallbacksAndMessages(null);
+
+ cleanupAudioManager();
+ // unregisterVolumeCallback is not being called when disconnect car, so we manually cleanup
+ // audio manager beforehand.
+ mCar.disconnect();
+ }
+
+ private void initDialog() {
+ loadAudioUsageItems();
+ mVolumeLineItems.clear();
+ mDialog = new CustomDialog(mContext);
+
+ mHovering = false;
+ mShowing = false;
+ mExpanded = false;
+ mWindow = mDialog.getWindow();
+ mWindow.requestFeature(Window.FEATURE_NO_TITLE);
+ mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+ mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
+ mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+ mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+ mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
+ final WindowManager.LayoutParams lp = mWindow.getAttributes();
+ lp.format = PixelFormat.TRANSLUCENT;
+ lp.setTitle(VolumeDialogImpl.class.getSimpleName());
+ lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
+ lp.windowAnimations = -1;
+ mWindow.setAttributes(lp);
+ mWindow.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ mDialog.setCanceledOnTouchOutside(true);
+ mDialog.setContentView(R.layout.car_volume_dialog);
+ mDialog.setOnShowListener(dialog -> {
+ mListView.setTranslationY(-mListView.getHeight());
+ mListView.setAlpha(0);
+ mListView.animate()
+ .alpha(1)
+ .translationY(0)
+ .setDuration(LISTVIEW_ANIMATION_DURATION_IN_MILLIS)
+ .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
+ .start();
+ });
+ mListView = (PagedListView) mWindow.findViewById(R.id.volume_list);
+ mListView.setOnHoverListener((v, event) -> {
+ int action = event.getActionMasked();
+ mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
+ || (action == MotionEvent.ACTION_HOVER_MOVE);
+ rescheduleTimeoutH();
+ return true;
+ });
+
+ mPagedListAdapter = new ListItemAdapter(mContext, new ListProvider(mVolumeLineItems),
+ BackgroundStyle.PANEL);
+ mListView.setAdapter(mPagedListAdapter);
+ mListView.setMaxPages(PagedListView.UNLIMITED_PAGES);
+ }
+
+
+ private void showH(int reason) {
+ if (D.BUG) {
+ Log.d(TAG, "showH r=" + Events.DISMISS_REASONS[reason]);
+ }
+
+ mHandler.removeMessages(H.SHOW);
+ mHandler.removeMessages(H.DISMISS);
+ rescheduleTimeoutH();
+ // Refresh the data set before showing.
+ mPagedListAdapter.notifyDataSetChanged();
+ if (mShowing) {
+ return;
+ }
+ mShowing = true;
+
+ mDialog.show();
+ Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
+ }
+
+ private void rescheduleTimeoutH() {
+ mHandler.removeMessages(H.DISMISS);
+ final int timeout = computeTimeoutH();
+ mHandler.sendMessageDelayed(mHandler
+ .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT), timeout);
+
+ if (D.BUG) {
+ Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller());
+ }
+ }
+
+ private int computeTimeoutH() {
+ return mHovering ? HOVERING_TIMEOUT : NORMAL_TIMEOUT;
+ }
+
+ private void dismissH(int reason) {
+ if (D.BUG) {
+ Log.d(TAG, "dismissH r=" + Events.DISMISS_REASONS[reason]);
+ }
+
+ mHandler.removeMessages(H.DISMISS);
+ mHandler.removeMessages(H.SHOW);
+ if (!mShowing) {
+ return;
+ }
+
+ mListView.animate().cancel();
+
+ mListView.setTranslationY(0);
+ mListView.setAlpha(1);
+ mListView.animate()
+ .alpha(0)
+ .translationY(-mListView.getHeight())
+ .setDuration(LISTVIEW_ANIMATION_DURATION_IN_MILLIS)
+ .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
+ .withEndAction(() -> mHandler.postDelayed(() -> {
+ if (D.BUG) {
+ Log.d(TAG, "mDialog.dismiss()");
+ }
+ mDialog.dismiss();
+ mShowing = false;
+ }, DISMISS_DELAY_IN_MILLIS))
+ .start();
+
+ Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason);
+ }
+
+ private void loadAudioUsageItems() {
+ try (XmlResourceParser parser = mContext.getResources().getXml(R.xml.car_volume_items)) {
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+ int type;
+ // Traverse to the first start tag
+ while ((type = parser.next()) != XmlResourceParser.END_DOCUMENT
+ && type != XmlResourceParser.START_TAG) {
+ // Do Nothing (moving parser to start element)
+ }
+
+ if (!XML_TAG_VOLUME_ITEMS.equals(parser.getName())) {
+ throw new RuntimeException("Meta-data does not start with carVolumeItems tag");
+ }
+ int outerDepth = parser.getDepth();
+ int rank = 0;
+ while ((type = parser.next()) != XmlResourceParser.END_DOCUMENT
+ && (type != XmlResourceParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlResourceParser.END_TAG) {
+ continue;
+ }
+ if (XML_TAG_VOLUME_ITEM.equals(parser.getName())) {
+ TypedArray item = mContext.getResources().obtainAttributes(
+ attrs, R.styleable.carVolumeItems_item);
+ int usage = item.getInt(R.styleable.carVolumeItems_item_usage, -1);
+ if (usage >= 0) {
+ VolumeItem volumeItem = new VolumeItem();
+ volumeItem.rank = rank;
+ volumeItem.icon = item.getResourceId(R.styleable.carVolumeItems_item_icon,
+ 0);
+ mVolumeItems.put(usage, volumeItem);
+ rank++;
+ }
+ item.recycle();
+ }
+ }
+ } catch (XmlPullParserException | IOException e) {
+ Log.e(TAG, "Error parsing volume groups configuration", e);
+ }
+ }
+
+ private VolumeItem getVolumeItemForUsages(int[] usages) {
+ int rank = Integer.MAX_VALUE;
+ VolumeItem result = null;
+ for (int usage : usages) {
+ VolumeItem volumeItem = mVolumeItems.get(usage);
+ if (volumeItem.rank < rank) {
+ rank = volumeItem.rank;
+ result = volumeItem;
+ }
+ }
+ return result;
+ }
+
+ private SeekbarListItem addSeekbarListItem(VolumeItem volumeItem,
+ int volumeGroupId,
+ int supplementalIconId,
+ @Nullable View.OnClickListener supplementalIconOnClickListener) {
+ SeekbarListItem listItem = new SeekbarListItem(mContext);
+ listItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
+ int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
+ int progress = getSeekbarValue(mCarAudioManager, volumeGroupId);
+ listItem.setProgress(progress);
+ listItem.setOnSeekBarChangeListener(new CarVolumeDialogImpl
+ .VolumeSeekBarChangeListener(volumeGroupId, mCarAudioManager));
+ Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
+ primaryIcon.mutate().setTint(color);
+ listItem.setPrimaryActionIcon(primaryIcon);
+ if (supplementalIconId != 0) {
+ Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId);
+ supplementalIcon.mutate().setTint(color);
+ listItem.setSupplementalIcon(supplementalIcon, true);
+ listItem.setSupplementalIconListener(supplementalIconOnClickListener);
+ } else {
+ listItem.setSupplementalEmptyIcon(true);
+ listItem.setSupplementalIconListener(null);
+ }
+
+ mVolumeLineItems.add(listItem);
+ volumeItem.listItem = listItem;
+ volumeItem.progress = progress;
+ return listItem;
+ }
+
+ private VolumeItem findVolumeItem(SeekbarListItem targetItem) {
+ for (int i = 0; i < mVolumeItems.size(); ++i) {
+ VolumeItem volumeItem = mVolumeItems.valueAt(i);
+ if (volumeItem.listItem == targetItem) {
+ return volumeItem;
+ }
+ }
+ return null;
+ }
+
+ private void cleanupAudioManager() {
+ try {
+ mCarAudioManager.unregisterVolumeCallback(mVolumeChangeCallback.asBinder());
+ } catch (CarNotConnectedException e) {
+ Log.e(TAG, "Car is not connected!", e);
+ }
+ mVolumeLineItems.clear();
+ mCarAudioManager = null;
+ }
+
+ /**
+ * Wrapper class which contains information of each volume group.
+ */
+ private static class VolumeItem {
+
+ private int rank;
+ private boolean defaultItem = false;
+ private @DrawableRes int icon;
+ private SeekbarListItem listItem;
+ private int progress;
+ }
+
+ private final class H extends Handler {
+
+ private static final int SHOW = 1;
+ private static final int DISMISS = 2;
+
+ private H() {
+ super(Looper.getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SHOW:
+ showH(msg.arg1);
+ break;
+ case DISMISS:
+ dismissH(msg.arg1);
+ break;
+ default:
+ }
+ }
+ }
+
+ private final class CustomDialog extends Dialog implements DialogInterface {
+
+ private CustomDialog(Context context) {
+ super(context, com.android.systemui.R.style.qs_theme);
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ rescheduleTimeoutH();
+ return super.dispatchTouchEvent(ev);
+ }
+
+ @Override
+ protected void onStart() {
+ super.setCanceledOnTouchOutside(true);
+ super.onStart();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (isShowing()) {
+ if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+ mHandler.obtainMessage(
+ H.DISMISS, Events.DISMISS_REASON_TOUCH_OUTSIDE).sendToTarget();
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private final class ExpandIconListener implements View.OnClickListener {
+
+ @Override
+ public void onClick(final View v) {
+ mExpanded = !mExpanded;
+ Animator inAnimator;
+ if (mExpanded) {
+ for (int groupId = 0; groupId < mAvailableVolumeItems.size(); ++groupId) {
+ // Adding the items which are not coming from the default item.
+ VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
+ if (volumeItem.defaultItem) {
+ // Set progress here due to the progress of seekbar may not be updated.
+ volumeItem.listItem.setProgress(volumeItem.progress);
+ } else {
+ addSeekbarListItem(volumeItem, groupId, 0, null);
+ }
+ }
+ inAnimator = AnimatorInflater.loadAnimator(
+ mContext, R.anim.car_arrow_fade_in_rotate_up);
+ } else {
+ // Only keeping the default stream if it is not expended.
+ Iterator itr = mVolumeLineItems.iterator();
+ while (itr.hasNext()) {
+ SeekbarListItem seekbarListItem = (SeekbarListItem) itr.next();
+ VolumeItem volumeItem = findVolumeItem(seekbarListItem);
+ if (!volumeItem.defaultItem) {
+ itr.remove();
+ } else {
+ // Set progress here due to the progress of seekbar may not be updated.
+ seekbarListItem.setProgress(volumeItem.progress);
+ }
+ }
+ inAnimator = AnimatorInflater.loadAnimator(
+ mContext, R.anim.car_arrow_fade_in_rotate_down);
+ }
+
+ Animator outAnimator = AnimatorInflater.loadAnimator(
+ mContext, R.anim.car_arrow_fade_out);
+ inAnimator.setStartDelay(ARROW_FADE_IN_START_DELAY_IN_MILLIS);
+ AnimatorSet animators = new AnimatorSet();
+ animators.playTogether(outAnimator, inAnimator);
+ animators.setTarget(v);
+ animators.start();
+ mPagedListAdapter.notifyDataSetChanged();
+ }
+ }
+
+ private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
+
+ private final int mVolumeGroupId;
+ private final CarAudioManager mCarAudioManager;
+
+ private VolumeSeekBarChangeListener(int volumeGroupId, CarAudioManager carAudioManager) {
+ mVolumeGroupId = volumeGroupId;
+ mCarAudioManager = carAudioManager;
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (!fromUser) {
+ // For instance, if this event is originated from AudioService,
+ // we can ignore it as it has already been handled and doesn't need to be
+ // sent back down again.
+ return;
+ }
+ try {
+ if (mCarAudioManager == null) {
+ Log.w(TAG, "Ignoring volume change event because the car isn't connected");
+ return;
+ }
+ mAvailableVolumeItems.get(mVolumeGroupId).progress = progress;
+ mCarAudioManager.setGroupVolume(mVolumeGroupId, progress, 0);
+ } catch (CarNotConnectedException e) {
+ Log.e(TAG, "Car is not connected!", e);
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ }
+}
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 4b212c25c89e..0cad5af00267 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -19,8 +19,7 @@ package android.ext.services.notification;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
-import static android.service.notification.NotificationListenerService.Ranking
- .USER_SENTIMENT_NEGATIVE;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -241,7 +240,7 @@ public class Assistant extends NotificationAssistantService {
signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies);
}
if (Settings.Secure.getInt(getContentResolver(),
- Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL, 0) == 1) {
+ Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL, 1) == 1) {
if (mNotificationCategorizer.shouldSilence(entry)) {
final int importance = entry.getImportance() < IMPORTANCE_LOW
? entry.getImportance() : IMPORTANCE_LOW;
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index c9ee5c87de0f..1eb4b7494085 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -224,7 +224,7 @@ public class ExternalStorageProvider extends FileSystemProvider {
root.flags |= Root.FLAG_REMOVABLE_USB;
}
- if (!VolumeInfo.ID_EMULATED_INTERNAL.equals(volume.getId())) {
+ if (volume.getType() != VolumeInfo.TYPE_EMULATED) {
root.flags |= Root.FLAG_SUPPORTS_EJECT;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 56b768feee23..df5b1467f9d9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1165,6 +1165,12 @@ class SettingsProtoDumpUtil {
GlobalSettingsProto.SmartSelection.UPDATE_METADATA_URL);
p.end(smartSelectToken);
+ final long smartSuggestionsToken = p.start(GlobalSettingsProto.SMART_SUGGESTIONS);
+ dumpSetting(s, p,
+ Settings.Global.SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED,
+ GlobalSettingsProto.SmartSuggestions.SERVICE_EXPLICITLY_ENABLED);
+ p.end(smartSuggestionsToken);
+
final long smsToken = p.start(GlobalSettingsProto.SMS);
dumpSetting(s, p,
Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
@@ -1306,6 +1312,9 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.WARNING_TEMPERATURE,
GlobalSettingsProto.TemperatureWarning.WARNING_TEMPERATURE_LEVEL);
+ dumpSetting(s, p,
+ Settings.Global.USB_ALARM_TEMPERATURE,
+ GlobalSettingsProto.TemperatureWarning.USB_ALARM_TEMPERATURE_LEVEL);
p.end(tempWarningToken);
final long tetherToken = p.start(GlobalSettingsProto.TETHER);
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 0b9b27f238d7..7d53c2f78151 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -223,6 +223,9 @@
<uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" />
+ <!-- Permission to change the display color -->
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+
<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/drawable/car_ic_music.xml b/packages/SystemUI/res/drawable/car_ic_music.xml
deleted file mode 100644
index f90cd69c1b39..000000000000
--- a/packages/SystemUI/res/drawable/car_ic_music.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="56dp"
- android:height="56dp"
- android:viewportWidth="48"
- android:viewportHeight="48">
-
- <path
- android:fillAlpha=".1"
- android:strokeAlpha=".1"
- android:pathData="M0 0h48v48H0z" />
- <path
- android:fillColor="@color/car_grey_50"
- android:pathData="M24 2C14.06 2 6 10.06 6 20v14c0 3.31 2.69 6 6 6h6V24h-8v-4c0-7.73 6.27-14
-14-14s14 6.27 14 14v4h-8v16h6c3.31 0 6-2.69 6-6V20c0-9.94-8.06-18-18-18z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/car_ic_notification.xml b/packages/SystemUI/res/drawable/car_ic_notification.xml
deleted file mode 100644
index 61d937b90d04..000000000000
--- a/packages/SystemUI/res/drawable/car_ic_notification.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="56dp"
- android:height="56dp"
- android:viewportWidth="48"
- android:viewportHeight="48">
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M24 44c2.21 0 4-1.79 4-4h-8c0 2.21 1.79 4 4
-4zm12-12V22c0-6.15-3.27-11.28-9-12.64V8c0-1.66-1.34-3-3-3s-3 1.34-3 3v1.36c-5.73
-1.36-9 6.49-9 12.64v10l-4 4v2h32v-2l-4-4zm-4 2H16V22c0-4.97 3.03-9 8-9s8 4.03 8
-9v12z" />
-</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/car_ic_overview.xml b/packages/SystemUI/res/drawable/car_ic_overview.xml
deleted file mode 100644
index 4651dcb3a229..000000000000
--- a/packages/SystemUI/res/drawable/car_ic_overview.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="56dp"
- android:height="56dp"
- android:viewportWidth="48"
- android:viewportHeight="48">
-
- <path
- android:pathData="M0 0h48v48H0z" />
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm0 36c-8.82
-0-16-7.18-16-16S15.18 8 24 8s16 7.18 16 16-7.18 16-16 16z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/car_rounded_bg_bottom.xml b/packages/SystemUI/res/drawable/car_rounded_bg_bottom.xml
deleted file mode 100644
index 25b449ab3a8a..000000000000
--- a/packages/SystemUI/res/drawable/car_rounded_bg_bottom.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?android:attr/colorBackgroundFloating" />
- <corners
- android:bottomLeftRadius="@dimen/car_radius_3"
- android:topLeftRadius="0dp"
- android:bottomRightRadius="@dimen/car_radius_3"
- android:topRightRadius="0dp"
- />
-</shape>
diff --git a/packages/SystemUI/res/layout/car_navigation_bar.xml b/packages/SystemUI/res/layout/car_navigation_bar.xml
deleted file mode 100644
index d568d0d3c179..000000000000
--- a/packages/SystemUI/res/layout/car_navigation_bar.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<com.android.systemui.statusbar.car.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:background="@drawable/system_bar_background">
-
- <LinearLayout
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:orientation="horizontal"
- android:id="@+id/nav_buttons"
- android:gravity="left"
- android:paddingLeft="30dp"
- android:layout_weight="1"
- android:animateLayoutChanges="true">
-
- <com.android.systemui.statusbar.car.CarNavigationButton
- android:id="@+id/home"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- android:src="@drawable/car_ic_overview"
- android:background="?android:attr/selectableItemBackground"
- android:paddingLeft="30dp"
- android:paddingRight="30dp"
- />
-
- <com.android.systemui.statusbar.car.CarNavigationButton
- android:id="@+id/hvac"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- systemui:broadcast="true"
- android:src="@drawable/car_ic_hvac"
- android:background="?android:attr/selectableItemBackground"
- android:paddingLeft="30dp"
- android:paddingRight="30dp"
- />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="right"
- android:orientation="horizontal">
-
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/notifications"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:src="@drawable/car_ic_notification"
- android:background="?android:attr/selectableItemBackground"
- android:paddingLeft="20dp"
- android:paddingRight="20dp"
- android:alpha="0.7"
- />
-
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:singleLine="true"
- android:paddingStart="@dimen/status_bar_clock_starting_padding"
- android:paddingEnd="@dimen/status_bar_clock_end_padding"
- android:gravity="center_vertical"
- android:paddingRight="20dp"
- />
-
- <Space
- android:layout_width="10dp"
- android:layout_height="match_parent"/>
-
- </LinearLayout>
-
-</com.android.systemui.statusbar.car.CarNavigationBarView>
-
diff --git a/packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml b/packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml
deleted file mode 100644
index 4ba6c06d80a1..000000000000
--- a/packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<com.android.systemui.statusbar.car.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:background="@drawable/system_bar_background">
-
- <LinearLayout
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:orientation="horizontal"
- android:id="@+id/nav_buttons"
- android:gravity="left"
- android:paddingLeft="30dp"
- android:layout_weight="1"
- android:animateLayoutChanges="true">
-
- <com.android.systemui.statusbar.car.CarNavigationButton
- android:id="@+id/home"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- android:src="@drawable/car_ic_overview"
- android:background="?android:attr/selectableItemBackground"
- android:paddingLeft="30dp"
- android:paddingRight="30dp"
- />
-
- <com.android.systemui.statusbar.car.CarNavigationButton
- android:id="@+id/hvac"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- systemui:broadcast="true"
- android:src="@drawable/car_ic_hvac"
- android:background="?android:attr/selectableItemBackground"
- android:paddingLeft="30dp"
- android:paddingRight="30dp"
- />
- </LinearLayout>
-</com.android.systemui.statusbar.car.CarNavigationBarView>
-
diff --git a/packages/SystemUI/res/layout/car_status_bar_header.xml b/packages/SystemUI/res/layout/car_status_bar_header.xml
deleted file mode 100644
index f2ef30180bc0..000000000000
--- a/packages/SystemUI/res/layout/car_status_bar_header.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!-- Extends LinearLayout -->
-<com.android.systemui.qs.car.CarStatusBarHeader
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:id="@+id/header"
- android:layout_width="match_parent"
- android:layout_height="@dimen/car_qs_header_system_icons_area_height"
- android:paddingStart="8dp"
- android:paddingEnd="8dp" >
-
- <include layout="@layout/system_icons"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical|end"
- android:layout_weight="1"
- />
-
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:singleLine="true"
- android:paddingStart="@dimen/status_bar_clock_starting_padding"
- android:paddingEnd="@dimen/status_bar_clock_end_padding"
- android:gravity="center_vertical|end"
- />
-</com.android.systemui.qs.car.CarStatusBarHeader>
diff --git a/packages/SystemUI/res/layout/car_top_navigation_bar.xml b/packages/SystemUI/res/layout/car_top_navigation_bar.xml
deleted file mode 100644
index e16014bb8945..000000000000
--- a/packages/SystemUI/res/layout/car_top_navigation_bar.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<com.android.systemui.statusbar.car.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:background="@drawable/system_bar_background">
-
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:singleLine="true"
- android:paddingStart="@dimen/status_bar_clock_starting_padding"
- android:paddingEnd="@dimen/status_bar_clock_end_padding"
- android:gravity="center_vertical"
- />
-
-</com.android.systemui.statusbar.car.CarNavigationBarView>
-
diff --git a/packages/SystemUI/res/layout/car_volume_dialog.xml b/packages/SystemUI/res/layout/car_volume_dialog.xml
deleted file mode 100644
index a6beaa15a4bf..000000000000
--- a/packages/SystemUI/res/layout/car_volume_dialog.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
- Copyright (C) 2018 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.
--->
-<androidx.car.widget.PagedListView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:background="@drawable/car_card_rounded_background"
- android:id="@+id/volume_list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/car_margin"
- android:layout_marginEnd="@dimen/car_margin"
- android:minWidth="@dimen/volume_dialog_panel_width"
- android:theme="@style/Theme.Car.NoActionBar"
- app:dividerStartMargin="@dimen/car_keyline_1"
- app:dividerEndMargin="@dimen/car_keyline_1"
- app:gutter="none"
- app:showPagedListViewDivider="true"
- app:scrollBarEnabled="false" />
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 0cc3c9eb55dc..34c208ab81aa 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -56,11 +56,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
- <ViewStub android:id="@+id/fullscreen_user_switcher_stub"
- android:layout="@layout/car_fullscreen_user_switcher"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-
<include layout="@layout/status_bar_expanded"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b0a519c00943..8e0bfb65428e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -881,6 +881,7 @@
<dimen name="smart_reply_button_stroke_width">1dp</dimen>
<dimen name="smart_reply_button_font_size">14sp</dimen>
<dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
+ <dimen name="smart_action_button_icon_size">24dp</dimen>
<dimen name="smart_action_button_icon_padding">10dp</dimen>
<!-- A reasonable upper bound for the height of the smart reply button. The measuring code
diff --git a/packages/SystemUI/res/xml/car_volume_items.xml b/packages/SystemUI/res/xml/car_volume_items.xml
deleted file mode 100644
index 742dfdda73c8..000000000000
--- a/packages/SystemUI/res/xml/car_volume_items.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- *
- * Copyright 2018, 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.
-*/
--->
-
-<!--
- Defines all possible items on car volume settings UI, keyed by usage.
-
- This enables the CarSettings UI to associate VolumeGroups surfaced by
- CarAudioManager.getVolumeGroupCount with renderable assets (ie: title, icon)
- for presentation.
-
- Order matters in this configuration. If one volume group contains multiple
- audio usages, the first one appears in this file would be picked to be
- presented on UI.
-
- When overriding this configuration, please consult also the
- car_volume_groups.xml, which is read by car audio service.
--->
-<carVolumeItems xmlns:car="http://schemas.android.com/apk/res-auto">
- <item car:usage="unknown"
- car:icon="@drawable/car_ic_music"/>
- <item car:usage="media"
- car:icon="@drawable/car_ic_music"/>
- <item car:usage="voice_communication"
- car:icon="@*android:drawable/ic_audio_ring_notif"/>
- <item car:usage="voice_communication_signalling"
- car:icon="@*android:drawable/ic_audio_ring_notif"/>
- <item car:usage="alarm"
- car:icon="@*android:drawable/ic_audio_alarm"/>
- <item car:usage="notification"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="notification_ringtone"
- car:icon="@*android:drawable/ic_audio_ring_notif"/>
- <item car:usage="notification_communication_request"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="notification_communication_instant"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="notification_communication_delayed"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="notification_event"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="assistance_accessibility"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="assistance_navigation_guidance"
- car:icon="@drawable/car_ic_navigation"/>
- <item car:usage="assistance_sonification"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="game"
- car:icon="@drawable/car_ic_music"/>
- <item car:usage="assistant"
- car:icon="@drawable/car_ic_music"/>
-</carVolumeItems>
-
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
index 12699d52772a..18dc185c6fbe 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityCompat.java
@@ -58,4 +58,8 @@ public class ActivityCompat {
encoder.endStream();
return true;
}
+
+ public int getDisplayId() {
+ return mWrapped.getDisplayId();
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index b55aa5c8897d..904f94486e6c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1904,13 +1904,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
+ slotId + ", state=" + state +")");
}
+ boolean becameAbsent = false;
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
Log.w(TAG, "invalid subId in handleSimStateChange()");
/* Only handle No SIM(ABSENT) due to handleServiceStateChange() handle other case */
if (state == State.ABSENT) {
updateTelephonyCapable(true);
+ // Even though the subscription is not valid anymore, we need to notify that the
+ // SIM card was removed so we can update the UI.
+ becameAbsent = true;
+ } else {
+ return;
}
- return;
}
SimData data = mSimDatas.get(subId);
@@ -1925,7 +1930,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
data.subId = subId;
data.slotId = slotId;
}
- if (changed && state != State.UNKNOWN) {
+ if ((changed || becameAbsent) && state != State.UNKNOWN) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 053ea67b92c8..04c427f87125 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -88,6 +88,9 @@ public class BatteryMeterView extends LinearLayout implements
private int mShowPercentMode = MODE_DEFAULT;
private boolean mForceShowPercent;
private boolean mShowPercentAvailable;
+ // Some places may need to show the battery conditionally, and not obey the tuner
+ private boolean mIgnoreTunerUpdates;
+ private boolean mIsSubscribedForTunerUpdates;
private int mDarkModeBackgroundColor;
private int mDarkModeFillColor;
@@ -183,6 +186,44 @@ public class BatteryMeterView extends LinearLayout implements
}
/**
+ * Set {@code true} to turn off BatteryMeterView's subscribing to the tuner for updates, and
+ * thus avoid it controlling its own visibility
+ *
+ * @param ignore whether to ignore the tuner or not
+ */
+ public void setIgnoreTunerUpdates(boolean ignore) {
+ mIgnoreTunerUpdates = ignore;
+ updateTunerSubscription();
+ }
+
+ private void updateTunerSubscription() {
+ if (mIgnoreTunerUpdates) {
+ unsubscribeFromTunerUpdates();
+ } else {
+ subscribeForTunerUpdates();
+ }
+ }
+
+ private void subscribeForTunerUpdates() {
+ if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) {
+ return;
+ }
+
+ Dependency.get(TunerService.class)
+ .addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ mIsSubscribedForTunerUpdates = true;
+ }
+
+ private void unsubscribeFromTunerUpdates() {
+ if (!mIsSubscribedForTunerUpdates) {
+ return;
+ }
+
+ Dependency.get(TunerService.class).removeTunable(this);
+ mIsSubscribedForTunerUpdates = false;
+ }
+
+ /**
* Sets whether the battery meter view uses the wallpaperTextColor. If we're not using it, we'll
* revert back to dark-mode-based/tinted colors.
*
@@ -247,8 +288,7 @@ public class BatteryMeterView extends LinearLayout implements
getContext().getContentResolver().registerContentObserver(
Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
updateShowPercent();
- Dependency.get(TunerService.class)
- .addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ subscribeForTunerUpdates();
Dependency.get(ConfigurationController.class).addCallback(this);
mUserTracker.startTracking();
}
@@ -259,7 +299,7 @@ public class BatteryMeterView extends LinearLayout implements
mUserTracker.stopTracking();
mBatteryController.removeCallback(this);
getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
- Dependency.get(TunerService.class).removeTunable(this);
+ unsubscribeFromTunerUpdates();
Dependency.get(ConfigurationController.class).removeCallback(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 417d5168641d..867c9175d308 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -62,6 +62,7 @@ import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
+import com.android.systemui.volume.VolumeDialogComponent;
import java.util.function.Consumer;
@@ -132,6 +133,10 @@ public class SystemUIFactory {
return new QSTileHost(context, statusBar, iconController);
}
+ public VolumeDialogComponent createVolumeDialogComponent(SystemUI systemUi, Context context) {
+ return new VolumeDialogComponent(systemUi, context);
+ }
+
public void injectDependencies(ArrayMap<Object, DependencyProvider> providers,
Context context) {
providers.put(StatusBarStateController.class, StatusBarStateController::new);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index a90a7d231dc1..ba89fe662a65 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -140,7 +140,7 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba
createDialogs();
if (!mDialogs.isEmpty()) {
- getComponent(CommandQueue.class).addCallbacks(this);
+ getComponent(CommandQueue.class).addCallback(this);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 416cc594051b..5c259d5c4093 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -342,13 +342,16 @@ public class BubbleController {
}
}
}
+ boolean isCall = Notification.CATEGORY_CALL.equals(n.getNotification().category)
+ && n.isOngoing();
+ boolean isMusic = n.getNotification().hasMediaSession();
+ boolean isImportantOngoing = isMusic || isCall;
Class<? extends Notification.Style> style = n.getNotification().getNotificationStyle();
- boolean isMessageType = Notification.MessagingStyle.class.equals(style)
- || Notification.CATEGORY_MESSAGE.equals(n.getNotification().category)
- || hasRemoteInput;
- return (isMessageType && autoBubbleMessages)
- || (n.isOngoing() && autoBubbleOngoing)
+ boolean isMessageType = Notification.CATEGORY_MESSAGE.equals(n.getNotification().category);
+ boolean isMessageStyle = Notification.MessagingStyle.class.equals(style);
+ return (((isMessageType && hasRemoteInput) || isMessageStyle) && autoBubbleMessages)
+ || (isImportantOngoing && autoBubbleOngoing)
|| autoBubbleAll;
}
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
deleted file mode 100644
index 09c000b469a7..000000000000
--- a/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2016 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.car;
-
-import android.content.Context;
-import android.util.ArrayMap;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.Dependency.DependencyProvider;
-import com.android.systemui.SystemUIFactory;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.car.CarFacetButtonController;
-import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
-import com.android.systemui.statusbar.car.hvac.HvacController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
-
-/**
- * Class factory to provide car specific SystemUI components.
- */
-public class CarSystemUIFactory extends SystemUIFactory {
-
- public StatusBarKeyguardViewManager createStatusBarKeyguardViewManager(Context context,
- ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) {
- return new CarStatusBarKeyguardViewManager(context, viewMediatorCallback, lockPatternUtils);
- }
-
- @Override
- public void injectDependencies(ArrayMap<Object, DependencyProvider> providers,
- Context context) {
- super.injectDependencies(providers, context);
- providers.put(NotificationEntryManager.class,
- () -> new CarNotificationEntryManager(context));
- providers.put(CarFacetButtonController.class, () -> new CarFacetButtonController(context));
- providers.put(HvacController.class, () -> new HvacController(context));
- providers.put(NotificationMediaManager.class,
- () -> new CarNotificationMediaManager(context));
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 2c61da343763..1718cff4e62b 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -108,7 +108,7 @@ public class FalsingManager implements SensorEventListener {
UserHandle.USER_ALL);
updateConfiguration();
- Dependency.get(StatusBarStateController.class).addListener(mStateListener);
+ Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
}
public static FalsingManager getInstance(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
index aa085626b6c2..e8ef454bd466 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
@@ -45,7 +45,7 @@ public class GlobalActionsComponent extends SystemUI implements Callbacks, Globa
.withCallback(this::onExtensionCallback)
.build();
mPlugin = mExtension.get();
- SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
+ SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
}
private void onExtensionCallback(GlobalActions newPlugin) {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 039499858603..dc11b4c63d83 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -55,12 +55,12 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks
mContext = context;
mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
- SysUiServiceProvider.getComponent(context, CommandQueue.class).addCallbacks(this);
+ SysUiServiceProvider.getComponent(context, CommandQueue.class).addCallback(this);
}
@Override
public void destroy() {
- SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallbacks(this);
+ SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallback(this);
if (mGlobalActions != null) {
mGlobalActions.destroy();
mGlobalActions = null;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 3b9110d31c6f..9ccdf79c37ca 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -488,6 +488,9 @@ public class KeyguardViewMediator extends SystemUI {
// MVNO SIMs can become transiently NOT_READY when switching networks,
// so we should only lock when they are ABSENT.
onSimAbsentLocked();
+ if (simWasLocked) {
+ resetStateLocked();
+ }
}
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
index 7792e177b601..37c8163702cf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
@@ -58,7 +58,7 @@ public class PipUI extends SystemUI implements CommandQueue.Callbacks {
: com.android.systemui.pip.phone.PipManager.getInstance();
mPipManager.initialize(mContext);
- getComponent(CommandQueue.class).addCallbacks(this);
+ getComponent(CommandQueue.class).addCallback(this);
putComponent(PipUI.class, this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 953eb70cac5d..2acbea45a235 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -108,12 +108,12 @@ public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks {
mQSPanel.getTileLayout().restoreInstanceState(savedInstanceState);
}
}
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
+ SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallback(this);
}
@Override
public void onDestroyView() {
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
+ SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallback(this);
super.onDestroyView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index e2e943a369c2..d7d3981d05d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -79,7 +79,7 @@ public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClic
mFooterIcon = (ImageView) mRootView.findViewById(R.id.footer_icon);
mFooterIconId = R.drawable.ic_info_outline;
mContext = context;
- mMainHandler = new Handler(Looper.getMainLooper());
+ mMainHandler = new Handler(Looper.myLooper());
mActivityStarter = Dependency.get(ActivityStarter.class);
mSecurityController = Dependency.get(SecurityController.class);
mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index d1c2df53b5a5..ca8e824a223f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -308,7 +308,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> {
protected static List<String> loadTileSpecs(Context context, String tileList) {
final Resources res = context.getResources();
final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);
- if (tileList == null) {
+ if (TextUtils.isEmpty(tileList)) {
tileList = res.getString(R.string.quick_settings_tiles);
if (DEBUG) Log.d(TAG, "Loaded tile specs from config: " + tileList);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 427f638b0d30..3cecff033c91 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -232,6 +232,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
// Tint for the battery icons are handled in setupHost()
mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_OFF);
+ // Don't need to worry about tuner settings for this icon
+ mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
mBatteryRemainingText = findViewById(R.id.batteryRemainingText);
mBatteryRemainingText.setTextColor(fillColor);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 0702d74506fd..f13b565bd532 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -37,7 +37,7 @@ public class Recents extends SystemUI implements CommandQueue.Callbacks {
@Override
public void start() {
- getComponent(CommandQueue.class).addCallbacks(this);
+ getComponent(CommandQueue.class).addCallback(this);
putComponent(Recents.class, this);
mImpl = createRecentsImplementationFromConfig();
mImpl.onStart(mContext, this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 8b9399536969..95019ee2aeea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -35,6 +35,8 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
+import com.android.systemui.statusbar.policy.CallbackController;
import java.util.ArrayList;
@@ -45,7 +47,7 @@ import java.util.ArrayList;
* coalescing these calls so they don't stack up. For the calls
* are coalesced, note that they are all idempotent.
*/
-public class CommandQueue extends IStatusBar.Stub {
+public class CommandQueue extends IStatusBar.Stub implements CallbackController<Callbacks> {
private static final int INDEX_MASK = 0xffff;
private static final int MSG_SHIFT = 16;
private static final int MSG_MASK = 0xffff << MSG_SHIFT;
@@ -183,12 +185,12 @@ public class CommandQueue extends IStatusBar.Stub {
&& !ONLY_CORE_APPS;
}
- public void addCallbacks(Callbacks callbacks) {
+ public void addCallback(Callbacks callbacks) {
mCallbacks.add(callbacks);
callbacks.disable(mDisable1, mDisable2, false /* animate */);
}
- public void removeCallbacks(Callbacks callbacks) {
+ public void removeCallback(Callbacks callbacks) {
mCallbacks.remove(callbacks);
}
@@ -223,7 +225,9 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void disable(int state1, int state2) {
+ // TODO(b/117478341): Add multi-display support.
+ @Override
+ public void disable(int displayId, int state1, int state2) {
disable(state1, state2, true);
}
@@ -266,8 +270,10 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
- int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ // TODO(b/117478341): Add multi-display support.
+ @Override
+ public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
synchronized (mLock) {
// Don't coalesce these, since it might have one time flags set such as
// STATUS_BAR_UNHIDE which might get lost.
@@ -282,7 +288,9 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void topAppWindowChanged(boolean menuVisible) {
+ // TODO(b/117478341): Add multi-display support.
+ @Override
+ public void topAppWindowChanged(int displayId, boolean menuVisible) {
synchronized (mLock) {
mHandler.removeMessages(MSG_TOP_APP_WINDOW_CHANGED);
mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, menuVisible ? 1 : 0, 0,
@@ -290,7 +298,9 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ // TODO(b/117478341): Add multi-display support.
+ @Override
+ public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
boolean showImeSwitcher) {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
@@ -371,7 +381,9 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void setWindowState(int window, int state) {
+ // TODO(b/117478341): Add multi-display support.
+ @Override
+ public void setWindowState(int displayId, int window, int state) {
synchronized (mLock) {
// don't coalesce these
mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget();
@@ -385,7 +397,9 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void appTransitionPending() {
+ // TODO(b/117478341): Add multi-display support.
+ @Override
+ public void appTransitionPending(int displayId) {
appTransitionPending(false /* forced */);
}
@@ -395,13 +409,17 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
- public void appTransitionCancelled() {
+ // TODO(b/117478341): Add multi-display support.
+ @Override
+ public void appTransitionCancelled(int displayId) {
synchronized (mLock) {
mHandler.sendEmptyMessage(MSG_APP_TRANSITION_CANCELLED);
}
}
- public void appTransitionStarting(long startTime, long duration) {
+ // TODO(b/117478341): Add multi-display support.
+ @Override
+ public void appTransitionStarting(int displayId, long startTime, long duration) {
appTransitionStarting(startTime, duration, false /* forced */);
}
@@ -412,8 +430,9 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
+ // TODO(b/117478341): Add multi-display support.
@Override
- public void appTransitionFinished() {
+ public void appTransitionFinished(int displayId) {
synchronized (mLock) {
mHandler.sendEmptyMessage(MSG_APP_TRANSITION_FINISHED);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 960d22185652..7d1b640f7e40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -156,7 +156,7 @@ public class KeyguardIndicationController implements StateListener {
new IntentFilter(Intent.ACTION_TIME_TICK), null,
Dependency.get(Dependency.TIME_TICK_HANDLER));
- Dependency.get(StatusBarStateController.class).addListener(this);
+ Dependency.get(StatusBarStateController.class).addCallback(this);
}
/**
@@ -167,7 +167,7 @@ public class KeyguardIndicationController implements StateListener {
*/
public void destroy() {
mContext.unregisterReceiver(mTickReceiver);
- Dependency.get(StatusBarStateController.class).removeListener(this);
+ Dependency.get(StatusBarStateController.class).removeCallback(this);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index b0724b1e014b..bba4369b5e01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -165,7 +165,7 @@ public class NotificationLockscreenUserManagerImpl implements
mCurrentUserId = ActivityManager.getCurrentUser();
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- Dependency.get(StatusBarStateController.class).addListener(this);
+ Dependency.get(StatusBarStateController.class).addCallback(this);
mLockPatternUtils = new LockPatternUtils(context);
mKeyguardManager = context.getSystemService(KeyguardManager.class);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 7be5461f0afa..ecadf96dfbfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -141,7 +141,7 @@ public class NotificationRemoteInputManager implements Dumpable {
ActivityManager.getService().resumeAppSwitches();
} catch (RemoteException e) {
}
- return mCallback.handleRemoteViewClick(pendingIntent, () -> {
+ return mCallback.handleRemoteViewClick(view, pendingIntent, () -> {
Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view);
options.second.setLaunchWindowingMode(
WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
@@ -666,11 +666,13 @@ public class NotificationRemoteInputManager implements Dumpable {
* Performs any special handling for a remote view click. The default behaviour can be
* called through the defaultHandler parameter.
*
+ * @param view
* @param pendingIntent
* @param defaultHandler
* @return true iff the click was handled
*/
- boolean handleRemoteViewClick(PendingIntent pendingIntent, ClickHandler defaultHandler);
+ boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
+ ClickHandler defaultHandler);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index ac4abfc7fba5..6cec36a81e5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -121,13 +121,13 @@ public class NotificationShelf extends ActivatableNotificationView implements
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Dependency.get(StatusBarStateController.class)
- .addListener(mStateListener, StatusBarStateController.RANK_SHELF);
+ .addCallback(mStateListener, StatusBarStateController.RANK_SHELF);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- Dependency.get(StatusBarStateController.class).removeListener(mStateListener);
+ Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
}
public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index daa2fd45b142..dc3a60786ce2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -129,7 +129,7 @@ public class NotificationViewHierarchyManager {
res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications);
mStatusBarStateListener = new StatusBarStateListener(mBubbleController);
mEntryManager.setStatusBarStateListener(mStatusBarStateListener);
- Dependency.get(StatusBarStateController.class).addListener(mStatusBarStateListener);
+ Dependency.get(StatusBarStateController.class).addCallback(mStatusBarStateListener);
}
public void setUpWithPresenter(NotificationPresenter presenter,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
index eaf52cb357fe..3f84416ad575 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
@@ -26,8 +26,10 @@ import android.view.animation.Interpolator;
import com.android.internal.annotations.GuardedBy;
import com.android.systemui.Interpolators;
+import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.CallbackController;
import java.lang.annotation.Retention;
import java.util.ArrayList;
@@ -36,7 +38,7 @@ import java.util.Comparator;
/**
* Tracks and reports on {@link StatusBarState}.
*/
-public class StatusBarStateController {
+public class StatusBarStateController implements CallbackController<StateListener> {
private static final String TAG = "SbStateController";
private static final int MAX_STATE = StatusBarState.FULLSCREEN_USER_SWITCHER;
@@ -228,7 +230,7 @@ public class StatusBarStateController {
return mLastState == StatusBarState.SHADE_LOCKED;
}
- public void addListener(StateListener listener) {
+ public void addCallback(StateListener listener) {
synchronized (mListeners) {
addListenerInternalLocked(listener, Integer.MAX_VALUE);
}
@@ -244,7 +246,7 @@ public class StatusBarStateController {
* StatusBarState out of StatusBar.java. Any new listeners should be built not to need ranking
* (i.e., they are non-dependent on the order of operations of StatusBarState listeners).
*/
- public void addListener(StateListener listener, @SbStateListenerRank int rank) {
+ public void addCallback(StateListener listener, @SbStateListenerRank int rank) {
synchronized (mListeners) {
addListenerInternalLocked(listener, rank);
}
@@ -264,7 +266,7 @@ public class StatusBarStateController {
mListeners.sort(mComparator);
}
- public void removeListener(StateListener listener) {
+ public void removeCallback(StateListener listener) {
synchronized (mListeners) {
mListeners.removeIf((it) -> it.listener.equals(listener));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
deleted file mode 100644
index bd328567fb46..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.android.systemui.statusbar.car;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.TypedArray;
-import android.os.UserHandle;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import com.android.keyguard.AlphaOptimizedImageButton;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-
-/**
- * CarFacetButton is a ui component designed to be used as a shortcut for an app of a defined
- * category. It can also render a indicator impling that there are more options of apps to launch
- * using this component. This is done with a "More icon" currently an arrow as defined in the layout
- * file. The class is to serve as an example.
- * Usage example: A button that allows a user to select a music app and indicate that there are
- * other music apps installed.
- */
-public class CarFacetButton extends LinearLayout {
- private static final String FACET_FILTER_DELIMITER = ";";
- /**
- * Extra information to be sent to a helper to make the decision of what app to launch when
- * clicked.
- */
- private static final String EXTRA_FACET_CATEGORIES = "categories";
- private static final String EXTRA_FACET_PACKAGES = "packages";
- private static final String EXTRA_FACET_ID = "filter_id";
- private static final String EXTRA_FACET_LAUNCH_PICKER = "launch_picker";
-
- private Context mContext;
- private AlphaOptimizedImageButton mIcon;
- private AlphaOptimizedImageButton mMoreIcon;
- private boolean mSelected = false;
- private String[] mComponentNames;
- /** App categories that are to be used with this widget */
- private String[] mFacetCategories;
- /** App packages that are allowed to be used with this widget */
- private String[] mFacetPackages;
- private int mIconResourceId;
- /**
- * If defined in the xml this will be the icon that's rendered when the button is marked as
- * selected
- */
- private int mSelectedIconResourceId;
- private boolean mUseMoreIcon = true;
- private float mSelectedAlpha = 1f;
- private float mUnselectedAlpha = 1f;
-
-
- public CarFacetButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- View.inflate(context, R.layout.car_facet_button, this);
-
- // extract custom attributes
- TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarFacetButton);
- setupIntents(typedArray);
- setupIcons(typedArray);
- CarFacetButtonController carFacetButtonController = Dependency.get(
- CarFacetButtonController.class);
- carFacetButtonController.addFacetButton(this);
-
- }
-
- /**
- * Reads the custom attributes to setup click handlers for this component.
- */
- private void setupIntents(TypedArray typedArray) {
- String intentString = typedArray.getString(R.styleable.CarFacetButton_intent);
- String longPressIntentString = typedArray.getString(R.styleable.CarFacetButton_longIntent);
- String categoryString = typedArray.getString(R.styleable.CarFacetButton_categories);
- String packageString = typedArray.getString(R.styleable.CarFacetButton_packages);
- String componentNameString =
- typedArray.getString(R.styleable.CarFacetButton_componentNames);
- try {
- final Intent intent = Intent.parseUri(intentString, Intent.URI_INTENT_SCHEME);
- intent.putExtra(EXTRA_FACET_ID, Integer.toString(getId()));
-
- if (packageString != null) {
- mFacetPackages = packageString.split(FACET_FILTER_DELIMITER);
- intent.putExtra(EXTRA_FACET_PACKAGES, mFacetPackages);
- }
- if (categoryString != null) {
- mFacetCategories = categoryString.split(FACET_FILTER_DELIMITER);
- intent.putExtra(EXTRA_FACET_CATEGORIES, mFacetCategories);
- }
- if (componentNameString != null) {
- mComponentNames = componentNameString.split(FACET_FILTER_DELIMITER);
- }
-
- setOnClickListener(v -> {
- intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, mSelected);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
- });
-
- if (longPressIntentString != null) {
- final Intent longPressIntent = Intent.parseUri(longPressIntentString,
- Intent.URI_INTENT_SCHEME);
- setOnLongClickListener(v -> {
- mContext.startActivityAsUser(longPressIntent, UserHandle.CURRENT);
- return true;
- });
- }
- } catch (Exception e) {
- throw new RuntimeException("Failed to attach intent", e);
- }
- }
-
-
- private void setupIcons(TypedArray styledAttributes) {
- mSelectedAlpha = styledAttributes.getFloat(
- R.styleable.CarFacetButton_selectedAlpha, mSelectedAlpha);
- mUnselectedAlpha = styledAttributes.getFloat(
- R.styleable.CarFacetButton_unselectedAlpha, mUnselectedAlpha);
- mIcon = findViewById(R.id.car_nav_button_icon);
- mIcon.setScaleType(ImageView.ScaleType.CENTER);
- mIcon.setClickable(false);
- mIcon.setAlpha(mUnselectedAlpha);
- mIconResourceId = styledAttributes.getResourceId(R.styleable.CarFacetButton_icon, 0);
- mIcon.setImageResource(mIconResourceId);
- mSelectedIconResourceId = styledAttributes.getResourceId(
- R.styleable.CarFacetButton_selectedIcon, mIconResourceId);
-
- mMoreIcon = findViewById(R.id.car_nav_button_more_icon);
- mMoreIcon.setClickable(false);
- mMoreIcon.setAlpha(mSelectedAlpha);
- mMoreIcon.setVisibility(GONE);
- mUseMoreIcon = styledAttributes.getBoolean(R.styleable.CarFacetButton_useMoreIcon, true);
- }
-
- /**
- * @return The app categories the component represents
- */
- public String[] getCategories() {
- if (mFacetCategories == null) {
- return new String[0];
- }
- return mFacetCategories;
- }
-
- /**
- * @return The valid packages that should be considered.
- */
- public String[] getFacetPackages() {
- if (mFacetPackages == null) {
- return new String[0];
- }
- return mFacetPackages;
- }
-
- public String[] getComponentName() {
- if (mComponentNames == null) {
- return new String[0];
- }
- return mComponentNames;
- }
-
- /**
- * Updates the alpha of the icons to "selected" and shows the "More icon"
- * @param selected true if the view must be selected, false otherwise
- */
- public void setSelected(boolean selected) {
- super.setSelected(selected);
- setSelected(selected, selected);
- }
-
- /**
- * Updates the visual state to let the user know if it's been selected.
- * @param selected true if should update the alpha of the icon to selected, false otherwise
- * @param showMoreIcon true if the "more icon" should be shown, false otherwise. Note this
- * is ignored if the attribute useMoreIcon is set to false
- */
- public void setSelected(boolean selected, boolean showMoreIcon) {
- mSelected = selected;
- mIcon.setAlpha(mSelected ? mSelectedAlpha : mUnselectedAlpha);
- mIcon.setImageResource(mSelected ? mSelectedIconResourceId : mIconResourceId);
- if (mUseMoreIcon) {
- mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index f506753379a4..f899863dcc6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -299,6 +299,10 @@ public class ActivityLaunchAnimator {
return top;
}
+ public int getBottom() {
+ return bottom;
+ }
+
public int getWidth() {
return right - left;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 1f48c15e63c0..09eb8a1030ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -75,6 +75,6 @@ public class NotificationUtils {
/** Returns the value of the new interruption model setting. */
public static boolean useNewInterruptionModel(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
- NOTIFICATION_NEW_INTERRUPTION_MODEL, 0) != 0;
+ NOTIFICATION_NEW_INTERRUPTION_MODEL, 1) != 0;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 87313b8a0393..9f02e543b6e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -149,7 +149,7 @@ public class NotificationLogger implements StateListener {
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
// Not expected to be destroyed, don't need to unsubscribe
- Dependency.get(StatusBarStateController.class).addListener(this);
+ Dependency.get(StatusBarStateController.class).addCallback(this);
}
public void setUpWithContainer(NotificationListContainer listContainer) {
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 63fe04aff08b..8214ea6c7616 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
@@ -328,6 +328,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private float mTranslationWhenRemoved;
private boolean mWasChildInGroupWhenRemoved;
private int mNotificationColorAmbient;
+ private NotificationInlineImageResolver mImageResolver;
private SystemNotificationAsyncTask mSystemNotificationAsyncTask =
new SystemNotificationAsyncTask();
@@ -1621,6 +1622,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mFalsingManager = FalsingManager.getInstance(context);
mNotificationInflater = new NotificationInflater(this);
mMenuRow = new NotificationMenuRow(mContext);
+ mImageResolver = new NotificationInlineImageResolver(context,
+ new NotificationInlineImageCache());
initDimens();
}
@@ -1657,6 +1660,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
res.getBoolean(R.bool.config_showGroupNotificationBgWhenExpanded);
}
+ NotificationInlineImageResolver getImageResolver() {
+ return mImageResolver;
+ }
+
/**
* Resets this view so it can be re-used for an updated notification.
*/
@@ -2008,7 +2015,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
float interpolation = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(params.getProgress());
int startClipTopAmount = params.getStartClipTopAmount();
if (mNotificationParent != null) {
- top -= mNotificationParent.getTranslationY();
+ float parentY = mNotificationParent.getTranslationY();
+ top -= parentY;
mNotificationParent.setTranslationZ(translationZ);
int parentStartClipTopAmount = params.getParentStartClipTopAmount();
if (startClipTopAmount != 0) {
@@ -2018,8 +2026,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mNotificationParent.setClipTopAmount(clipTopAmount);
}
mNotificationParent.setExtraWidthForClipping(extraWidthForClipping);
- mNotificationParent.setMinimumHeightForClipping(params.getHeight()
- + mNotificationParent.getActualHeight());
+ float clipBottom = Math.max(params.getBottom(),
+ parentY + mNotificationParent.getActualHeight()
+ - mNotificationParent.getClipBottomAmount());
+ float clipTop = Math.min(params.getTop(), parentY);
+ int minimumHeightForClipping = (int) (clipBottom - clipTop);
+ mNotificationParent.setMinimumHeightForClipping(minimumHeightForClipping);
} else if (startClipTopAmount != 0) {
int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, interpolation);
setClipTopAmount(clipTopAmount);
@@ -2085,7 +2097,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
@Override
protected boolean shouldClipToActualHeight() {
- return super.shouldClipToActualHeight() && !mExpandAnimationRunning && !mChildIsExpanding;
+ return super.shouldClipToActualHeight() && !mExpandAnimationRunning;
}
@Override
@@ -3129,6 +3141,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
pw.print(", alpha: " + getAlpha());
pw.print(", translation: " + getTranslation());
pw.print(", removed: " + isRemoved());
+ pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
NotificationContentView showingLayout = getShowingLayout();
pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
pw.println();
@@ -3142,6 +3155,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
pw.println();
pw.println();
if (mIsSummaryWithChildren) {
+ pw.print(" ChildrenContainer");
+ pw.print(" visibility: " + mChildrenContainer.getVisibility());
+ pw.print(", alpha: " + mChildrenContainer.getAlpha());
+ pw.print(", translationY: " + mChildrenContainer.getTranslationY());
+ pw.println();
List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
pw.println(" Children: " + notificationChildren.size());
pw.println(" {");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
index 0efb1308e83e..6aadcb7b30e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
@@ -77,8 +77,6 @@ public abstract class ExpandableOutlineView extends ExpandableView {
protected boolean mShouldTranslateContents;
private boolean mTopAmountRounded;
private float mDistanceToTopRoundness = -1;
- private float mExtraWidthForClipping;
- private int mMinimumHeightForClipping = 0;
private final ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@Override
@@ -219,13 +217,15 @@ public abstract class ExpandableOutlineView extends ExpandableView {
return result;
}
+ @Override
public void setExtraWidthForClipping(float extraWidthForClipping) {
- mExtraWidthForClipping = extraWidthForClipping;
+ super.setExtraWidthForClipping(extraWidthForClipping);
invalidate();
}
+ @Override
public void setMinimumHeightForClipping(int minimumHeightForClipping) {
- mMinimumHeightForClipping = minimumHeightForClipping;
+ super.setMinimumHeightForClipping(minimumHeightForClipping);
invalidate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 1e8de076cbed..20c48163e6b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -48,6 +48,8 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
private int mActualHeight;
protected int mClipTopAmount;
protected int mClipBottomAmount;
+ protected int mMinimumHeightForClipping = 0;
+ protected float mExtraWidthForClipping = 0;
private boolean mDark;
private ArrayList<View> mMatchParentViews = new ArrayList<View>();
private static Rect mClipRect = new Rect();
@@ -398,14 +400,26 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
protected void updateClipping() {
if (mClipToActualHeight && shouldClipToActualHeight()) {
int top = getClipTopAmount();
- mClipRect.set(0, top, getWidth(), Math.max(getActualHeight() + getExtraBottomPadding()
- - mClipBottomAmount, top));
+ int bottom = Math.max(Math.max(getActualHeight() + getExtraBottomPadding()
+ - mClipBottomAmount, top), mMinimumHeightForClipping);
+ int halfExtraWidth = (int) (mExtraWidthForClipping / 2.0f);
+ mClipRect.set(-halfExtraWidth, top, getWidth() + halfExtraWidth, bottom);
setClipBounds(mClipRect);
} else {
setClipBounds(null);
}
}
+ public void setMinimumHeightForClipping(int minimumHeightForClipping) {
+ mMinimumHeightForClipping = minimumHeightForClipping;
+ updateClipping();
+ }
+
+ public void setExtraWidthForClipping(float extraWidthForClipping) {
+ mExtraWidthForClipping = extraWidthForClipping;
+ updateClipping();
+ }
+
public float getHeaderVisibleAmount() {
return 1.0f;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
index 7086025836cb..9908049984d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInflater.java
@@ -33,6 +33,7 @@ import android.view.View;
import android.widget.RemoteViews;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.ImageMessageConsumer;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
@@ -114,7 +115,7 @@ public class NotificationInflater {
@InflationFlag
private int mInflationFlags = REQUIRED_INFLATION_FLAGS;
- private static final InflationExecutor EXECUTOR = new InflationExecutor();
+ static final InflationExecutor EXECUTOR = new InflationExecutor();
private final ExpandableNotificationRow mRow;
private boolean mIsLowPriority;
@@ -244,6 +245,10 @@ public class NotificationInflater {
// Only inflate the ones that are set.
reInflateFlags &= mInflationFlags;
StatusBarNotification sbn = mRow.getEntry().notification;
+
+ // To check if the notification has inline image and preload inline image if necessary.
+ mRow.getImageResolver().preloadImages(sbn.getNotification());
+
AsyncInflationTask task = new AsyncInflationTask(sbn, reInflateFlags, mCachedContentViews,
mRow, mIsLowPriority, mIsChildInGroup, mUsesIncreasedHeight,
mUsesIncreasedHeadsUpHeight, mRedactAmbient, mCallback, mRemoteViewClickHandler);
@@ -520,8 +525,14 @@ public class NotificationInflater {
}
return;
}
- RemoteViews.OnViewAppliedListener listener
- = new RemoteViews.OnViewAppliedListener() {
+ RemoteViews.OnViewAppliedListener listener = new RemoteViews.OnViewAppliedListener() {
+
+ @Override
+ public void onViewInflated(View v) {
+ if (v instanceof ImageMessageConsumer) {
+ ((ImageMessageConsumer) v).setImageResolver(row.getImageResolver());
+ }
+ }
@Override
public void onViewApplied(View v) {
@@ -697,7 +708,7 @@ public class NotificationInflater {
&& newView.getPackage() != null
&& newView.getPackage().equals(oldView.getPackage())
&& newView.getLayoutId() == oldView.getLayoutId()
- && !oldView.isReapplyDisallowed());
+ && !oldView.hasFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED));
}
public void setInflationCallback(InflationCallback callback) {
@@ -851,6 +862,10 @@ public class NotificationInflater {
mRow.getEntry().onInflationTaskFinished();
mRow.onNotificationUpdated();
mCallback.onAsyncInflationFinished(mRow.getEntry(), inflatedFlags);
+
+ // Notify the resolver that the inflation task has finished,
+ // try to purge unnecessary cached entries.
+ mRow.getImageResolver().purgeCache();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
new file mode 100644
index 000000000000..8c8bad2ab196
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageCache.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 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.row;
+
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * A cache for inline images of image messages.
+ */
+public class NotificationInlineImageCache implements NotificationInlineImageResolver.ImageCache {
+ private static final String TAG = NotificationInlineImageCache.class.getSimpleName();
+
+ private NotificationInlineImageResolver mResolver;
+ private final ConcurrentHashMap<Uri, PreloadImageTask> mCache;
+
+ public NotificationInlineImageCache() {
+ mCache = new ConcurrentHashMap<>();
+ }
+
+ @Override
+ public void setImageResolver(NotificationInlineImageResolver resolver) {
+ mResolver = resolver;
+ }
+
+ @Override
+ public boolean hasEntry(Uri uri) {
+ return mCache.containsKey(uri);
+ }
+
+ @Override
+ public void preload(Uri uri) {
+ PreloadImageTask newTask = new PreloadImageTask(mResolver);
+ newTask.executeOnExecutor(NotificationInflater.EXECUTOR, uri);
+ mCache.put(uri, newTask);
+ }
+
+ @Override
+ public Drawable get(Uri uri) {
+ Drawable result = null;
+ try {
+ result = mCache.get(uri).get();
+ } catch (InterruptedException | ExecutionException ex) {
+ Log.d(TAG, "get: Failed get image from " + uri);
+ }
+ return result;
+ }
+
+ @Override
+ public void purge() {
+ Set<Uri> wantedSet = mResolver.getWantedUriSet();
+ mCache.entrySet().removeIf(entry -> !wantedSet.contains(entry.getKey()));
+ }
+
+ private static class PreloadImageTask extends AsyncTask<Uri, Void, Drawable> {
+ private final NotificationInlineImageResolver mResolver;
+
+ PreloadImageTask(NotificationInlineImageResolver resolver) {
+ mResolver = resolver;
+ }
+
+ @Override
+ protected Drawable doInBackground(Uri... uris) {
+ Drawable drawable = null;
+ Uri target = uris[0];
+
+ try {
+ drawable = mResolver.resolveImage(target);
+ } catch (IOException ex) {
+ Log.d(TAG, "PreloadImageTask: Resolve failed from " + target);
+ }
+
+ return drawable;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
new file mode 100644
index 000000000000..588246f3d2c6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2018 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.row;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.Log;
+
+import com.android.internal.widget.ImageResolver;
+import com.android.internal.widget.LocalImageResolver;
+import com.android.internal.widget.MessagingMessage;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Custom resolver with built-in image cache for image messages.
+ */
+public class NotificationInlineImageResolver implements ImageResolver {
+ private static final String TAG = NotificationInlineImageResolver.class.getSimpleName();
+
+ private final Context mContext;
+ private final ImageCache mImageCache;
+ private Set<Uri> mWantedUriSet;
+
+ /**
+ * Constructor.
+ * @param context Context.
+ * @param imageCache The implementation of internal cache.
+ */
+ public NotificationInlineImageResolver(Context context, ImageCache imageCache) {
+ mContext = context.getApplicationContext();
+ mImageCache = imageCache;
+
+ if (mImageCache != null) {
+ mImageCache.setImageResolver(this);
+ }
+ }
+
+ /**
+ * Check if this resolver has its internal cache implementation.
+ * @return True if has its internal cache, false otherwise.
+ */
+ public boolean hasCache() {
+ return mImageCache != null && !ActivityManager.isLowRamDeviceStatic();
+ }
+
+ /**
+ * To resolve image from specified uri directly.
+ * @param uri Uri of the image.
+ * @return Drawable of the image.
+ * @throws IOException Throws if failed at resolving the image.
+ */
+ Drawable resolveImage(Uri uri) throws IOException {
+ return LocalImageResolver.resolveImage(uri, mContext);
+ }
+
+ @Override
+ public Drawable loadImage(Uri uri) {
+ Drawable result = null;
+ try {
+ result = hasCache() ? mImageCache.get(uri) : resolveImage(uri);
+ } catch (IOException ex) {
+ Log.d(TAG, "loadImage: Can't load image from " + uri);
+ }
+ return result;
+ }
+
+ /**
+ * Resolve the message list from specified notification and
+ * refresh internal cache according to the result.
+ * @param notification The Notification to be resolved.
+ */
+ public void preloadImages(Notification notification) {
+ if (!hasCache()) {
+ return;
+ }
+
+ retrieveWantedUriSet(notification);
+ Set<Uri> wantedSet = getWantedUriSet();
+ wantedSet.forEach(uri -> {
+ if (!mImageCache.hasEntry(uri)) {
+ // The uri is not in the cache, we need trigger a loading task for it.
+ mImageCache.preload(uri);
+ }
+ });
+ }
+
+ /**
+ * Try to purge unnecessary cache entries.
+ */
+ public void purgeCache() {
+ if (!hasCache()) {
+ return;
+ }
+ mImageCache.purge();
+ }
+
+ private void retrieveWantedUriSet(Notification notification) {
+ Parcelable[] messages;
+ Parcelable[] historicMessages;
+ List<Notification.MessagingStyle.Message> messageList;
+ List<Notification.MessagingStyle.Message> historicList;
+ Set<Uri> result = new HashSet<>();
+
+ Bundle extras = notification.extras;
+ if (extras == null) {
+ return;
+ }
+
+ messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+ messageList = messages == null ? null :
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
+ if (messageList != null) {
+ for (Notification.MessagingStyle.Message message : messageList) {
+ if (MessagingMessage.hasImage(message)) {
+ result.add(message.getDataUri());
+ }
+ }
+ }
+
+ historicMessages = extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES);
+ historicList = historicMessages == null ? null :
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(historicMessages);
+ if (historicList != null) {
+ for (Notification.MessagingStyle.Message historic : historicList) {
+ if (MessagingMessage.hasImage(historic)) {
+ result.add(historic.getDataUri());
+ }
+ }
+ }
+
+ mWantedUriSet = result;
+ }
+
+ Set<Uri> getWantedUriSet() {
+ return mWantedUriSet;
+ }
+
+ /**
+ * A interface for internal cache implementation of this resolver.
+ */
+ interface ImageCache {
+ /**
+ * Load the image from cache first then resolve from uri if missed the cache.
+ * @param uri The uri of the image.
+ * @return Drawable of the image.
+ */
+ Drawable get(Uri uri);
+
+ /**
+ * Set the image resolver that actually resolves image from specified uri.
+ * @param resolver The resolver implementation that resolves image from specified uri.
+ */
+ void setImageResolver(NotificationInlineImageResolver resolver);
+
+ /**
+ * Check if the uri is in the cache no matter it is loading or loaded.
+ * @param uri The uri to check.
+ * @return True if it is already in the cache; false otherwise.
+ */
+ boolean hasEntry(Uri uri);
+
+ /**
+ * Start a new loading task for the target uri.
+ * @param uri The target to load.
+ */
+ void preload(Uri uri);
+
+ /**
+ * Purge unnecessary entries in the cache.
+ */
+ void purge();
+ }
+
+}
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 5d640e0216e0..eca1a1411212 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
@@ -618,7 +618,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Dependency.get(StatusBarStateController.class)
- .addListener(mStateListener, StatusBarStateController.RANK_STACK_SCROLLER);
+ .addCallback(mStateListener, StatusBarStateController.RANK_STACK_SCROLLER);
Dependency.get(ConfigurationController.class).addCallback(this);
}
@@ -626,7 +626,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- Dependency.get(StatusBarStateController.class).removeListener(mStateListener);
+ Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
Dependency.get(ConfigurationController.class).removeCallback(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 3b13fe96fe42..24570aec9db4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -120,15 +120,15 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
@Override
public void onResume() {
super.onResume();
- mCommandQueue.addCallbacks(this);
- mStatusBarStateController.addListener(this);
+ mCommandQueue.addCallback(this);
+ mStatusBarStateController.addCallback(this);
}
@Override
public void onPause() {
super.onPause();
- mCommandQueue.removeCallbacks(this);
- mStatusBarStateController.removeListener(this);
+ mCommandQueue.removeCallback(this);
+ mStatusBarStateController.removeCallback(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 94b2cdeea898..cfa751cec613 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -88,7 +88,7 @@ public class DozeScrimController implements StateListener {
public DozeScrimController(DozeParameters dozeParameters) {
mDozeParameters = dozeParameters;
//Never expected to be destroyed
- Dependency.get(StatusBarStateController.class).addListener(this);
+ Dependency.get(StatusBarStateController.class).addCallback(this);
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 9faada05294b..aa0b7b656e1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -129,7 +129,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
updateTouchableRegionListener();
}
});
- Dependency.get(StatusBarStateController.class).addListener(mStateListener);
+ Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
if (!hasBubbles) {
mBubbleGoingAway = true;
@@ -143,7 +143,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
}
public void destroy() {
- Dependency.get(StatusBarStateController.class).removeListener(mStateListener);
+ Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
}
private void initResources() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index b29889dac6f8..57cc7d6c1ecb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -73,15 +73,15 @@ public class LightBarTransitionsController implements Dumpable, Callbacks,
mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
mStatusBarStateController = Dependency.get(StatusBarStateController.class);
SysUiServiceProvider.getComponent(context, CommandQueue.class)
- .addCallbacks(this);
- mStatusBarStateController.addListener(this);
+ .addCallback(this);
+ mStatusBarStateController.addCallback(this);
mDozeAmount = mStatusBarStateController.getDozeAmount();
}
public void destroy(Context context) {
SysUiServiceProvider.getComponent(context, CommandQueue.class)
- .removeCallbacks(this);
- mStatusBarStateController.removeListener(this);
+ .removeCallback(this);
+ mStatusBarStateController.removeCallback(this);
}
public void saveState(Bundle outState) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 8657003891be..d2bfd123f113 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -199,7 +199,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
- mCommandQueue.addCallbacks(this);
+ mCommandQueue.addCallback(this);
mStatusBar = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
mRecents = SysUiServiceProvider.getComponent(getContext(), Recents.class);
mDivider = SysUiServiceProvider.getComponent(getContext(), Divider.class);
@@ -225,7 +225,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
@Override
public void onDestroy() {
super.onDestroy();
- mCommandQueue.removeCallbacks(this);
+ mCommandQueue.removeCallback(this);
Dependency.get(AccessibilityManagerWrapper.class).removeCallback(
mAccessibilityListener);
mContentResolver.unregisterContentObserver(mMagnificationObserver);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 12a0cc882a81..3984405f8e09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -24,7 +24,6 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.IWallpaperVisibilityListener;
import android.view.IWindowManager;
-import android.view.MotionEvent;
import android.view.View;
import com.android.internal.statusbar.IStatusBarService;
@@ -165,23 +164,4 @@ public final class NavigationBarTransitions extends BarTransitions {
}
mView.onDarkIntensityChange(darkIntensity);
}
-
- private final View.OnTouchListener mLightsOutListener = new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- // even though setting the systemUI visibility below will turn these views
- // on, we need them to come up faster so that they can catch this motion
- // event
- applyLightsOut(false, false, false);
-
- try {
- mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE,
- "LightsOutListener");
- } catch (android.os.RemoteException ex) {
- }
- }
- return false;
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index 3e31fa06ef27..2a68fa598603 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -82,7 +82,7 @@ public class NotificationGroupAlertTransferHelper implements OnGroupChangeListen
private boolean mIsDozing;
public NotificationGroupAlertTransferHelper() {
- Dependency.get(StatusBarStateController.class).addListener(this);
+ Dependency.get(StatusBarStateController.class).addCallback(this);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 448b5c38da51..8f4369a98b17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -55,7 +55,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener,
private boolean mIsUpdatingUnchangedGroup;
public NotificationGroupManager() {
- Dependency.get(StatusBarStateController.class).addListener(this);
+ Dependency.get(StatusBarStateController.class).addCallback(this);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 33d176a580da..a2a11bbfd650 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -366,7 +366,7 @@ public class NotificationPanelView extends PanelView implements
protected void onAttachedToWindow() {
super.onAttachedToWindow();
FragmentHostManager.get(this).addTagListener(QS.TAG, mFragmentListener);
- Dependency.get(StatusBarStateController.class).addListener(this);
+ Dependency.get(StatusBarStateController.class).addCallback(this);
Dependency.get(ZenModeController.class).addCallback(this);
Dependency.get(ConfigurationController.class).addCallback(this);
}
@@ -375,7 +375,7 @@ public class NotificationPanelView extends PanelView implements
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
FragmentHostManager.get(this).removeTagListener(QS.TAG, mFragmentListener);
- Dependency.get(StatusBarStateController.class).removeListener(this);
+ Dependency.get(StatusBarStateController.class).removeCallback(this);
Dependency.get(ZenModeController.class).removeCallback(this);
Dependency.get(ConfigurationController.class).removeCallback(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index c84f3db8acb0..ee1eb42a07f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -268,7 +268,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
mLocationController.addCallback(this);
mPrivacyItemController.setListening(true);
- SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
+ SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
// Clear out all old notifications on startup (only present in the case where sysui dies)
@@ -296,7 +296,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks,
mKeyguardMonitor.removeCallback(this);
mLocationController.removeCallback(this);
mPrivacyItemController.setListening(false);
- SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallbacks(this);
+ SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallback(this);
mContext.unregisterReceiver(mIntentReceiver);
NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 2cbf27c6e61c..4983618ba414 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -185,6 +185,7 @@ public class QuickStepController implements GestureHelper {
// Requires proxy and an active gesture or able to perform any gesture to continue
if (mOverviewEventSender.getProxy() == null
+ || !mOverviewEventSender.shouldShowSwipeUpUI()
|| (mCurrentAction == null && !canPerformAnyAction())) {
return deadZoneConsumed;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 5723948bc293..96ec6be1f957 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -161,7 +161,6 @@ import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.Snoo
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.qs.car.CarQSFragment;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -580,6 +579,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private boolean mVibrateOnOpening;
private VibratorHelper mVibratorHelper;
protected NotificationPresenter mPresenter;
+ private boolean mPulsing;
@Override
public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
@@ -628,7 +628,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mBubbleController.setExpandListener(mBubbleExpandListener);
mColorExtractor.addOnColorsChangedListener(this);
- mStatusBarStateController.addListener(this, StatusBarStateController.RANK_STATUS_BAR);
+ mStatusBarStateController.addCallback(this, StatusBarStateController.RANK_STATUS_BAR);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mDreamManager = IDreamManager.Stub.asInterface(
@@ -664,7 +664,7 @@ public class StatusBar extends SystemUI implements DemoMode,
// Connect in to the status bar manager service
mCommandQueue = getComponent(CommandQueue.class);
- mCommandQueue.addCallbacks(this);
+ mCommandQueue.addCallback(this);
int[] switches = new int[9];
ArrayList<IBinder> binders = new ArrayList<>();
@@ -920,8 +920,7 @@ public class StatusBar extends SystemUI implements DemoMode,
Dependency.get(ExtensionController.class)
.newExtension(QS.class)
.withPlugin(QS.class)
- .withFeature(PackageManager.FEATURE_AUTOMOTIVE, CarQSFragment::new)
- .withDefault(QSFragment::new)
+ .withDefault(this::createDefaultQSFragment)
.build());
final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mIconController);
@@ -1009,6 +1008,10 @@ public class StatusBar extends SystemUI implements DemoMode,
ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
}
+ protected QS createDefaultQSFragment() {
+ return new QSFragment();
+ }
+
protected void setUpPresenter() {
// Set up the initial notification state.
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
@@ -1542,7 +1545,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public boolean isPulsing() {
- return mAmbientPulseManager.hasNotifications();
+ return mPulsing;
}
public boolean isLaunchTransitionFadingAway() {
@@ -2524,7 +2527,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
if (dismissShade) {
- if (mExpandedVisible) {
+ if (mExpandedVisible && !mBouncerShowing) {
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
true /* delayed*/);
} else {
@@ -2887,7 +2890,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mContext.unregisterReceiver(mDemoReceiver);
mAssistManager.destroy();
mHeadsUpManager.destroy();
- mStatusBarStateController.removeListener(this);
+ mStatusBarStateController.removeCallback(this);
if (mQSPanel != null && mQSPanel.getHost() != null) {
mQSPanel.getHost().destroy();
@@ -3205,6 +3208,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanel.onAffordanceLaunchEnded();
mNotificationPanel.animate().cancel();
mNotificationPanel.setAlpha(1f);
+ updateScrimController();
Trace.endSection();
return staying;
}
@@ -3933,6 +3937,10 @@ public class StatusBar extends SystemUI implements DemoMode,
return;
}
+ // Set the state to pulsing, so ScrimController will know what to do once we ask it to
+ // execute the transition. The pulse callback will then be invoked when the scrims
+ // are black, indicating that StatusBar is ready to present the rest of the UI.
+ mPulsing = true;
mDozeScrimController.pulse(new PulseCallback() {
@Override
public void onPulseStarted() {
@@ -3946,6 +3954,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onPulseFinished() {
+ mPulsing = false;
callback.onPulseFinished();
setPulsing(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 7c17c018443e..4f25349ef7d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -76,7 +76,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
loadDimens();
SysUiServiceProvider.getComponent(context, CommandQueue.class)
- .addCallbacks(this);
+ .addCallback(this);
Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 484fe110b28a..0f8970f1069f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -151,7 +151,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mLockPatternUtils = lockPatternUtils;
mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback);
- Dependency.get(StatusBarStateController.class).addListener(this);
+ Dependency.get(StatusBarStateController.class).addCallback(this);
}
public void registerStatusBar(StatusBar statusBar,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index a743d41e8d3a..e3f6bd8f21f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -70,10 +70,10 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks {
mContext = context;
mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL,
new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null);
- mStatusBarStateController.addListener(mStateListener);
+ mStatusBarStateController.addCallback(mStateListener);
mKeyguardManager = context.getSystemService(KeyguardManager.class);
mCommandQueue = getComponent(context, CommandQueue.class);
- mCommandQueue.addCallbacks(this);
+ mCommandQueue.addCallback(this);
}
private void setStatusBarState(int state) {
@@ -206,7 +206,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks {
}
@Override
- public boolean handleRemoteViewClick(PendingIntent pendingIntent,
+ public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
NotificationRemoteInputManager.ClickHandler defaultHandler) {
final boolean isActivity = pendingIntent.isActivity();
if (isActivity) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 158ee8ae8fbd..986a86d13958 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -92,7 +92,7 @@ public class StatusBarWindowController implements Callback, Dumpable, Configurat
mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
mDozeParameters = dozeParameters;
mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
- Dependency.get(StatusBarStateController.class).addListener(
+ Dependency.get(StatusBarStateController.class).addCallback(
mStateListener, StatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER);
Dependency.get(ConfigurationController.class).addCallback(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index c2af95e66fe9..aafdcd50b8e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -187,7 +187,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
null, Dependency.get(Dependency.TIME_TICK_HANDLER));
Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
StatusBarIconController.ICON_BLACKLIST);
- SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
+ SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallback(this);
if (mShowDark) {
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
}
@@ -215,7 +215,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
mAttached = false;
Dependency.get(TunerService.class).removeTunable(this);
SysUiServiceProvider.getComponent(getContext(), CommandQueue.class)
- .removeCallbacks(this);
+ .removeCallback(this);
if (mShowDark) {
Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index f36066ce3794..2a4336e809a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -21,7 +21,6 @@ import android.text.TextPaint;
import android.text.method.TransformationMethod;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.Size;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -41,6 +40,7 @@ import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import java.text.BreakIterator;
+import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
@@ -282,9 +282,9 @@ public class SmartReplyView extends ViewGroup {
Drawable iconDrawable = action.getIcon().loadDrawable(context);
// Add the action icon to the Smart Action button.
- Size newIconSize = calculateIconSizeFromSingleLineButton(context, root,
- new Size(iconDrawable.getIntrinsicWidth(), iconDrawable.getIntrinsicHeight()));
- iconDrawable.setBounds(0, 0, newIconSize.getWidth(), newIconSize.getHeight());
+ int newIconSize = context.getResources().getDimensionPixelSize(
+ R.dimen.smart_action_button_icon_size);
+ iconDrawable.setBounds(0, 0, newIconSize, newIconSize);
button.setCompoundDrawables(iconDrawable, null, null, null);
button.setOnClickListener(view ->
@@ -295,30 +295,12 @@ public class SmartReplyView extends ViewGroup {
// TODO(b/119010281): handle accessibility
+ // Mark this as an Action button
+ final LayoutParams lp = (LayoutParams) button.getLayoutParams();
+ lp.buttonType = SmartButtonType.ACTION;
return button;
}
- private static Size calculateIconSizeFromSingleLineButton(Context context, ViewGroup root,
- Size originalIconSize) {
- Button button = (Button) LayoutInflater.from(context).inflate(
- R.layout.smart_action_button, root, false);
- // Add simple text here to ensure the button displays one line of text.
- button.setText("a");
- return calculateIconSizeFromButtonHeight(button, originalIconSize);
- }
-
- // Given a button with text on a single line - we want to add an icon to that button. This
- // method calculates the icon height to use to avoid making the button grow in height.
- private static Size calculateIconSizeFromButtonHeight(Button button, Size originalIconSize) {
- // A completely permissive measure spec should make the button text single-line.
- button.measure(MEASURE_SPEC_ANY_LENGTH, MEASURE_SPEC_ANY_LENGTH);
- int buttonHeight = button.getMeasuredHeight();
- int newIconHeight = buttonHeight / 2;
- int newIconWidth = (int) (originalIconSize.getWidth()
- * ((double) newIconHeight) / originalIconSize.getHeight());
- return new Size(newIconWidth, newIconHeight);
- }
-
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(mContext, attrs);
@@ -352,18 +334,26 @@ public class SmartReplyView extends ViewGroup {
int displayedChildCount = 0;
int buttonPaddingHorizontal = mSingleLineButtonPaddingHorizontal;
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
+ // Set up a list of suggestions where actions come before replies. Note that the Buttons
+ // themselves have already been added to the view hierarchy in an order such that Smart
+ // Replies are shown before Smart Actions. The order of the list below determines which
+ // suggestions will be shown at all - only the first X elements are shown (where X depends
+ // on how much space each suggestion button needs).
+ List<View> smartActions = filterActionsOrReplies(SmartButtonType.ACTION);
+ List<View> smartReplies = filterActionsOrReplies(SmartButtonType.REPLY);
+ List<View> smartSuggestions = new ArrayList<>(smartActions);
+ smartSuggestions.addAll(smartReplies);
+ List<View> coveredSuggestions = new ArrayList<>();
+
+ for (View child : smartSuggestions) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- if (child.getVisibility() != View.VISIBLE || !(child instanceof Button)) {
- continue;
- }
child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
buttonPaddingHorizontal, child.getPaddingBottom());
child.measure(MEASURE_SPEC_ANY_LENGTH, heightMeasureSpec);
+ coveredSuggestions.add(child);
+
final int lineCount = ((Button) child).getLineCount();
if (lineCount < 1 || lineCount > 2) {
// If smart reply has no text, or more than two lines, then don't show it.
@@ -417,7 +407,8 @@ public class SmartReplyView extends ViewGroup {
// Mark all buttons from the last squeezing round as "failed to squeeze", so
// that they're re-measured without squeezing later.
- markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_FAILED, i);
+ markButtonsWithPendingSqueezeStatusAs(
+ LayoutParams.SQUEEZE_STATUS_FAILED, coveredSuggestions);
// The current button doesn't fit, so there's no point in measuring further
// buttons.
@@ -426,7 +417,8 @@ public class SmartReplyView extends ViewGroup {
// The current button fits, so mark all squeezed buttons as "successfully squeezed"
// to prevent them from being un-squeezed in a subsequent squeezing round.
- markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_SUCCESSFUL, i);
+ markButtonsWithPendingSqueezeStatusAs(
+ LayoutParams.SQUEEZE_STATUS_SUCCESSFUL, coveredSuggestions);
}
lp.show = true;
@@ -445,6 +437,22 @@ public class SmartReplyView extends ViewGroup {
mPaddingTop + maxChildHeight + mPaddingBottom), heightMeasureSpec));
}
+ private List<View> filterActionsOrReplies(SmartButtonType buttonType) {
+ List<View> actions = new ArrayList<>();
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (child.getVisibility() != View.VISIBLE || !(child instanceof Button)) {
+ continue;
+ }
+ if (lp.buttonType == buttonType) {
+ actions.add(child);
+ }
+ }
+ return actions;
+ }
+
private void resetButtonsLayoutParams() {
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -615,9 +623,9 @@ public class SmartReplyView extends ViewGroup {
}
}
- private void markButtonsWithPendingSqueezeStatusAs(int squeezeStatus, int maxChildIndex) {
- for (int i = 0; i <= maxChildIndex; i++) {
- final View child = getChildAt(i);
+ private void markButtonsWithPendingSqueezeStatusAs(
+ int squeezeStatus, List<View> coveredChildren) {
+ for (View child : coveredChildren) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.squeezeStatus == LayoutParams.SQUEEZE_STATUS_PENDING) {
lp.squeezeStatus = squeezeStatus;
@@ -712,6 +720,11 @@ public class SmartReplyView extends ViewGroup {
return mActivityStarter;
}
+ private enum SmartButtonType {
+ REPLY,
+ ACTION
+ }
+
@VisibleForTesting
static class LayoutParams extends ViewGroup.LayoutParams {
@@ -737,6 +750,7 @@ public class SmartReplyView extends ViewGroup {
private boolean show = false;
private int squeezeStatus = SQUEEZE_STATUS_NONE;
+ private SmartButtonType buttonType = SmartButtonType.REPLY;
private LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index cd379c5f551f..4a69cd783a6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -42,7 +42,7 @@ public class TvStatusBar extends SystemUI implements Callbacks {
public void start() {
putComponent(TvStatusBar.class, this);
CommandQueue commandQueue = getComponent(CommandQueue.class);
- commandQueue.addCallbacks(this);
+ commandQueue.addCallback(this);
int[] switches = new int[9];
ArrayList<IBinder> binders = new ArrayList<>();
ArrayList<String> iconSlots = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/util/Assert.java b/packages/SystemUI/src/com/android/systemui/util/Assert.java
index 0f7c9a462c0a..096ac3fcee1d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Assert.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Assert.java
@@ -18,19 +18,24 @@ package com.android.systemui.util;
import android.os.Looper;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Helper providing common assertions.
*/
public class Assert {
+ @VisibleForTesting
+ public static Looper sMainLooper = Looper.getMainLooper();
+
public static void isMainThread() {
- if (!Looper.getMainLooper().isCurrentThread()) {
+ if (!sMainLooper.isCurrentThread()) {
throw new IllegalStateException("should be called from the main thread.");
}
}
public static void isNotMainThread() {
- if (Looper.getMainLooper().isCurrentThread()) {
+ if (sMainLooper.isCurrentThread()) {
throw new IllegalStateException("should not be called from the main thread.");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 6812410c851c..490cdd5ce9bd 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -57,13 +57,13 @@ public class Utils {
public void onViewAttachedToWindow(View v) {
mView = v;
SysUiServiceProvider.getComponent(v.getContext(), CommandQueue.class)
- .addCallbacks(this);
+ .addCallback(this);
}
@Override
public void onViewDetachedFromWindow(View v) {
SysUiServiceProvider.getComponent(mView.getContext(), CommandQueue.class)
- .removeCallbacks(this);
+ .removeCallback(this);
mView = null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
deleted file mode 100644
index 9b616e00a72f..000000000000
--- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.volume;
-
-import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorSet;
-import android.annotation.DrawableRes;
-import android.annotation.Nullable;
-import android.app.Dialog;
-import android.app.KeyguardManager;
-import android.car.Car;
-import android.car.CarNotConnectedException;
-import android.car.media.CarAudioManager;
-import android.car.media.ICarVolumeCallback;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.ServiceConnection;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.os.Debug;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.Xml;
-import android.view.ContextThemeWrapper;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
-
-import androidx.car.widget.ListItem;
-import androidx.car.widget.ListItemAdapter;
-import androidx.car.widget.ListItemAdapter.BackgroundStyle;
-import androidx.car.widget.ListItemProvider.ListProvider;
-import androidx.car.widget.PagedListView;
-import androidx.car.widget.SeekbarListItem;
-
-import com.android.systemui.R;
-import com.android.systemui.plugins.VolumeDialog;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Car version of the volume dialog.
- *
- * Methods ending in "H" must be called on the (ui) handler.
- */
-public class CarVolumeDialogImpl implements VolumeDialog {
- private static final String TAG = Util.logTag(CarVolumeDialogImpl.class);
-
- private static final String XML_TAG_VOLUME_ITEMS = "carVolumeItems";
- private static final String XML_TAG_VOLUME_ITEM = "item";
- private static final int HOVERING_TIMEOUT = 16000;
- private static final int NORMAL_TIMEOUT = 3000;
- private static final int LISTVIEW_ANIMATION_DURATION_IN_MILLIS = 250;
- private static final int DISMISS_DELAY_IN_MILLIS = 50;
- private static final int ARROW_FADE_IN_START_DELAY_IN_MILLIS = 100;
-
- private final Context mContext;
- private final H mHandler = new H();
-
- private Window mWindow;
- private CustomDialog mDialog;
- private PagedListView mListView;
- private ListItemAdapter mPagedListAdapter;
- // All the volume items.
- private final SparseArray<VolumeItem> mVolumeItems = new SparseArray<>();
- // Available volume items in car audio manager.
- private final List<VolumeItem> mAvailableVolumeItems = new ArrayList<>();
- // Volume items in the PagedListView.
- private final List<ListItem> mVolumeLineItems = new ArrayList<>();
- private final KeyguardManager mKeyguard;
-
- private Car mCar;
- private CarAudioManager mCarAudioManager;
-
- private boolean mHovering;
- private boolean mShowing;
- private boolean mExpanded;
-
- public CarVolumeDialogImpl(Context context) {
- mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
- mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- mCar = Car.createCar(mContext, mServiceConnection);
- }
-
- public void init(int windowType, Callback callback) {
- initDialog();
-
- mCar.connect();
- }
-
- @Override
- public void destroy() {
- mHandler.removeCallbacksAndMessages(null);
-
- cleanupAudioManager();
- // unregisterVolumeCallback is not being called when disconnect car, so we manually cleanup
- // audio manager beforehand.
- mCar.disconnect();
- }
-
- private void initDialog() {
- loadAudioUsageItems();
- mVolumeLineItems.clear();
- mDialog = new CustomDialog(mContext);
-
- mHovering = false;
- mShowing = false;
- mExpanded = false;
- mWindow = mDialog.getWindow();
- mWindow.requestFeature(Window.FEATURE_NO_TITLE);
- mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
- mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
- | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
- mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
- mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
- final WindowManager.LayoutParams lp = mWindow.getAttributes();
- lp.format = PixelFormat.TRANSLUCENT;
- lp.setTitle(VolumeDialogImpl.class.getSimpleName());
- lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- lp.windowAnimations = -1;
- mWindow.setAttributes(lp);
- mWindow.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-
- mDialog.setCanceledOnTouchOutside(true);
- mDialog.setContentView(R.layout.car_volume_dialog);
- mDialog.setOnShowListener(dialog -> {
- mListView.setTranslationY(-mListView.getHeight());
- mListView.setAlpha(0);
- mListView.animate()
- .alpha(1)
- .translationY(0)
- .setDuration(LISTVIEW_ANIMATION_DURATION_IN_MILLIS)
- .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
- .start();
- });
- mListView = (PagedListView) mWindow.findViewById(R.id.volume_list);
- mListView.setOnHoverListener((v, event) -> {
- int action = event.getActionMasked();
- mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
- || (action == MotionEvent.ACTION_HOVER_MOVE);
- rescheduleTimeoutH();
- return true;
- });
-
- mPagedListAdapter = new ListItemAdapter(mContext, new ListProvider(mVolumeLineItems),
- BackgroundStyle.PANEL);
- mListView.setAdapter(mPagedListAdapter);
- mListView.setMaxPages(PagedListView.UNLIMITED_PAGES);
- }
-
- public void show(int reason) {
- mHandler.obtainMessage(H.SHOW, reason).sendToTarget();
- }
-
- public void dismiss(int reason) {
- mHandler.obtainMessage(H.DISMISS, reason).sendToTarget();
- }
-
- private void showH(int reason) {
- if (D.BUG) {
- Log.d(TAG, "showH r=" + Events.DISMISS_REASONS[reason]);
- }
-
- mHandler.removeMessages(H.SHOW);
- mHandler.removeMessages(H.DISMISS);
- rescheduleTimeoutH();
- // Refresh the data set before showing.
- mPagedListAdapter.notifyDataSetChanged();
- if (mShowing) {
- return;
- }
- mShowing = true;
-
- mDialog.show();
- Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
- }
-
- protected void rescheduleTimeoutH() {
- mHandler.removeMessages(H.DISMISS);
- final int timeout = computeTimeoutH();
- mHandler.sendMessageDelayed(mHandler
- .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT), timeout);
-
- if (D.BUG) {
- Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller());
- }
- }
-
- private int computeTimeoutH() {
- return mHovering ? HOVERING_TIMEOUT : NORMAL_TIMEOUT;
- }
-
- protected void dismissH(int reason) {
- if (D.BUG) {
- Log.d(TAG, "dismissH r=" + Events.DISMISS_REASONS[reason]);
- }
-
- mHandler.removeMessages(H.DISMISS);
- mHandler.removeMessages(H.SHOW);
- if (!mShowing) {
- return;
- }
-
- mListView.animate().cancel();
-
- mListView.setTranslationY(0);
- mListView.setAlpha(1);
- mListView.animate()
- .alpha(0)
- .translationY(-mListView.getHeight())
- .setDuration(LISTVIEW_ANIMATION_DURATION_IN_MILLIS)
- .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
- .withEndAction(() -> mHandler.postDelayed(() -> {
- if (D.BUG) {
- Log.d(TAG, "mDialog.dismiss()");
- }
- mDialog.dismiss();
- mShowing = false;
- }, DISMISS_DELAY_IN_MILLIS))
- .start();
-
- Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason);
- }
-
- public void dump(PrintWriter writer) {
- writer.println(VolumeDialogImpl.class.getSimpleName() + " state:");
- writer.print(" mShowing: "); writer.println(mShowing);
- }
-
- private void loadAudioUsageItems() {
- try (XmlResourceParser parser = mContext.getResources().getXml(R.xml.car_volume_items)) {
- AttributeSet attrs = Xml.asAttributeSet(parser);
- int type;
- // Traverse to the first start tag
- while ((type=parser.next()) != XmlResourceParser.END_DOCUMENT
- && type != XmlResourceParser.START_TAG) {
- }
-
- if (!XML_TAG_VOLUME_ITEMS.equals(parser.getName())) {
- throw new RuntimeException("Meta-data does not start with carVolumeItems tag");
- }
- int outerDepth = parser.getDepth();
- int rank = 0;
- while ((type=parser.next()) != XmlResourceParser.END_DOCUMENT
- && (type != XmlResourceParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlResourceParser.END_TAG) {
- continue;
- }
- if (XML_TAG_VOLUME_ITEM.equals(parser.getName())) {
- TypedArray item = mContext.getResources().obtainAttributes(
- attrs, R.styleable.carVolumeItems_item);
- int usage = item.getInt(R.styleable.carVolumeItems_item_usage, -1);
- if (usage >= 0) {
- VolumeItem volumeItem = new VolumeItem();
- volumeItem.usage = usage;
- volumeItem.rank = rank;
- volumeItem.icon = item.getResourceId(R.styleable.carVolumeItems_item_icon, 0);
- mVolumeItems.put(usage, volumeItem);
- rank++;
- }
- item.recycle();
- }
- }
- } catch (XmlPullParserException | IOException e) {
- Log.e(TAG, "Error parsing volume groups configuration", e);
- }
- }
-
- private VolumeItem getVolumeItemForUsages(int[] usages) {
- int rank = Integer.MAX_VALUE;
- VolumeItem result = null;
- for (int usage : usages) {
- VolumeItem volumeItem = mVolumeItems.get(usage);
- if (volumeItem.rank < rank) {
- rank = volumeItem.rank;
- result = volumeItem;
- }
- }
- return result;
- }
-
- private static int getSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
- try {
- return carAudioManager.getGroupVolume(volumeGroupId);
- } catch (CarNotConnectedException e) {
- Log.e(TAG, "Car is not connected!", e);
- }
- return 0;
- }
-
- private static int getMaxSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
- try {
- return carAudioManager.getGroupMaxVolume(volumeGroupId);
- } catch (CarNotConnectedException e) {
- Log.e(TAG, "Car is not connected!", e);
- }
- return 0;
- }
-
- private SeekbarListItem addSeekbarListItem(VolumeItem volumeItem, int volumeGroupId,
- int supplementalIconId, @Nullable View.OnClickListener supplementalIconOnClickListener) {
- SeekbarListItem listItem = new SeekbarListItem(mContext);
- listItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
- int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
- int progress = getSeekbarValue(mCarAudioManager, volumeGroupId);
- listItem.setProgress(progress);
- listItem.setOnSeekBarChangeListener(
- new CarVolumeDialogImpl.VolumeSeekBarChangeListener(volumeGroupId, mCarAudioManager));
- Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
- primaryIcon.mutate().setTint(color);
- listItem.setPrimaryActionIcon(primaryIcon);
- if (supplementalIconId != 0) {
- Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId);
- supplementalIcon.mutate().setTint(color);
- listItem.setSupplementalIcon(supplementalIcon, true);
- listItem.setSupplementalIconListener(supplementalIconOnClickListener);
- } else {
- listItem.setSupplementalEmptyIcon(true);
- listItem.setSupplementalIconListener(null);
- }
-
- mVolumeLineItems.add(listItem);
- volumeItem.listItem = listItem;
- volumeItem.progress = progress;
- return listItem;
- }
-
- private VolumeItem findVolumeItem(SeekbarListItem targetItem) {
- for (int i = 0; i < mVolumeItems.size(); ++i) {
- VolumeItem volumeItem = mVolumeItems.valueAt(i);
- if (volumeItem.listItem == targetItem) {
- return volumeItem;
- }
- }
- return null;
- }
-
- private void cleanupAudioManager() {
- try {
- mCarAudioManager.unregisterVolumeCallback(mVolumeChangeCallback.asBinder());
- } catch (CarNotConnectedException e) {
- Log.e(TAG, "Car is not connected!", e);
- }
- mVolumeLineItems.clear();
- mCarAudioManager = null;
- }
-
- private final class H extends Handler {
- private static final int SHOW = 1;
- private static final int DISMISS = 2;
-
- public H() {
- super(Looper.getMainLooper());
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case SHOW:
- showH(msg.arg1);
- break;
- case DISMISS:
- dismissH(msg.arg1);
- break;
- default:
- }
- }
- }
-
- private final class CustomDialog extends Dialog implements DialogInterface {
- public CustomDialog(Context context) {
- super(context, com.android.systemui.R.style.qs_theme);
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- rescheduleTimeoutH();
- return super.dispatchTouchEvent(ev);
- }
-
- @Override
- protected void onStart() {
- super.setCanceledOnTouchOutside(true);
- super.onStart();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (isShowing()) {
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- mHandler.obtainMessage(
- H.DISMISS, Events.DISMISS_REASON_TOUCH_OUTSIDE).sendToTarget();
- return true;
- }
- }
- return false;
- }
- }
-
- private final class ExpandIconListener implements View.OnClickListener {
- @Override
- public void onClick(final View v) {
- mExpanded = !mExpanded;
- Animator inAnimator;
- if (mExpanded) {
- for (int groupId = 0; groupId < mAvailableVolumeItems.size(); ++groupId) {
- // Adding the items which are not coming from the default item.
- VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
- if (volumeItem.defaultItem) {
- // Set progress here due to the progress of seekbar may not be updated.
- volumeItem.listItem.setProgress(volumeItem.progress);
- } else {
- addSeekbarListItem(volumeItem, groupId, 0, null);
- }
- }
- inAnimator = AnimatorInflater.loadAnimator(
- mContext, R.anim.car_arrow_fade_in_rotate_up);
- } else {
- // Only keeping the default stream if it is not expended.
- Iterator itr = mVolumeLineItems.iterator();
- while (itr.hasNext()) {
- SeekbarListItem seekbarListItem = (SeekbarListItem) itr.next();
- VolumeItem volumeItem = findVolumeItem(seekbarListItem);
- if (!volumeItem.defaultItem) {
- itr.remove();
- } else {
- // Set progress here due to the progress of seekbar may not be updated.
- seekbarListItem.setProgress(volumeItem.progress);
- }
- }
- inAnimator = AnimatorInflater.loadAnimator(
- mContext, R.anim.car_arrow_fade_in_rotate_down);
- }
-
- Animator outAnimator = AnimatorInflater.loadAnimator(
- mContext, R.anim.car_arrow_fade_out);
- inAnimator.setStartDelay(ARROW_FADE_IN_START_DELAY_IN_MILLIS);
- AnimatorSet animators = new AnimatorSet();
- animators.playTogether(outAnimator, inAnimator);
- animators.setTarget(v);
- animators.start();
- mPagedListAdapter.notifyDataSetChanged();
- }
- }
-
- private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
- private final int mVolumeGroupId;
- private final CarAudioManager mCarAudioManager;
-
- private VolumeSeekBarChangeListener(int volumeGroupId, CarAudioManager carAudioManager) {
- mVolumeGroupId = volumeGroupId;
- mCarAudioManager = carAudioManager;
- }
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (!fromUser) {
- // For instance, if this event is originated from AudioService,
- // we can ignore it as it has already been handled and doesn't need to be
- // sent back down again.
- return;
- }
- try {
- if (mCarAudioManager == null) {
- Log.w(TAG, "Ignoring volume change event because the car isn't connected");
- return;
- }
- mAvailableVolumeItems.get(mVolumeGroupId).progress = progress;
- mCarAudioManager.setGroupVolume(mVolumeGroupId, progress, 0);
- } catch (CarNotConnectedException e) {
- Log.e(TAG, "Car is not connected!", e);
- }
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {}
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {}
- }
-
- private final ICarVolumeCallback mVolumeChangeCallback = new ICarVolumeCallback.Stub() {
- @Override
- public void onGroupVolumeChanged(int groupId, int flags) {
- VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
- int value = getSeekbarValue(mCarAudioManager, groupId);
- // Do not update the progress if it is the same as before. When car audio manager sets its
- // group volume caused by the seekbar progress changed, it also triggers this callback.
- // Updating the seekbar at the same time could block the continuous seeking.
- if (value != volumeItem.progress) {
- volumeItem.listItem.setProgress(value);
- volumeItem.progress = value;
- }
- if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
- show(Events.SHOW_REASON_VOLUME_CHANGED);
- }
- }
-
- @Override
- public void onMasterMuteChanged(int flags) {
- // ignored
- }
- };
-
- private final ServiceConnection mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- try {
- mExpanded = false;
- mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
- int volumeGroupCount = mCarAudioManager.getVolumeGroupCount();
- // Populates volume slider items from volume groups to UI.
- for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
- VolumeItem volumeItem = getVolumeItemForUsages(
- mCarAudioManager.getUsagesForVolumeGroupId(groupId));
- mAvailableVolumeItems.add(volumeItem);
- // The first one is the default item.
- if (groupId == 0) {
- volumeItem.defaultItem = true;
- addSeekbarListItem(volumeItem, groupId, R.drawable.car_ic_keyboard_arrow_down,
- new ExpandIconListener());
- }
- }
-
- // If list is already initiated, update its content.
- if (mPagedListAdapter != null) {
- mPagedListAdapter.notifyDataSetChanged();
- }
- mCarAudioManager.registerVolumeCallback(mVolumeChangeCallback.asBinder());
- } catch (CarNotConnectedException e) {
- Log.e(TAG, "Car is not connected!", e);
- }
- }
-
- /**
- * This does not get called when service is properly disconnected.
- * So we need to also handle cleanups in destroy().
- */
- @Override
- public void onServiceDisconnected(ComponentName name) {
- cleanupAudioManager();
- }
- };
-
- /**
- * Wrapper class which contains information of each volume group.
- */
- private static class VolumeItem {
- private @AudioAttributes.AttributeUsage int usage;
- private int rank;
- private boolean defaultItem = false;
- private @DrawableRes int icon;
- private SeekbarListItem listItem;
- private int progress;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 2861dffe5460..080567739be7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -19,12 +19,10 @@ package com.android.systemui.volume;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.media.VolumePolicy;
import android.os.Bundle;
-import android.os.Handler;
import android.view.WindowManager.LayoutParams;
import com.android.settingslib.applications.InterestingConfigChanges;
@@ -57,7 +55,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
public static final boolean DEFAULT_DO_NOT_DISTURB_WHEN_SILENT = false;
private final SystemUI mSysui;
- private final Context mContext;
+ protected final Context mContext;
private final VolumeDialogControllerImpl mController;
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
@@ -70,7 +68,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
400 // vibrateToSilentDebounce
);
- public VolumeDialogComponent(SystemUI sysui, Context context, Handler handler) {
+ public VolumeDialogComponent(SystemUI sysui, Context context) {
mSysui = sysui;
mContext = context;
mController = (VolumeDialogControllerImpl) Dependency.get(VolumeDialogController.class);
@@ -81,7 +79,6 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
Dependency.get(ExtensionController.class).newExtension(VolumeDialog.class)
.withPlugin(VolumeDialog.class)
.withDefault(this::createDefault)
- .withFeature(PackageManager.FEATURE_AUTOMOTIVE, this::createCarDefault)
.withCallback(dialog -> {
if (mDialog != null) {
mDialog.destroy();
@@ -94,7 +91,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
VOLUME_SILENT_DO_NOT_DISTURB);
}
- private VolumeDialog createDefault() {
+ protected VolumeDialog createDefault() {
VolumeDialogImpl impl = new VolumeDialogImpl(mContext);
impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
impl.setAutomute(true);
@@ -102,10 +99,6 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna
return impl;
}
- private VolumeDialog createCarDefault() {
- return new CarVolumeDialogImpl(mContext);
- }
-
@Override
public void onTuningChanged(String key, String newValue) {
if (VOLUME_DOWN_SILENT.equals(key)) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index e4f37decdf35..f8cf79322b40 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -22,6 +22,7 @@ import android.util.Log;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
+import com.android.systemui.SystemUIFactory;
import com.android.systemui.qs.tiles.DndTile;
import java.io.FileDescriptor;
@@ -43,7 +44,9 @@ public class VolumeUI extends SystemUI {
mContext.getResources().getBoolean(R.bool.enable_safety_warning);
mEnabled = enableVolumeUi || enableSafetyWarning;
if (!mEnabled) return;
- mVolumeComponent = new VolumeDialogComponent(this, mContext, null);
+
+ mVolumeComponent = SystemUIFactory.getInstance()
+ .createVolumeDialogComponent(this, mContext);
mVolumeComponent.setEnableDialogs(enableVolumeUi, enableSafetyWarning);
putComponent(VolumeComponent.class, getVolumeComponent());
setDefaultVolumeController();
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index b32bf99ad53d..83ec33c69629 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -38,8 +38,6 @@ LOCAL_JAVA_LIBRARIES := \
android.test.runner \
telephony-common \
android.test.base \
- android.car \
- android.car.userlib
LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui:com.android.keyguard
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 9cbe4152b5c4..7ca54231fe7b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -51,7 +51,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
@RunWith(AndroidTestingRunner.class)
public class KeyguardClockSwitchTest extends SysuiTestCase {
private PluginManager mPluginManager;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
index 359832f7a542..58870e4acbd0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
@@ -38,7 +38,7 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class KeyguardPinBasedInputViewTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
index b98ce39f5ed3..77895c97051c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -19,9 +19,14 @@ import android.graphics.Color;
import android.net.Uri;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
+import androidx.slice.SliceProvider;
+import androidx.slice.SliceSpecs;
+import androidx.slice.builders.ListBuilder;
+
import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.KeyguardSliceProvider;
@@ -34,12 +39,8 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
-import androidx.slice.SliceProvider;
-import androidx.slice.SliceSpecs;
-import androidx.slice.builders.ListBuilder;
-
@SmallTest
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
@RunWith(AndroidTestingRunner.class)
public class KeyguardSliceViewTest extends SysuiTestCase {
private KeyguardSliceView mKeyguardSliceView;
@@ -47,6 +48,7 @@ public class KeyguardSliceViewTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
mKeyguardSliceView = (KeyguardSliceView) LayoutInflater.from(getContext())
.inflate(R.layout.keyguard_status_area, null);
mSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
index 9e96df2c30cf..3582ab010413 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
@@ -20,10 +20,12 @@ import static org.mockito.Mockito.verify;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -32,7 +34,7 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
@SmallTest
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
@RunWith(AndroidTestingRunner.class)
public class KeyguardStatusViewTest extends SysuiTestCase {
@@ -45,6 +47,7 @@ public class KeyguardStatusViewTest extends SysuiTestCase {
@Before
public void setUp() {
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
mKeyguardStatusView =
(KeyguardStatusView) layoutInflater.inflate(R.layout.keyguard_status_view, null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
index c180ff8fd30c..948e0014a451 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java
@@ -16,29 +16,29 @@
package com.android.systemui;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import android.animation.ObjectAnimator;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.util.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class ExpandHelperTest extends SysuiTestCase {
private ExpandableNotificationRow mRow;
@@ -47,6 +47,7 @@ public class ExpandHelperTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
Context context = getContext();
mRow = new NotificationTestHelper(context).createRow();
mCallback = mock(ExpandHelper.Callback.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index a58bc8548bd4..9c5a59243d05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -29,6 +29,7 @@ import android.testing.LeakCheck;
import android.util.Log;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.util.Assert;
import org.junit.After;
import org.junit.Before;
@@ -78,6 +79,8 @@ public abstract class SysuiTestCase {
public void SysuiTeardown() {
InstrumentationRegistry.registerInstance(mRealInstrumentation,
InstrumentationRegistry.getArguments());
+ // Reset the assert's main looper.
+ Assert.sMainLooper = Looper.getMainLooper();
}
protected LeakCheck getLeakCheck() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 368c814f8e0a..e1c481e4ef28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -28,8 +28,8 @@ import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
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.mock;
@@ -40,14 +40,12 @@ import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
-import android.view.Display;
+import android.testing.UiThreadTest;
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.wakelock.WakeLockFake;
-import android.testing.UiThreadTest;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 5c8336c8dee1..31fc625d34dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -48,7 +48,7 @@ import org.junit.runner.RunWith;
@SmallTest
@Ignore("failing")
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class DozeTriggersTest extends SysuiTestCase {
private DozeTriggers mTriggers;
private DozeMachine mMachine;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 095395185f86..c1c80ce4a70a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -55,7 +55,7 @@ import java.util.concurrent.TimeUnit;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class KeyguardSliceProviderTest extends SysuiTestCase {
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 4e24354d9878..bc7d9836d6f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -18,39 +18,32 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
-import android.app.FragmentController;
-import android.app.FragmentManagerNonConfig;
+import android.content.Context;
import android.os.Looper;
-import android.support.test.filters.FlakyTest;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.LayoutInflaterBuilder;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+import android.widget.FrameLayout;
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.CarrierText;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-
-import android.os.Parcelable;
-import android.support.test.filters.SmallTest;
-import android.testing.AndroidTestingRunner;
-
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.policy.UserSwitcherController;
-import android.testing.LayoutInflaterBuilder;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
-import android.content.Context;
-import android.view.View;
-import android.widget.FrameLayout;
-
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
@SmallTest
@Ignore
public class QSFragmentTest extends SysuiBaseFragmentTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 33b347a66b33..fd31013db429 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -22,7 +22,6 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.UserInfo;
-import android.os.Looper;
import android.os.UserManager;
import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
@@ -58,7 +57,7 @@ import org.mockito.Mockito;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class QSSecurityFooterTest extends SysuiTestCase {
private final String MANAGING_ORGANIZATION = "organization";
@@ -76,7 +75,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
@Before
public void setUp() {
mDependency.injectTestDependency(SecurityController.class, mSecurityController);
- mDependency.injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
+ mDependency.injectTestDependency(Dependency.BG_LOOPER,
+ TestableLooper.get(this).getLooper());
mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE,
new LayoutInflaterBuilder(mContext)
.replace("ImageView", TestableImageView.class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
new file mode 100644
index 000000000000..78700b88d4bc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+
+import static junit.framework.TestCase.assertFalse;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class QSTileHostTest extends SysuiTestCase {
+
+ @Test
+ public void testLoadTileSpecs_emptySetting() {
+ List<String> tiles = QSTileHost.loadTileSpecs(mContext, "");
+ assertFalse(tiles.isEmpty());
+ }
+
+ @Test
+ public void testLoadTileSpecs_nullSetting() {
+ List<String> tiles = QSTileHost.loadTileSpecs(mContext, null);
+ assertFalse(tiles.isEmpty());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java
deleted file mode 100644
index f89a93264b0c..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/car/CarQsFragmentTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-package com.android.systemui.qs.car;
-
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.mock;
-
-import android.content.Context;
-import android.support.test.filters.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.LayoutInflaterBuilder;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.keyguard.CarrierText;
-import com.android.systemui.Dependency;
-import com.android.systemui.SysuiBaseFragmentTest;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.policy.Clock;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@link CarQSFragment}.
- */
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
-@SmallTest
-@Ignore
-public class CarQsFragmentTest extends SysuiBaseFragmentTest {
- public CarQsFragmentTest() {
- super(CarQSFragment.class);
- }
-
- @Before
- public void initDependencies() {
- mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE,
- new LayoutInflaterBuilder(mContext)
- .replace("com.android.systemui.statusbar.policy.SplitClockView",
- FrameLayout.class)
- .replace("TextClock", View.class)
- .replace(CarrierText.class, View.class)
- .replace(Clock.class, View.class)
- .build());
- mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
- mDependency.injectTestDependency(Dependency.BG_LOOPER,
- TestableLooper.get(this).getLooper());
- }
-
- @Test
- @Ignore("Flaky")
- public void testLayoutInflation() {
- CarQSFragment fragment = (CarQSFragment) mFragment;
- mFragments.dispatchResume();
-
- assertNotNull(fragment.getHeader());
- assertNotNull(fragment.getFooter());
- }
-
- @Test
- @Ignore("Flaky")
- public void testListening() {
- CarQSFragment qs = (CarQSFragment) mFragment;
- mFragments.dispatchResume();
- processAllMessages();
-
- qs.setListening(true);
- processAllMessages();
-
- qs.setListening(false);
- processAllMessages();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index c016a851010a..c6597b9bd534 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -24,16 +24,15 @@ import android.content.ComponentName;
import android.os.Looper;
import android.service.quicksettings.Tile;
import android.test.suitebuilder.annotation.SmallTest;
-
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
import com.android.systemui.SysuiTestCase;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BluetoothController;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -45,7 +44,7 @@ import java.util.ArrayList;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class TileServicesTest extends SysuiTestCase {
private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 8ae3cd8d6acd..a04e57bb4990 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -14,6 +14,8 @@
package com.android.systemui.statusbar;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -42,7 +44,7 @@ public class CommandQueueTest extends SysuiTestCase {
public void setup() {
mCommandQueue = new CommandQueue();
mCallbacks = mock(Callbacks.class);
- mCommandQueue.addCallbacks(mCallbacks);
+ mCommandQueue.addCallback(mCallbacks);
verify(mCallbacks).disable(eq(0), eq(0), eq(false));
}
@@ -64,11 +66,12 @@ public class CommandQueueTest extends SysuiTestCase {
verify(mCallbacks).removeIcon(eq(slot));
}
+ // TODO(b/117478341): add test case for multi-display
@Test
public void testDisable() {
int state1 = 14;
int state2 = 42;
- mCommandQueue.disable(state1, state2);
+ mCommandQueue.disable(DEFAULT_DISPLAY, state1, state2);
waitForIdleSync();
verify(mCallbacks).disable(eq(state1), eq(state2), eq(true));
}
@@ -95,24 +98,27 @@ public class CommandQueueTest extends SysuiTestCase {
verify(mCallbacks).animateExpandSettingsPanel(eq(panel));
}
+ // TODO(b/117478341): add test case for multi-display
@Test
public void testSetSystemUiVisibility() {
Rect r = new Rect();
- mCommandQueue.setSystemUiVisibility(1, 2, 3, 4, null, r);
+ mCommandQueue.setSystemUiVisibility(DEFAULT_DISPLAY, 1, 2, 3, 4, null, r);
waitForIdleSync();
verify(mCallbacks).setSystemUiVisibility(eq(1), eq(2), eq(3), eq(4), eq(null), eq(r));
}
+ // TODO(b/117478341): add test case for multi-display
@Test
public void testTopAppWindowChanged() {
- mCommandQueue.topAppWindowChanged(true);
+ mCommandQueue.topAppWindowChanged(DEFAULT_DISPLAY, true);
waitForIdleSync();
verify(mCallbacks).topAppWindowChanged(eq(true));
}
+ // TODO(b/117478341): add test case for multi-display
@Test
public void testShowImeButton() {
- mCommandQueue.setImeWindowStatus(null, 1, 2, true);
+ mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true);
waitForIdleSync();
verify(mCallbacks).setImeWindowStatus(eq(null), eq(1), eq(2), eq(true));
}
@@ -166,9 +172,10 @@ public class CommandQueueTest extends SysuiTestCase {
verify(mCallbacks).toggleKeyboardShortcutsMenu(eq(1));
}
+ // TODO(b/117478341): add test case for multi-display
@Test
public void testSetWindowState() {
- mCommandQueue.setWindowState(1, 2);
+ mCommandQueue.setWindowState(DEFAULT_DISPLAY, 1, 2);
waitForIdleSync();
verify(mCallbacks).setWindowState(eq(1), eq(2));
}
@@ -180,30 +187,34 @@ public class CommandQueueTest extends SysuiTestCase {
verify(mCallbacks).showScreenPinningRequest(eq(1));
}
+ // TODO(b/117478341): add test case for multi-display
@Test
public void testAppTransitionPending() {
- mCommandQueue.appTransitionPending();
+ mCommandQueue.appTransitionPending(DEFAULT_DISPLAY);
waitForIdleSync();
verify(mCallbacks).appTransitionPending(eq(false));
}
+ // TODO(b/117478341): add test case for multi-display
@Test
public void testAppTransitionCancelled() {
- mCommandQueue.appTransitionCancelled();
+ mCommandQueue.appTransitionCancelled(DEFAULT_DISPLAY);
waitForIdleSync();
verify(mCallbacks).appTransitionCancelled();
}
+ // TODO(b/117478341): add test case for multi-display
@Test
public void testAppTransitionStarting() {
- mCommandQueue.appTransitionStarting(1, 2);
+ mCommandQueue.appTransitionStarting(DEFAULT_DISPLAY, 1, 2);
waitForIdleSync();
verify(mCallbacks).appTransitionStarting(eq(1L), eq(2L), eq(false));
}
+ // TODO(b/117478341): add test case for multi-display
@Test
public void testAppTransitionFinished() {
- mCommandQueue.appTransitionFinished();
+ mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY);
waitForIdleSync();
verify(mCallbacks).appTransitionFinished();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 2e280d336aab..9449e297fcc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -50,7 +50,7 @@ import org.mockito.MockitoAnnotations;
*/
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
@Ignore("b/118400112")
public class NonPhoneDependencyTest extends SysuiTestCase {
@Mock private NotificationPresenter mPresenter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 63ececbe2994..65c04fe4bcd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -16,15 +16,12 @@
package com.android.systemui.statusbar;
-import static junit.framework.Assert.assertTrue;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.os.Handler;
-import android.os.Looper;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
@@ -45,7 +42,7 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
public class NotificationListenerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
private static final int TEST_UID = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 72d6cd8eaeea..520a927d1ab0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -46,6 +46,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.util.Assert;
import com.google.android.collect.Lists;
@@ -60,7 +61,7 @@ import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Mock private NotificationPresenter mPresenter;
@Mock private NotificationData mNotificationData;
@@ -79,6 +80,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
mDependency.injectTestDependency(NotificationLockscreenUserManager.class,
mLockscreenUserManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
index b7aa21b86d33..db2c8780e783 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
@@ -19,15 +19,15 @@ package com.android.systemui.statusbar.notification;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.widget.FrameLayout;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import org.junit.Assert;
import org.junit.Before;
@@ -36,7 +36,7 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class AboveShelfObserverTest extends SysuiTestCase {
private AboveShelfObserver mObserver;
@@ -46,6 +46,7 @@ public class AboveShelfObserverTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
mNotificationTestHelper = new NotificationTestHelper(getContext());
mHostLayout = new FrameLayout(getContext());
mObserver = new AboveShelfObserver(mHostLayout);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
index f94ba95999bf..8e88ed0556bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
@@ -53,6 +53,7 @@ import android.service.notification.StatusBarNotification;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.ArraySet;
@@ -78,7 +79,7 @@ import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class NotificationDataTest extends SysuiTestCase {
private static final int UID_NORMAL = 123;
@@ -101,6 +102,7 @@ public class NotificationDataTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
MockitoAnnotations.initMocks(this);
when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java
index 63d1e8dbc954..24aa772e2fc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationViewWrapperTest.java
@@ -17,28 +17,29 @@
package com.android.systemui.statusbar.notification;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
+import com.android.systemui.util.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidTestingRunner.class)
@SmallTest
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class NotificationViewWrapperTest extends SysuiTestCase {
@Test
public void constructor_doesntUseViewContext() throws Exception {
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
new TestableNotificationViewWrapper(mContext,
new View(mContext),
new NotificationTestHelper(getContext()).createRow());
@@ -50,4 +51,4 @@ public class NotificationViewWrapperTest extends SysuiTestCase {
super(ctx, view, row);
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 3710fa833d50..512acd073a84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -37,13 +37,13 @@ import android.testing.TestableLooper;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.SysuiTestCase;
-
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+
import com.google.android.collect.Lists;
import org.junit.Before;
@@ -58,7 +58,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
public class NotificationLoggerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test";
private static final int TEST_UID = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 2da72e7858c8..6d3553912701 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -40,6 +40,7 @@ import android.app.AppOpsManager;
import android.app.NotificationChannel;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.ArraySet;
import android.view.NotificationHeaderView;
@@ -64,7 +65,7 @@ import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class ExpandableNotificationRowTest extends SysuiTestCase {
private ExpandableNotificationRow mGroupRow;
@@ -77,6 +78,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
mNotificationTestHelper = new NotificationTestHelper(mContext);
mGroupRow = mNotificationTestHelper.createGroup();
mGroupRow.setHeadsUpAnimatingAwayListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
index 4efab5385c0a..669b98e1b279 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
@@ -16,10 +16,18 @@
package com.android.systemui.statusbar.notification.row;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.NotificationTestHelper;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.support.test.filters.FlakyTest;
@@ -28,30 +36,24 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.util.Assert;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
/**
* Tests for {@link NotificationBlockingHelperManager}.
*/
@SmallTest
@FlakyTest
@org.junit.runner.RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
private NotificationBlockingHelperManager mBlockingHelperManager;
@@ -65,6 +67,7 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
@Before
public void setUp() {
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
MockitoAnnotations.initMocks(this);
when(mGutsManager.openGuts(
any(View.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 766c5d2377c6..8966aca3069c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -64,6 +64,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.util.Assert;
import org.junit.Before;
import org.junit.Rule;
@@ -79,7 +80,7 @@ import org.mockito.junit.MockitoRule;
*/
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
public class NotificationGutsManagerTest extends SysuiTestCase {
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
@@ -101,6 +102,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
@Before
public void setUp() {
mTestableLooper = TestableLooper.get(this);
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
mDependency.injectTestDependency(DeviceProvisionedController.class,
mDeviceProvisionedController);
mHandler = Handler.createAsync(mTestableLooper.getLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index 906e718f19d9..e4d019656072 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -25,7 +25,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.Notification;
+import android.app.NotificationChannel;
import android.service.notification.StatusBarNotification;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -35,6 +35,7 @@ import android.testing.ViewUtils;
import android.view.ViewGroup;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
@@ -43,19 +44,26 @@ import org.junit.runner.RunWith;
import org.mockito.Mockito;
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper()
+@RunWithLooper
@SmallTest
public class NotificationMenuRowTest extends LeakCheckedTest {
+ private ExpandableNotificationRow mRow;
+
@Before
public void setup() {
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
+ mRow = mock(ExpandableNotificationRow.class);
+ NotificationData.Entry entry = new NotificationData.Entry(
+ mock(StatusBarNotification.class));
+ entry.channel = mock(NotificationChannel.class);
+ when(mRow.getEntry()).thenReturn(entry);
}
@Test
public void testAttachDetach() {
NotificationMenuRowPlugin row = new NotificationMenuRow(mContext);
- row.createMenu(null, null);
+ row.createMenu(mRow, null);
ViewUtils.attachView(row.getMenuView());
TestableLooper.get(this).processAllMessages();
ViewUtils.detachView(row.getMenuView());
@@ -65,9 +73,9 @@ public class NotificationMenuRowTest extends LeakCheckedTest {
@Test
public void testRecreateMenu() {
NotificationMenuRowPlugin row = new NotificationMenuRow(mContext);
- row.createMenu(null, null);
+ row.createMenu(mRow, null);
assertTrue(row.getMenuView() != null);
- row.createMenu(null, null);
+ row.createMenu(mRow, null);
assertTrue(row.getMenuView() != null);
}
@@ -81,12 +89,7 @@ public class NotificationMenuRowTest extends LeakCheckedTest {
@Test
public void testNoAppOpsInSlowSwipe() {
NotificationMenuRow row = new NotificationMenuRow(mContext);
- Notification n = mock(Notification.class);
- StatusBarNotification sbn = mock(StatusBarNotification.class);
- when(sbn.getNotification()).thenReturn(n);
- ExpandableNotificationRow parent = mock(ExpandableNotificationRow.class);
- when(parent.getStatusBarNotification()).thenReturn(sbn);
- row.createMenu(parent, null);
+ row.createMenu(mRow, null);
ViewGroup container = (ViewGroup) row.getMenuView();
// one for snooze and one for noti blocking
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
index 4b94a2523cfe..fed66af07bcc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.row.wrapper;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import android.widget.RemoteViews;
@@ -34,13 +35,14 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class NotificationCustomViewWrapperTest extends SysuiTestCase {
private ExpandableNotificationRow mRow;
@Before
public void setUp() throws Exception {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
mRow = new NotificationTestHelper(mContext).createRow();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index 272845396e27..bbafb4e4a211 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -18,13 +18,14 @@ package com.android.systemui.statusbar.notification.stack;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.NotificationHeaderView;
import android.view.View;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import org.junit.Assert;
import org.junit.Before;
@@ -33,16 +34,16 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class NotificationChildrenContainerTest extends SysuiTestCase {
private ExpandableNotificationRow mGroup;
- private int mId;
private NotificationTestHelper mNotificationTestHelper;
private NotificationChildrenContainer mChildrenContainer;
@Before
public void setUp() throws Exception {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
mNotificationTestHelper = new NotificationTestHelper(mContext);
mGroup = mNotificationTestHelper.createGroup();
mChildrenContainer = mGroup.getChildrenContainer();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
index 662e016b77ff..8ae7d52a5da5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import com.android.systemui.SysuiTestCase;
@@ -41,7 +42,7 @@ import java.util.HashSet;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class NotificationRoundnessManagerTest extends SysuiTestCase {
private NotificationRoundnessManager mRoundnessManager = new NotificationRoundnessManager();
@@ -52,6 +53,7 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
NotificationTestHelper testHelper = new NotificationTestHelper(getContext());
mFirst = testHelper.createRow();
mFirst.setHeadsUpAnimatingAwayListener(animatingAway
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index c99e766ac697..4f6329cb0c57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -23,18 +23,18 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import android.widget.TextView;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import org.junit.Assert;
import org.junit.Before;
@@ -43,7 +43,7 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
private final NotificationStackScrollLayout mStackScroller =
@@ -58,6 +58,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
NotificationTestHelper testHelper = new NotificationTestHelper(getContext());
mFirst = testHelper.createRow();
mDependency.injectTestDependency(DarkIconDispatcher.class, mDarkIconDispatcher);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 7f8668fa064c..f7a95c50fee8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.content.res.ColorStateList;
import android.graphics.Color;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -35,7 +36,6 @@ import android.testing.TestableLooper;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
-import android.content.res.ColorStateList;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardHostView;
@@ -56,7 +56,7 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
public class KeyguardBouncerTest extends SysuiTestCase {
@Mock
@@ -78,6 +78,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Before
public void setup() {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
MockitoAnnotations.initMocks(this);
DejankUtils.setImmediate(true);
final ViewGroup container = new FrameLayout(getContext());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 31014b8a62e9..27ed9c5a14c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -30,7 +30,7 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
private static final int SCREEN_HEIGHT = 2000;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java
index 54291536093c..c5875554b073 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardPresentationTest.java
@@ -20,21 +20,20 @@ import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater;
-import android.view.View;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
public class KeyguardPresentationTest extends SysuiTestCase {
@Test
public void testInflation_doesntCrash() {
+ com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
LayoutInflater inflater = LayoutInflater.from(getContext());
inflater.inflate(R.layout.keyguard_presentation, null);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
index 8fc15b247ab9..cdaa2420186f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
@@ -29,7 +29,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.anyFloat;
-import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -38,11 +37,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import com.android.systemui.R;
-import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.shared.recents.IOverviewProxy;
-import com.android.systemui.SysuiTestCase;
-
import android.content.Context;
import android.content.res.Resources;
import android.support.test.filters.SmallTest;
@@ -51,6 +45,11 @@ import android.testing.TestableLooper.RunWithLooper;
import android.view.MotionEvent;
import android.view.View;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.shared.recents.IOverviewProxy;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -59,7 +58,7 @@ import org.mockito.MockitoAnnotations;
/** atest QuickStepControllerTest */
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
@SmallTest
public class QuickStepControllerTest extends SysuiTestCase {
private QuickStepController mController;
@@ -78,6 +77,7 @@ public class QuickStepControllerTest extends SysuiTestCase {
mProxyService = mock(OverviewProxyService.class);
mProxy = mock(IOverviewProxy.Stub.class);
doReturn(mProxy).when(mProxyService).getProxy();
+ doReturn(true).when(mProxyService).shouldShowSwipeUpUI();
mDependency.injectTestDependency(OverviewProxyService.class, mProxyService);
mStatusBar = mock(StatusBar.class);
@@ -106,6 +106,18 @@ public class QuickStepControllerTest extends SysuiTestCase {
}
@Test
+ public void testNoGesturesWhenSwipeUpDisabled() throws Exception {
+ doReturn(false).when(mProxyService).shouldShowSwipeUpUI();
+ mController.setGestureActions(mockAction(true), null /* swipeDownAction */,
+ null /* swipeLeftAction */, null /* swipeRightAction */);
+
+ MotionEvent ev = event(MotionEvent.ACTION_DOWN, 1, 1);
+ assertFalse(mController.onInterceptTouchEvent(ev));
+ verify(mNavigationBarView, never()).requestUnbufferedDispatch(ev);
+ assertNull(mController.getCurrentAction());
+ }
+
+ @Test
public void testHasActionDetectGesturesTouchdown() throws Exception {
MotionEvent ev = event(MotionEvent.ACTION_DOWN, 1, 1);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index e9e8eb785d1a..c207feff26f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -72,6 +72,8 @@ import com.android.systemui.appops.AppOpsControllerImpl;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.doze.DozeHost;
+import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
@@ -123,6 +125,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private IStatusBarService mBarService;
@Mock private IDreamManager mDreamManager;
@Mock private ScrimController mScrimController;
+ @Mock private DozeScrimController mDozeScrimController;
@Mock private ArrayList<Entry> mNotificationList;
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private NotificationData mNotificationData;
@@ -211,7 +214,7 @@ public class StatusBarTest extends SysuiTestCase {
mKeyguardViewMediator, mRemoteInputManager, mock(NotificationGroupManager.class),
mock(NotificationGroupAlertTransferHelper.class), mock(FalsingManager.class),
mock(StatusBarWindowController.class), mock(NotificationIconAreaController.class),
- mock(DozeScrimController.class), mock(NotificationShelf.class),
+ mDozeScrimController, mock(NotificationShelf.class),
mLockscreenUserManager, mCommandQueue, mNotificationPresenter,
mock(BubbleController.class));
mStatusBar.mContext = mContext;
@@ -570,7 +573,28 @@ public class StatusBarTest extends SysuiTestCase {
}
@Test
+ public void testPulseWhileDozing_updatesScrimController() {
+ mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+ mStatusBar.showKeyguardImpl();
+
+ // Keep track of callback to be able to stop the pulse
+ DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1];
+ doAnswer(invocation -> {
+ pulseCallback[0] = invocation.getArgument(0);
+ return null;
+ }).when(mDozeScrimController).pulse(any(), anyInt());
+ // Starting a pulse should change the scrim controller to the pulsing state
+ mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class),
+ DozeLog.PULSE_REASON_NOTIFICATION);
+ verify(mScrimController).transitionTo(eq(ScrimState.PULSING), any());
+
+ // Ending a pulse should take it back to keyguard state
+ pulseCallback[0].onPulseFinished();
+ verify(mScrimController).transitionTo(eq(ScrimState.KEYGUARD));
+ }
+
+ @Test
public void testSetState_changesIsFullScreenUserSwitcherState() {
mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
assertFalse(mStatusBar.isFullScreenUserSwitcherState());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
index dcd531dc9eb7..090963be7ac7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -15,6 +15,7 @@
package com.android.systemui.statusbar.phone;
import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -35,7 +36,7 @@ import org.mockito.ArgumentCaptor;
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
+@RunWithLooper
@SmallTest
public class SystemUIDialogTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 3164c0469c40..b3ac6be65d36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -32,9 +32,10 @@ import android.widget.ImageButton;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationTestHelper;
import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.util.Assert;
import org.junit.After;
import org.junit.Before;
@@ -44,7 +45,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
@SmallTest
public class RemoteInputViewTest extends SysuiTestCase {
@@ -60,6 +61,7 @@ public class RemoteInputViewTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
MockitoAnnotations.initMocks(this);
mDependency.injectTestDependency(RemoteInputQuickSettingsDisabler.class,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index df7aeab2ed38..506fa974944a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -801,4 +801,55 @@ public class SmartReplyViewTest extends SysuiTestCase {
assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2));
}
+
+ @Test
+ public void testMeasure_choicesAndActionsPrioritizeActionsOnlyActions() {
+ String[] choices = new String[] {"Reply"};
+ String[] actions = new String[] {"Looooooong actioooon", "second action", "third action"};
+
+ // All actions should be displayed as DOUBLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(new String[0], 2,
+ createActions(new String[] {
+ "Looooooong \nactioooon", "second \naction", "third \naction"}));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setSmartRepliesAndActions(choices, actions);
+ mView.measure(
+ MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ // smart replies
+ assertReplyButtonHidden(mView.getChildAt(0));
+ // smart actions
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3));
+ }
+
+ @Test
+ public void testMeasure_choicesAndActionsPrioritizeActions() {
+ String[] choices = new String[] {"Short", "longer reply"};
+ String[] actions = new String[] {"Looooooong actioooon", "second action"};
+
+ // All actions should be displayed as DOUBLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(new String[] {"Short"}, 2,
+ createActions(new String[] {"Looooooong \nactioooon", "second \naction"}));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setSmartRepliesAndActions(choices, actions);
+ mView.measure(
+ MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.UNSPECIFIED);
+
+ Button firstAction = ((Button) mView.getChildAt(1));
+
+ assertEqualMeasures(expectedView, mView);
+ // smart replies
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonHidden(mView.getChildAt(1));
+ // smart actions
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
index 43942f72993e..ab9b0c979fd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
@@ -20,11 +20,13 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.animation.Animator;
+import android.os.Looper;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -33,7 +35,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@TestableLooper.RunWithLooper
@RunWith(AndroidTestingRunner.class)
public class KeepAwakeAnimationListenerTest extends SysuiTestCase {
@Mock WakeLock mWakeLock;
@@ -41,6 +43,7 @@ public class KeepAwakeAnimationListenerTest extends SysuiTestCase {
@Before
public void setup() {
+ Assert.sMainLooper = TestableLooper.get(this).getLooper();
MockitoAnnotations.initMocks(this);
KeepAwakeAnimationListener.sWakeLock = mWakeLock;
mKeepAwakeAnimationListener = new KeepAwakeAnimationListener(getContext());
@@ -55,4 +58,10 @@ public class KeepAwakeAnimationListenerTest extends SysuiTestCase {
mKeepAwakeAnimationListener.onAnimationEnd((Animator) null);
verify(mWakeLock).release();
}
+
+ @Test(expected = IllegalStateException.class)
+ public void initThrows_onNonMainThread() {
+ Assert.sMainLooper = Looper.getMainLooper();
+ new KeepAwakeAnimationListener(getContext());
+ }
}
diff --git a/packages/overlays/AccentColorBlackOverlay/Android.mk b/packages/overlays/AccentColorBlackOverlay/Android.mk
new file mode 100644
index 000000000000..d316fbd8907c
--- /dev/null
+++ b/packages/overlays/AccentColorBlackOverlay/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright 2018, 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := AccentColorBlack
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := AccentColorBlackOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/AccentColorBlackOverlay/AndroidManifest.xml b/packages/overlays/AccentColorBlackOverlay/AndroidManifest.xml
new file mode 100644
index 000000000000..3b99648d20aa
--- /dev/null
+++ b/packages/overlays/AccentColorBlackOverlay/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<!--
+/**
+ * Copyright (c) 2018, 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.color.black"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android" android:category="android.theme.customization.accent_color" android:priority="1"/>
+
+ <application android:label="@string/accent_color_black_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/AccentColorBlackOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorBlackOverlay/res/values/colors_device_defaults.xml
new file mode 100644
index 000000000000..5648f915490b
--- /dev/null
+++ b/packages/overlays/AccentColorBlackOverlay/res/values/colors_device_defaults.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <color name="accent_device_default_light">#202020</color>
+ <color name="accent_device_default_dark">#FFFFFF</color>
+</resources>
diff --git a/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml b/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml
new file mode 100644
index 000000000000..baf09b11ac07
--- /dev/null
+++ b/packages/overlays/AccentColorBlackOverlay/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Black accent color name application label. [CHAR LIMIT=50] -->
+ <string name="accent_color_black_overlay" translatable="false">Black Accent Color</string>
+</resources>
+
diff --git a/packages/overlays/AccentColorGreenOverlay/Android.mk b/packages/overlays/AccentColorGreenOverlay/Android.mk
new file mode 100644
index 000000000000..afc42873a4d6
--- /dev/null
+++ b/packages/overlays/AccentColorGreenOverlay/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright 2018, 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := AccentColorGreen
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := AccentColorGreenOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/AccentColorGreenOverlay/AndroidManifest.xml b/packages/overlays/AccentColorGreenOverlay/AndroidManifest.xml
new file mode 100644
index 000000000000..609d5be8a758
--- /dev/null
+++ b/packages/overlays/AccentColorGreenOverlay/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<!--
+/**
+ * Copyright (c) 2018, 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.color.green"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android" android:category="android.theme.customization.accent_color" android:priority="1"/>
+
+ <application android:label="@string/accent_color_green_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/AccentColorGreenOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorGreenOverlay/res/values/colors_device_defaults.xml
new file mode 100644
index 000000000000..089f08c6bb19
--- /dev/null
+++ b/packages/overlays/AccentColorGreenOverlay/res/values/colors_device_defaults.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <color name="accent_device_default_light">#1B873B</color>
+ <color name="accent_device_default_dark">#84C188</color>
+</resources>
diff --git a/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml b/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml
new file mode 100644
index 000000000000..4de344cbb65e
--- /dev/null
+++ b/packages/overlays/AccentColorGreenOverlay/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Green accent color name application label. [CHAR LIMIT=50] -->
+ <string name="accent_color_green_overlay" translatable="false">Green Accent Color</string>
+</resources>
+
diff --git a/packages/overlays/AccentColorPurpleOverlay/Android.mk b/packages/overlays/AccentColorPurpleOverlay/Android.mk
new file mode 100644
index 000000000000..336616921d71
--- /dev/null
+++ b/packages/overlays/AccentColorPurpleOverlay/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright 2018, 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := AccentColorPurple
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := AccentColorPurpleOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/AccentColorPurpleOverlay/AndroidManifest.xml b/packages/overlays/AccentColorPurpleOverlay/AndroidManifest.xml
new file mode 100644
index 000000000000..497a35815554
--- /dev/null
+++ b/packages/overlays/AccentColorPurpleOverlay/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<!--
+/**
+ * Copyright (c) 2018, 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.color.purple"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android" android:category="android.theme.customization.accent_color" android:priority="1"/>
+
+ <application android:label="@string/accent_color_purple_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/AccentColorPurpleOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorPurpleOverlay/res/values/colors_device_defaults.xml
new file mode 100644
index 000000000000..7e34bac3d9fb
--- /dev/null
+++ b/packages/overlays/AccentColorPurpleOverlay/res/values/colors_device_defaults.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <color name="accent_device_default_light">#725AFF</color>
+ <color name="accent_device_default_dark">#B5A9FC</color>
+</resources>
diff --git a/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml b/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml
new file mode 100644
index 000000000000..d1eb95a940ac
--- /dev/null
+++ b/packages/overlays/AccentColorPurpleOverlay/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Purple accent color name application label. [CHAR LIMIT=50] -->
+ <string name="accent_color_purple_overlay" translatable="false">Purple Accent Color</string>
+</resources>
+
diff --git a/packages/overlays/AdaptiveIconChangeOverlay/Android.mk b/packages/overlays/AdaptiveIconChangeOverlay/Android.mk
new file mode 100644
index 000000000000..6e3b8cbbcf2f
--- /dev/null
+++ b/packages/overlays/AdaptiveIconChangeOverlay/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright 2018, 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := SquareIcon
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := SquareIconOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/AdaptiveIconChangeOverlay/AndroidManifest.xml b/packages/overlays/AdaptiveIconChangeOverlay/AndroidManifest.xml
new file mode 100644
index 000000000000..33da51047bf0
--- /dev/null
+++ b/packages/overlays/AdaptiveIconChangeOverlay/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<!--
+/**
+ * Copyright (c) 2018, 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.icon.square"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android"
+ android:category="android.theme.customization.adaptive_icon_shape"
+ android:priority="1"/>
+
+ <application android:label="@string/square_icon_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/SystemUI/res/values/arrays_car.xml b/packages/overlays/AdaptiveIconChangeOverlay/res/values/config.xml
index 8c760fc45e72..54623f5c9fb0 100644
--- a/packages/SystemUI/res/values/arrays_car.xml
+++ b/packages/overlays/AdaptiveIconChangeOverlay/res/values/config.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-**
-** Copyright 2015, The Android Open Source Project
+/*
+** Copyright 2018, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -16,15 +16,11 @@
** limitations under the License.
*/
-->
-<resources>
- <!-- These should be overriden in an overlay. The default implementation is empty.
- There needs to be correspondence per index between these arrays, which means that if there
- isn't a longpress action associated with a shortcut item, put in an empty item to make
- sure everything lines up.
- -->
- <array name="car_facet_icons" />
- <array name="car_facet_intent_uris" />
- <array name="car_facet_longpress_intent_uris" />
- <array name="car_facet_package_filters"/>
- <array name="car_facet_category_filters"/>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
+ <string name="config_icon_mask" translatable="false">"M50,0L100,0 100,100 0,100 0,0z"</string>
+ <!-- Flag indicating whether round icons should be parsed from the application manifest. -->
+ <bool name="config_useRoundIcon">false</bool>
+
</resources>
+
diff --git a/packages/overlays/AdaptiveIconChangeOverlay/res/values/strings.xml b/packages/overlays/AdaptiveIconChangeOverlay/res/values/strings.xml
new file mode 100644
index 000000000000..64b7d0dc16b5
--- /dev/null
+++ b/packages/overlays/AdaptiveIconChangeOverlay/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Square icon overlay [DO NOT TRANSLATE] -->
+ <string name="square_icon_overlay">Square Icons</string>
+
+</resources>
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 0da07ae52857..944ee3390150 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -70,10 +70,10 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
-import com.android.server.AbstractMasterSystemService;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.autofill.ui.AutoFillUI;
+import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.intelligence.IntelligenceManagerInternal;
import java.io.FileDescriptor;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 0df99d4b6642..1f229cd2a157 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -70,11 +70,11 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.server.AbstractPerUserSystemService;
import com.android.server.LocalServices;
import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
import com.android.server.autofill.AutofillManagerService.SmartSuggestionMode;
import com.android.server.autofill.ui.AutoFillUI;
+import com.android.server.infra.AbstractPerUserSystemService;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -190,6 +190,11 @@ final class AutofillManagerServiceImpl
return mInfo.getServiceInfo();
}
+ @Override // from PerUserSystemService
+ protected String getDefaultComponentName() {
+ return getComponentNameFromSettings();
+ }
+
@Nullable
String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) {
return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
@@ -369,7 +374,7 @@ final class AutofillManagerServiceImpl
final long identity = Binder.clearCallingIdentity();
try {
- final String autoFillService = getComponentNameFromSettings();
+ final String autoFillService = getComponentNameLocked();
final ComponentName componentName = serviceInfo.getComponentName();
if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) {
mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF,
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index af6575954842..4b7d29025730 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -40,7 +40,7 @@ import android.service.autofill.SaveRequest;
import android.text.format.DateUtils;
import android.util.Slog;
-import com.android.server.AbstractSinglePendingRequestRemoteService;
+import com.android.server.infra.AbstractSinglePendingRequestRemoteService;
final class RemoteFillService extends AbstractSinglePendingRequestRemoteService<RemoteFillService> {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4c645076eb95..fb64cb28619d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -95,10 +95,10 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
-import com.android.server.AbstractRemoteService;
import com.android.server.autofill.AutofillManagerService.SmartSuggestionMode;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.autofill.ui.PendingUi;
+import com.android.server.infra.AbstractRemoteService;
import com.android.server.intelligence.IntelligenceManagerInternal;
import com.android.server.intelligence.IntelligenceManagerInternal.AugmentedAutofillCallback;
@@ -2579,11 +2579,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
+ " when server returned null for session " + this.id);
}
+ final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue();
+
// TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
// furgher AFM -> AFMS calls.
// TODO(b/119638958): add CTS tests
return intelligenceManagerInternal.requestAutofill(mService.getUserId(), mClient,
- mActivityToken, this.id, mCurrentViewId);
+ mActivityToken, this.id, mCurrentViewId, currentValue);
}
@GuardedBy("mLock")
diff --git a/services/backup/java/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKey.java b/services/backup/java/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKey.java
new file mode 100644
index 000000000000..f356b4f102e2
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKey.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2018 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.backup.encryption.keys;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.RecoveryController;
+import android.util.Slog;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Wraps a {@link RecoveryController}'s {@link SecretKey}. These are kept in "AndroidKeyStore" (a
+ * provider for {@link java.security.KeyStore} and {@link javax.crypto.KeyGenerator}. They are also
+ * synced with the recoverable key store, wrapped by the primary key. This allows them to be
+ * recovered on a user's subsequent device through providing their lock screen secret.
+ */
+public class RecoverableKeyStoreSecondaryKey {
+ private static final String TAG = "RecoverableKeyStoreSecondaryKey";
+
+ private final String mAlias;
+ private final SecretKey mSecretKey;
+
+ /**
+ * A new instance.
+ *
+ * @param alias The alias. It is keyed with this in AndroidKeyStore and the recoverable key
+ * store.
+ * @param secretKey The key.
+ */
+ public RecoverableKeyStoreSecondaryKey(String alias, SecretKey secretKey) {
+ mAlias = checkNotNull(alias);
+ mSecretKey = checkNotNull(secretKey);
+ }
+
+ /**
+ * The ID, as stored in the recoverable {@link java.security.KeyStore}, and as used to identify
+ * wrapped tertiary keys on the backup server.
+ */
+ public String getAlias() {
+ return mAlias;
+ }
+
+ /** The secret key, to be used to wrap tertiary keys. */
+ public SecretKey getSecretKey() {
+ return mSecretKey;
+ }
+
+ /**
+ * The status of the key. i.e., whether it's been synced to remote trusted hardware.
+ *
+ * @param context The application context.
+ * @return One of {@link Status#SYNCED}, {@link Status#NOT_SYNCED} or {@link Status#DESTROYED}.
+ */
+ public @Status int getStatus(Context context) {
+ try {
+ return getStatusInternal(context);
+ } catch (InternalRecoveryServiceException e) {
+ Slog.wtf(TAG, "Internal error getting recovery status", e);
+ // Return NOT_SYNCED by default, as we do not want the backups to fail or to repeatedly
+ // attempt to reinitialize.
+ return Status.NOT_SYNCED;
+ }
+ }
+
+ private @Status int getStatusInternal(Context context) throws InternalRecoveryServiceException {
+ int status = RecoveryController.getInstance(context).getRecoveryStatus(mAlias);
+ switch (status) {
+ case RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE:
+ return Status.DESTROYED;
+ case RecoveryController.RECOVERY_STATUS_SYNCED:
+ return Status.SYNCED;
+ case RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS:
+ return Status.NOT_SYNCED;
+ default:
+ // Throw an exception if we encounter a status that doesn't match any of the above.
+ throw new InternalRecoveryServiceException(
+ "Unexpected status from getRecoveryStatus: " + status);
+ }
+ }
+
+ /** Status of a key in the recoverable key store. */
+ @IntDef({Status.NOT_SYNCED, Status.SYNCED, Status.DESTROYED})
+ public @interface Status {
+ /**
+ * The key has not yet been synced to remote trusted hardware. This may be because the user
+ * has not yet unlocked their device.
+ */
+ int NOT_SYNCED = 1;
+
+ /**
+ * The key has been synced with remote trusted hardware. It should now be recoverable on
+ * another device.
+ */
+ int SYNCED = 2;
+
+ /** The key has been lost forever. This can occur if the user disables their lock screen. */
+ int DESTROYED = 3;
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManager.java b/services/backup/java/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManager.java
new file mode 100644
index 000000000000..db5fe77478a5
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManager.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2018 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.backup.encryption.keys;
+
+import android.content.Context;
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.LockScreenRequiredException;
+import android.security.keystore.recovery.RecoveryController;
+import android.util.ByteStringUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.util.Optional;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Manages generating, deleting, and retrieving secondary keys through {@link RecoveryController}.
+ *
+ * <p>The recoverable key store will be synced remotely via the {@link RecoveryController}, allowing
+ * recovery of keys on other devices owned by the user.
+ */
+public class RecoverableKeyStoreSecondaryKeyManager {
+ private static final String BACKUP_KEY_ALIAS_PREFIX =
+ "com.android.server.backup/recoverablekeystore/";
+ private static final int BACKUP_KEY_SUFFIX_LENGTH_BITS = 128;
+ private static final int BITS_PER_BYTE = 8;
+
+ /** A new instance. */
+ public static RecoverableKeyStoreSecondaryKeyManager getInstance(Context context) {
+ return new RecoverableKeyStoreSecondaryKeyManager(
+ RecoveryController.getInstance(context), new SecureRandom());
+ }
+
+ private final RecoveryController mRecoveryController;
+ private final SecureRandom mSecureRandom;
+
+ @VisibleForTesting
+ public RecoverableKeyStoreSecondaryKeyManager(
+ RecoveryController recoveryController, SecureRandom secureRandom) {
+ mRecoveryController = recoveryController;
+ mSecureRandom = secureRandom;
+ }
+
+ /**
+ * Generates a new recoverable key using the {@link RecoveryController}.
+ *
+ * @throws InternalRecoveryServiceException if an unexpected error occurred generating the key.
+ * @throws LockScreenRequiredException if the user does not have a lock screen. A lock screen is
+ * required to generate a recoverable key.
+ */
+ public RecoverableKeyStoreSecondaryKey generate()
+ throws InternalRecoveryServiceException, LockScreenRequiredException,
+ UnrecoverableKeyException {
+ String alias = generateId();
+ mRecoveryController.generateKey(alias);
+ SecretKey key = (SecretKey) mRecoveryController.getKey(alias);
+ if (key == null) {
+ throw new InternalRecoveryServiceException(
+ String.format(
+ "Generated key %s but could not get it back immediately afterwards.",
+ alias));
+ }
+ return new RecoverableKeyStoreSecondaryKey(alias, key);
+ }
+
+ /**
+ * Removes the secondary key. This means the key will no longer be recoverable.
+ *
+ * @param alias The alias of the key.
+ * @throws InternalRecoveryServiceException if there was a {@link RecoveryController} error.
+ */
+ public void remove(String alias) throws InternalRecoveryServiceException {
+ mRecoveryController.removeKey(alias);
+ }
+
+ /**
+ * Returns the {@link RecoverableKeyStoreSecondaryKey} with {@code alias} if it is in the {@link
+ * RecoveryController}. Otherwise, {@link Optional#empty()}.
+ */
+ public Optional<RecoverableKeyStoreSecondaryKey> get(String alias)
+ throws InternalRecoveryServiceException, UnrecoverableKeyException {
+ SecretKey secretKey = (SecretKey) mRecoveryController.getKey(alias);
+ return Optional.ofNullable(secretKey)
+ .map(key -> new RecoverableKeyStoreSecondaryKey(alias, key));
+ }
+
+ /**
+ * Generates a new key alias. This has more entropy than a UUID - it can be considered
+ * universally unique.
+ */
+ private String generateId() {
+ byte[] id = new byte[BACKUP_KEY_SUFFIX_LENGTH_BITS / BITS_PER_BYTE];
+ mSecureRandom.nextBytes(id);
+ return BACKUP_KEY_ALIAS_PREFIX + ByteStringUtils.toHexString(id);
+ }
+
+ /** Constructs a {@link RecoverableKeyStoreSecondaryKeyManager}. */
+ public interface RecoverableKeyStoreSecondaryKeyManagerProvider {
+ /** Returns a newly constructed {@link RecoverableKeyStoreSecondaryKeyManager}. */
+ RecoverableKeyStoreSecondaryKeyManager get();
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyGenerator.java b/services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyGenerator.java
new file mode 100644
index 000000000000..ebf09dfd6ba6
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyGenerator.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 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.backup.encryption.keys;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+/** 256-bit AES key generator. Each app should have its own separate AES key. */
+public class TertiaryKeyGenerator {
+ private static final int KEY_SIZE_BITS = 256;
+ private static final String KEY_ALGORITHM = "AES";
+
+ private final KeyGenerator mKeyGenerator;
+
+ /** New instance generating keys using {@code secureRandom}. */
+ public TertiaryKeyGenerator(SecureRandom secureRandom) {
+ try {
+ mKeyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
+ mKeyGenerator.init(KEY_SIZE_BITS, secureRandom);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(
+ "Impossible condition: JCE thinks it does not support AES.", e);
+ }
+ }
+
+ /** Generates a new random AES key. */
+ public SecretKey generate() {
+ return mKeyGenerator.generateKey();
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyRotationTracker.java b/services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyRotationTracker.java
new file mode 100644
index 000000000000..ec90f6c8c95e
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyRotationTracker.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 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.backup.encryption.keys;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Locale;
+
+/**
+ * Tracks when a tertiary key rotation is due.
+ *
+ * <p>After a certain number of incremental backups, the device schedules a full backup, which will
+ * generate a new encryption key, effecting a key rotation. We should do this on a regular basis so
+ * that if a key does become compromised it has limited value to the attacker.
+ *
+ * <p>No additional synchronization of this class is provided. Only one instance should be used at
+ * any time. This should be fine as there should be no parallelism in backups.
+ */
+public class TertiaryKeyRotationTracker {
+ private static final int MAX_BACKUPS_UNTIL_TERTIARY_KEY_ROTATION = 31;
+ private static final String SHARED_PREFERENCES_NAME = "tertiary_key_rotation_tracker";
+
+ private static final String TAG = "TertiaryKeyRotationTracker";
+ private static final boolean DEBUG = false;
+
+ /**
+ * A new instance, using {@code context} to commit data to disk via {@link SharedPreferences}.
+ */
+ public static TertiaryKeyRotationTracker getInstance(Context context) {
+ return new TertiaryKeyRotationTracker(
+ context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE));
+ }
+
+ private final SharedPreferences mSharedPreferences;
+
+ /** New instance, storing data in {@code mSharedPreferences}. */
+ @VisibleForTesting
+ TertiaryKeyRotationTracker(SharedPreferences sharedPreferences) {
+ mSharedPreferences = sharedPreferences;
+ }
+
+ /**
+ * Returns {@code true} if the given app is due having its key rotated.
+ *
+ * @param packageName The package name of the app.
+ */
+ public boolean isKeyRotationDue(String packageName) {
+ return getBackupsSinceRotation(packageName) >= MAX_BACKUPS_UNTIL_TERTIARY_KEY_ROTATION;
+ }
+
+ /**
+ * Records that an incremental backup has occurred. Each incremental backup brings the app
+ * closer to the time when its key should be rotated.
+ *
+ * @param packageName The package name of the app for which the backup occurred.
+ */
+ public void recordBackup(String packageName) {
+ int backupsSinceRotation = getBackupsSinceRotation(packageName) + 1;
+ mSharedPreferences.edit().putInt(packageName, backupsSinceRotation).apply();
+ if (DEBUG) {
+ Slog.d(
+ TAG,
+ String.format(
+ Locale.US,
+ "Incremental backup for %s. %d backups until key rotation.",
+ packageName,
+ Math.max(
+ 0,
+ MAX_BACKUPS_UNTIL_TERTIARY_KEY_ROTATION
+ - backupsSinceRotation)));
+ }
+ }
+
+ /**
+ * Resets the rotation delay for the given app. Should be invoked after a key rotation.
+ *
+ * @param packageName Package name of the app whose key has rotated.
+ */
+ public void resetCountdown(String packageName) {
+ mSharedPreferences.edit().putInt(packageName, 0).apply();
+ }
+
+ /** Marks all enrolled packages for key rotation. */
+ public void markAllForRotation() {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ for (String packageName : mSharedPreferences.getAll().keySet()) {
+ editor.putInt(packageName, MAX_BACKUPS_UNTIL_TERTIARY_KEY_ROTATION);
+ }
+ editor.apply();
+ }
+
+ private int getBackupsSinceRotation(String packageName) {
+ return mSharedPreferences.getInt(packageName, 0);
+ }
+}
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index 01716a0ea40a..11a2fc9c1e45 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -16,23 +16,33 @@
package com.android.server;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+
import android.app.AppGlobals;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.os.ThreadLocalWorkSource;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BinderCallsStats;
+import com.android.internal.os.BinderInternal;
+import com.android.internal.os.BinderInternal.CallSession;
import com.android.internal.os.CachedDeviceState;
import java.io.FileDescriptor;
@@ -49,6 +59,106 @@ public class BinderCallsStatsService extends Binder {
private static final String PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING
= "persist.sys.binder_calls_detailed_tracking";
+ /** Resolves the work source of an incoming binder transaction. */
+ static class WorkSourceProvider {
+ private ArraySet<Integer> mAppIdWhitelist;
+
+ WorkSourceProvider() {
+ mAppIdWhitelist = new ArraySet<>();
+ }
+
+ public int resolveWorkSourceUid() {
+ final int callingUid = getCallingUid();
+ final int appId = UserHandle.getAppId(callingUid);
+ if (mAppIdWhitelist.contains(appId)) {
+ final int workSource = getCallingWorkSourceUid();
+ final boolean isWorkSourceSet = workSource != Binder.UNSET_WORKSOURCE;
+ return isWorkSourceSet ? workSource : callingUid;
+ }
+ return callingUid;
+ }
+
+ public void systemReady(Context context) {
+ mAppIdWhitelist = createAppidWhitelist(context);
+ }
+
+ public void dump(PrintWriter pw, Map<Integer, String> appIdToPackageName) {
+ pw.println("AppIds of apps that can set the work source:");
+ final ArraySet<Integer> whitelist = mAppIdWhitelist;
+ for (Integer appId : whitelist) {
+ pw.println("\t- " + appIdToPackageName.getOrDefault(appId, String.valueOf(appId)));
+ }
+ }
+
+ protected int getCallingUid() {
+ return Binder.getCallingUid();
+ }
+
+ protected int getCallingWorkSourceUid() {
+ return Binder.getCallingWorkSourceUid();
+ }
+
+ private ArraySet<Integer> createAppidWhitelist(Context context) {
+ // Use a local copy instead of mAppIdWhitelist to prevent concurrent read access.
+ final ArraySet<Integer> whitelist = new ArraySet<>();
+
+ // We trust our own process.
+ whitelist.add(Process.myUid());
+ // We only need to initialize it once. UPDATE_DEVICE_STATS is a system permission.
+ final PackageManager pm = context.getPackageManager();
+ final String[] permissions = { android.Manifest.permission.UPDATE_DEVICE_STATS };
+ final int queryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
+ final List<PackageInfo> packages =
+ pm.getPackagesHoldingPermissions(permissions, queryFlags);
+ final int packagesSize = packages.size();
+ for (int i = 0; i < packagesSize; i++) {
+ final PackageInfo pkgInfo = packages.get(i);
+ try {
+ final int uid = pm.getPackageUid(pkgInfo.packageName, queryFlags);
+ final int appId = UserHandle.getAppId(uid);
+ whitelist.add(appId);
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Cannot find uid for package name " + pkgInfo.packageName, e);
+ }
+ }
+ return whitelist;
+ }
+ }
+
+ /** Observer for all system server incoming binder transactions. */
+ @VisibleForTesting
+ static class BinderCallsObserver implements BinderInternal.Observer {
+ private final BinderInternal.Observer mBinderCallsStats;
+ private final WorkSourceProvider mWorkSourceProvider;
+
+ BinderCallsObserver(BinderInternal.Observer callsStats,
+ WorkSourceProvider workSourceProvider) {
+ mBinderCallsStats = callsStats;
+ mWorkSourceProvider = workSourceProvider;
+ }
+
+ @Override
+ public CallSession callStarted(Binder binder, int code) {
+ // We depend on the code in Binder#execTransact to reset the state of
+ // ThreadLocalWorkSource
+ setThreadLocalWorkSourceUid(mWorkSourceProvider.resolveWorkSourceUid());
+ return mBinderCallsStats.callStarted(binder, code);
+ }
+
+ @Override
+ public void callEnded(CallSession s, int parcelRequestSize, int parcelReplySize) {
+ mBinderCallsStats.callEnded(s, parcelRequestSize, parcelReplySize);
+ }
+
+ @Override
+ public void callThrewException(CallSession s, Exception exception) {
+ mBinderCallsStats.callThrewException(s, exception);
+ }
+
+ protected void setThreadLocalWorkSourceUid(int uid) {
+ ThreadLocalWorkSource.setUid(uid);
+ }
+ }
/** Listens for flag changes. */
private static class SettingsObserver extends ContentObserver {
@@ -63,13 +173,16 @@ public class BinderCallsStatsService extends Binder {
private final Context mContext;
private final KeyValueListParser mParser = new KeyValueListParser(',');
private final BinderCallsStats mBinderCallsStats;
+ private final BinderCallsObserver mBinderCallsObserver;
- public SettingsObserver(Context context, BinderCallsStats binderCallsStats) {
+ SettingsObserver(Context context, BinderCallsStats binderCallsStats,
+ BinderCallsObserver observer) {
super(BackgroundThread.getHandler());
mContext = context;
context.getContentResolver().registerContentObserver(mUri, false, this,
UserHandle.USER_SYSTEM);
mBinderCallsStats = binderCallsStats;
+ mBinderCallsObserver = observer;
// Always kick once to ensure that we match current state
onChange();
}
@@ -107,7 +220,7 @@ public class BinderCallsStatsService extends Binder {
mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT);
if (mEnabled != enabled) {
if (enabled) {
- Binder.setObserver(mBinderCallsStats);
+ Binder.setObserver(mBinderCallsObserver);
Binder.setProxyTransactListener(
new Binder.PropagateWorkSourceTransactListener());
} else {
@@ -116,6 +229,7 @@ public class BinderCallsStatsService extends Binder {
}
mEnabled = enabled;
mBinderCallsStats.reset();
+ mBinderCallsStats.setAddDebugEntries(enabled);
}
}
}
@@ -154,6 +268,7 @@ public class BinderCallsStatsService extends Binder {
public static class LifeCycle extends SystemService {
private BinderCallsStatsService mService;
private BinderCallsStats mBinderCallsStats;
+ private WorkSourceProvider mWorkSourceProvider;
public LifeCycle(Context context) {
super(context);
@@ -162,7 +277,11 @@ public class BinderCallsStatsService extends Binder {
@Override
public void onStart() {
mBinderCallsStats = new BinderCallsStats(new BinderCallsStats.Injector());
- mService = new BinderCallsStatsService(mBinderCallsStats);
+ mWorkSourceProvider = new WorkSourceProvider();
+ BinderCallsObserver binderCallsObserver =
+ new BinderCallsObserver(mBinderCallsStats, mWorkSourceProvider);
+ mService = new BinderCallsStatsService(
+ mBinderCallsStats, binderCallsObserver, mWorkSourceProvider);
publishLocalService(Internal.class, new Internal(mBinderCallsStats));
publishBinderService("binder_calls_stats", mService);
boolean detailedTrackingEnabled = SystemProperties.getBoolean(
@@ -181,21 +300,29 @@ public class BinderCallsStatsService extends Binder {
if (SystemService.PHASE_SYSTEM_SERVICES_READY == phase) {
CachedDeviceState.Readonly deviceState = getLocalService(
CachedDeviceState.Readonly.class);
- mService.systemReady(getContext());
mBinderCallsStats.setDeviceState(deviceState);
+ // It needs to be called before mService.systemReady to make sure the observer is
+ // initialized before installing it.
+ mWorkSourceProvider.systemReady(getContext());
+ mService.systemReady(getContext());
}
}
}
private SettingsObserver mSettingsObserver;
private final BinderCallsStats mBinderCallsStats;
+ private final BinderCallsObserver mBinderCallsObserver;
+ private final WorkSourceProvider mWorkSourceProvider;
- BinderCallsStatsService(BinderCallsStats binderCallsStats) {
+ BinderCallsStatsService(BinderCallsStats binderCallsStats, BinderCallsObserver observer,
+ WorkSourceProvider workSourceProvider) {
mBinderCallsStats = binderCallsStats;
+ mBinderCallsObserver = observer;
+ mWorkSourceProvider = workSourceProvider;
}
public void systemReady(Context context) {
- mSettingsObserver = new SettingsObserver(context, mBinderCallsStats);
+ mSettingsObserver = new SettingsObserver(context, mBinderCallsStats, mBinderCallsObserver);
}
public void reset() {
@@ -215,7 +342,7 @@ public class BinderCallsStatsService extends Binder {
pw.println("binder_calls_stats reset.");
return;
} else if ("--enable".equals(arg)) {
- Binder.setObserver(mBinderCallsStats);
+ Binder.setObserver(mBinderCallsObserver);
return;
} else if ("--disable".equals(arg)) {
Binder.setObserver(null);
@@ -233,6 +360,9 @@ public class BinderCallsStatsService extends Binder {
mBinderCallsStats.setDetailedTracking(false);
pw.println("Detailed tracking disabled");
return;
+ } else if ("--dump-worksource-provider".equals(arg)) {
+ mWorkSourceProvider.dump(pw, getAppIdToPackagesMap());
+ return;
} else if ("-h".equals(arg)) {
pw.println("binder_calls_stats commands:");
pw.println(" --reset: Reset stats");
@@ -271,5 +401,4 @@ public class BinderCallsStatsService extends Binder {
}
return map;
}
-
}
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 7ee3d3b3bdc7..126bf6556538 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -1236,7 +1236,8 @@ public class IpSecService extends IIpSecService.Stub {
OsConstants.UDP_ENCAP,
OsConstants.UDP_ENCAP_ESPINUDP);
- mSrvConfig.getNetdInstance().ipSecSetEncapSocketOwner(sockFd, callingUid);
+ mSrvConfig.getNetdInstance().ipSecSetEncapSocketOwner(
+ new ParcelFileDescriptor(sockFd), callingUid);
if (port != 0) {
Log.v(TAG, "Binding to port " + port);
Os.bind(sockFd, INADDR_ANY, port);
@@ -1696,7 +1697,7 @@ public class IpSecService extends IIpSecService.Stub {
mSrvConfig
.getNetdInstance()
.ipSecApplyTransportModeTransform(
- socket.getFileDescriptor(),
+ socket,
callingUid,
direction,
c.getSourceAddress(),
@@ -1715,7 +1716,7 @@ public class IpSecService extends IIpSecService.Stub {
throws RemoteException {
mSrvConfig
.getNetdInstance()
- .ipSecRemoveTransportModeTransform(socket.getFileDescriptor());
+ .ipSecRemoveTransportModeTransform(socket);
}
/**
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index c563ad224da6..fa3babad639d 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -94,6 +94,8 @@ public class LooperStatsService extends Binder {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
pw.print("Start time: ");
pw.println(DateFormat.format("yyyy-MM-dd HH:mm:ss", mStats.getStartTimeMillis()));
+ pw.print("On battery time (ms): ");
+ pw.println(mStats.getBatteryTimeMillis());
final List<LooperStats.ExportedEntry> entries = mStats.getEntries();
entries.sort(Comparator
.comparing((LooperStats.ExportedEntry entry) -> entry.workSourceUid)
diff --git a/services/core/java/com/android/server/RuntimeService.java b/services/core/java/com/android/server/RuntimeService.java
index ccfac80d22a7..bb39ccc52af2 100644
--- a/services/core/java/com/android/server/RuntimeService.java
+++ b/services/core/java/com/android/server/RuntimeService.java
@@ -94,7 +94,7 @@ public class RuntimeService extends Binder {
// Add /data tz data set using the DistroVersion class (which libcore cannot use).
// This update mechanism will be removed after the time zone APEX is launched so this
// untidiness will disappear with it.
- String debugKeyPrefix = "core_library.timezone.data_";
+ String debugKeyPrefix = "core_library.timezone.source.data_";
String versionFileName = TimeZoneDataFiles.getDataTimeZoneFile(
TimeZoneDistro.DISTRO_VERSION_FILE_NAME);
addDistroVersionDebugInfo(versionFileName, debugKeyPrefix, coreLibraryDebugInfo);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 390126c63ab8..dbea529b72fe 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT;
import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT;
@@ -2758,6 +2760,14 @@ class StorageManagerService extends IStorageManager.Stub
public @Nullable ParcelFileDescriptor openProxyFileDescriptor(
int mountId, int fileId, int mode) {
Slog.v(TAG, "mountProxyFileDescriptor");
+
+ // We only support a narrow set of incoming mode flags
+ if ((mode & MODE_READ_WRITE) == MODE_READ_WRITE) {
+ mode = MODE_READ_WRITE;
+ } else {
+ mode = MODE_READ_ONLY;
+ }
+
try {
synchronized (mAppFuseLock) {
if (mAppFuseBridge == null) {
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
index 8cd9d1881639..15de3def913a 100644
--- a/services/core/java/com/android/server/am/ActiveInstrumentation.java
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -133,7 +133,7 @@ class ActiveInstrumentation {
proto.write(ActiveInstrumentationProto.TARGET_PROCESSES, p);
}
if (mTargetInfo != null) {
- mTargetInfo.writeToProto(proto, ActiveInstrumentationProto.TARGET_INFO);
+ mTargetInfo.writeToProto(proto, ActiveInstrumentationProto.TARGET_INFO, 0);
}
proto.write(ActiveInstrumentationProto.PROFILE_FILE, mProfileFile);
proto.write(ActiveInstrumentationProto.WATCHER, mWatcher.toString());
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a19e9287aa6c..23287cf399ca 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1801,16 +1801,25 @@ public final class ActiveServices {
for (int i = clist.size() - 1; i >= 0; i--) {
final ConnectionRecord crec = clist.get(i);
final ServiceRecord srec = crec.binding.service;
- if (srec != null && srec.app != null
- && (srec.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
- if (group > 0) {
- srec.app.connectionService = srec;
- srec.app.connectionGroup = group;
- srec.app.connectionImportance = importance;
+ if (srec != null && (srec.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
+ if (srec.app != null) {
+ if (group > 0) {
+ srec.app.connectionService = srec;
+ srec.app.connectionGroup = group;
+ srec.app.connectionImportance = importance;
+ } else {
+ srec.app.connectionService = null;
+ srec.app.connectionGroup = 0;
+ srec.app.connectionImportance = 0;
+ }
} else {
- srec.app.connectionService = null;
- srec.app.connectionGroup = 0;
- srec.app.connectionImportance = 0;
+ if (group > 0) {
+ srec.pendingConnectionGroup = group;
+ srec.pendingConnectionImportance = importance;
+ } else {
+ srec.pendingConnectionGroup = 0;
+ srec.pendingConnectionImportance = 0;
+ }
}
}
}
@@ -2058,8 +2067,8 @@ public final class ActiveServices {
sInfo.applicationInfo.uid, name.getPackageName(),
name.getClassName());
}
- r = new ServiceRecord(mAm, ss, className, name, filter, sInfo, callingFromFg,
- res);
+ r = new ServiceRecord(mAm, ss, className, name, filter, sInfo,
+ callingFromFg, res);
res.setService(r);
smap.mServicesByInstanceName.put(name, r);
smap.mServicesByIntent.put(filter, r);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8842f4198206..c16f1db5c579 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9209,6 +9209,19 @@ public class ActivityManagerService extends IActivityManager.Stub
}
sdumper.dumpWithClient();
}
+ if (dumpPackage == null) {
+ // Intentionally dropping the lock for this, because dumpBinderProxies() will make many
+ // outgoing binder calls to retrieve interface descriptors; while that is system code,
+ // there is nothing preventing an app from overriding this implementation by talking to
+ // the binder driver directly, and hang up system_server in the process. So, dump
+ // without locks held, and even then only when there is an unreasonably large number of
+ // proxies in the first place.
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpBinderProxies(pw, BINDER_PROXY_HIGH_WATERMARK /* minToDump */);
+ }
synchronized(this) {
pw.println();
if (dumpAll) {
@@ -9274,19 +9287,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
}
- if (dumpPackage == null) {
- // Intentionally dropping the lock for this, because dumpBinderProxies() will make many
- // outgoing binder calls to retrieve interface descriptors; while that is system code,
- // there is nothing preventing an app from overriding this implementation by talking to
- // the binder driver directly, and hang up system_server in the process. So, dump
- // without locks held, and even then only when there is an unreasonably large number of
- // proxies in the first place.
- pw.println();
- if (dumpAll) {
- pw.println("-------------------------------------------------------------------------------");
- }
- dumpBinderProxies(pw, BINDER_PROXY_HIGH_WATERMARK /* minToDump */);
- }
}
/**
@@ -10266,7 +10266,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
continue;
}
- r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS);
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS, mProcessList.mLruProcesses.indexOf(r)
+ );
if (r.isPersistent()) {
numPers++;
}
@@ -10278,7 +10279,9 @@ public class ActivityManagerService extends IActivityManager.Stub
if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
continue;
}
- r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ISOLATED_PROCS);
+ r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.ISOLATED_PROCS,
+ mProcessList.mLruProcesses.indexOf(r)
+ );
}
for (int i=0; i<mActiveInstrumentation.size(); i++) {
@@ -10376,7 +10379,7 @@ public class ActivityManagerService extends IActivityManager.Stub
writeProcessesToGcToProto(proto, ActivityManagerServiceDumpProcessesProto.GC_PROCS, dumpPackage);
mAppErrors.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.APP_ERRORS, dumpPackage);
- mAtmInternal.writeProcessesToProto(proto, dumpPackage);
+ mAtmInternal.writeProcessesToProto(proto, dumpPackage, mWakefulness, mTestPssMode);
if (dumpPackage == null) {
mUserController.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER);
@@ -10406,14 +10409,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- if (dumpPackage == null) {
- final long sleepToken = proto.start(ActivityManagerServiceDumpProcessesProto.SLEEP_STATUS);
- proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.WAKEFULNESS,
- PowerManagerInternal.wakefulnessToProtoEnum(mWakefulness));
- proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.TEST_PSS_MODE, mTestPssMode);
- proto.end(sleepToken);
- }
-
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
|| mOrigWaitForDebugger) {
if (dumpPackage == null || dumpPackage.equals(mDebugApp)
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 62f100926581..8cf9f1e9ae4a 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -537,40 +537,44 @@ public final class ProcessList {
}
private static String buildOomTag(String prefix, String space, int val, int base) {
- if (val == base) {
+ final int diff = val - base;
+ if (diff == 0) {
if (space == null) return prefix;
- return prefix + " ";
+ return prefix + space;
}
- return prefix + "+" + Integer.toString(val - base);
+ if (diff < 10) {
+ return prefix + "+ " + Integer.toString(diff);
+ }
+ return prefix + "+" + Integer.toString(diff);
}
public static String makeOomAdjString(int setAdj) {
if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
- return buildOomTag("cch", " ", setAdj, ProcessList.CACHED_APP_MIN_ADJ);
+ return buildOomTag("cch", " ", setAdj, ProcessList.CACHED_APP_MIN_ADJ);
} else if (setAdj >= ProcessList.SERVICE_B_ADJ) {
- return buildOomTag("svcb ", null, setAdj, ProcessList.SERVICE_B_ADJ);
+ return buildOomTag("svcb ", null, setAdj, ProcessList.SERVICE_B_ADJ);
} else if (setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
- return buildOomTag("prev ", null, setAdj, ProcessList.PREVIOUS_APP_ADJ);
+ return buildOomTag("prev ", null, setAdj, ProcessList.PREVIOUS_APP_ADJ);
} else if (setAdj >= ProcessList.HOME_APP_ADJ) {
- return buildOomTag("home ", null, setAdj, ProcessList.HOME_APP_ADJ);
+ return buildOomTag("home ", null, setAdj, ProcessList.HOME_APP_ADJ);
} else if (setAdj >= ProcessList.SERVICE_ADJ) {
- return buildOomTag("svc ", null, setAdj, ProcessList.SERVICE_ADJ);
+ return buildOomTag("svc ", null, setAdj, ProcessList.SERVICE_ADJ);
} else if (setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
- return buildOomTag("hvy ", null, setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+ return buildOomTag("hvy ", null, setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
} else if (setAdj >= ProcessList.BACKUP_APP_ADJ) {
- return buildOomTag("bkup ", null, setAdj, ProcessList.BACKUP_APP_ADJ);
+ return buildOomTag("bkup ", null, setAdj, ProcessList.BACKUP_APP_ADJ);
} else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
- return buildOomTag("prcp ", null, setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
+ return buildOomTag("prcp ", null, setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
} else if (setAdj >= ProcessList.VISIBLE_APP_ADJ) {
- return buildOomTag("vis ", null, setAdj, ProcessList.VISIBLE_APP_ADJ);
+ return buildOomTag("vis", " ", setAdj, ProcessList.VISIBLE_APP_ADJ);
} else if (setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
- return buildOomTag("fore ", null, setAdj, ProcessList.FOREGROUND_APP_ADJ);
+ return buildOomTag("fore ", null, setAdj, ProcessList.FOREGROUND_APP_ADJ);
} else if (setAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
- return buildOomTag("psvc ", null, setAdj, ProcessList.PERSISTENT_SERVICE_ADJ);
+ return buildOomTag("psvc ", null, setAdj, ProcessList.PERSISTENT_SERVICE_ADJ);
} else if (setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
- return buildOomTag("pers ", null, setAdj, ProcessList.PERSISTENT_PROC_ADJ);
+ return buildOomTag("pers ", null, setAdj, ProcessList.PERSISTENT_PROC_ADJ);
} else if (setAdj >= ProcessList.SYSTEM_ADJ) {
- return buildOomTag("sys ", null, setAdj, ProcessList.SYSTEM_ADJ);
+ return buildOomTag("sys ", null, setAdj, ProcessList.SYSTEM_ADJ);
} else if (setAdj >= ProcessList.NATIVE_ADJ) {
return buildOomTag("ntv ", null, setAdj, ProcessList.NATIVE_ADJ);
} else {
@@ -2237,6 +2241,191 @@ public final class ProcessList {
return index;
}
+ /**
+ * Handle the case where we are inserting a process hosting client activities:
+ * Make sure any groups have their order match their importance, and take care of
+ * distributing old clients across other activity processes so they can't spam
+ * the LRU list. Processing of the list will be restricted by the indices provided,
+ * and not extend out of them.
+ *
+ * @param topApp The app at the top that has just been inserted in to the list.
+ * @param topI The position in the list where topApp was inserted; this is the start (at the
+ * top) where we are going to do our processing.
+ * @param bottomI The last position at which we will be processing; this is the end position
+ * of whichever section of the LRU list we are in. Nothing past it will be
+ * touched.
+ * @param endIndex The current end of the top being processed. Typically topI - 1. That is,
+ * where we are going to start potentially adjusting other entries in the list.
+ */
+ private void updateClientActivitiesOrdering(final ProcessRecord topApp, final int topI,
+ final int bottomI, int endIndex) {
+ if (topApp.hasActivitiesOrRecentTasks() || topApp.treatLikeActivity
+ || !topApp.hasClientActivities()) {
+ // If this is not a special process that has client activities, then there is
+ // nothing to do.
+ return;
+ }
+
+ final int uid = topApp.info.uid;
+ if (topApp.connectionGroup > 0) {
+ int endImportance = topApp.connectionImportance;
+ for (int i = endIndex; i >= bottomI; i--) {
+ final ProcessRecord subProc = mLruProcesses.get(i);
+ if (subProc.info.uid == uid
+ && subProc.connectionGroup == topApp.connectionGroup) {
+ if (i == endIndex && subProc.connectionImportance >= endImportance) {
+ // This process is already in the group, and its importance
+ // is not as strong as the process before it, so keep it
+ // correctly positioned in the group.
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Keeping in-place above " + subProc
+ + " endImportance=" + endImportance
+ + " group=" + subProc.connectionGroup
+ + " importance=" + subProc.connectionImportance);
+ endIndex--;
+ endImportance = subProc.connectionImportance;
+ } else {
+ // We want to pull this up to be with the rest of the group,
+ // and order within the group by importance.
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Pulling up " + subProc
+ + " to position in group with importance="
+ + subProc.connectionImportance);
+ boolean moved = false;
+ for (int pos = topI; pos > endIndex; pos--) {
+ final ProcessRecord posProc = mLruProcesses.get(pos);
+ if (subProc.connectionImportance
+ <= posProc.connectionImportance) {
+ mLruProcesses.remove(i);
+ mLruProcesses.add(pos, subProc);
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Moving " + subProc
+ + " from position " + i + " to above " + posProc
+ + " @ " + pos);
+ moved = true;
+ endIndex--;
+ break;
+ }
+ }
+ if (!moved) {
+ // Goes to the end of the group.
+ mLruProcesses.remove(i);
+ mLruProcesses.add(endIndex - 1, subProc);
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Moving " + subProc
+ + " from position " + i + " to end of group @ "
+ + endIndex);
+ endIndex--;
+ endImportance = subProc.connectionImportance;
+ }
+ }
+ }
+ }
+
+ }
+ // To keep it from spamming the LRU list (by making a bunch of clients),
+ // we will distribute other entries owned by it to be in-between other apps.
+ int i = endIndex;
+ while (i >= bottomI) {
+ ProcessRecord subProc = mLruProcesses.get(i);
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Looking to spread old procs, at " + subProc + " @ " + i);
+ if (subProc.info.uid != uid) {
+ // This is a different app... if we have gone through some of the
+ // target app, pull this up to be before them. We want to pull up
+ // one activity process, but any number of non-activity processes.
+ if (i < endIndex) {
+ boolean hasActivity = false;
+ int connUid = 0;
+ int connGroup = 0;
+ while (i >= bottomI) {
+ mLruProcesses.remove(i);
+ mLruProcesses.add(endIndex, subProc);
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Different app, moving to " + endIndex);
+ i--;
+ if (i < bottomI) {
+ break;
+ }
+ subProc = mLruProcesses.get(i);
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Looking at next app at " + i + ": " + subProc);
+ if (subProc.hasActivitiesOrRecentTasks() || subProc.treatLikeActivity) {
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "This is hosting an activity!");
+ if (hasActivity) {
+ // Already found an activity, done.
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Already found an activity, done");
+ break;
+ }
+ hasActivity = true;
+ } else if (subProc.hasClientActivities()) {
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "This is a client of an activity");
+ if (hasActivity) {
+ if (connUid == 0 || connUid != subProc.info.uid) {
+ // Already have an activity that is not from from a client
+ // connection or is a different client connection, done.
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Already found a different activity: connUid="
+ + connUid + " uid=" + subProc.info.uid);
+ break;
+ } else if (connGroup == 0 || connGroup != subProc.connectionGroup) {
+ // Previously saw a different group or not from a group,
+ // want to treat these as different things.
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Already found a different group: connGroup="
+ + connGroup + " group=" + subProc.connectionGroup);
+ break;
+ }
+ } else {
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "This is an activity client! uid="
+ + subProc.info.uid + " group=" + subProc.connectionGroup);
+ hasActivity = true;
+ connUid = subProc.info.uid;
+ connGroup = subProc.connectionGroup;
+ }
+ }
+ endIndex--;
+ }
+ }
+ // Find the end of the next group of processes for target app. This
+ // is after any entries of different apps (so we don't change the existing
+ // relative order of apps) and then after the next last group of processes
+ // of the target app.
+ for (endIndex--; endIndex >= bottomI; endIndex--) {
+ final ProcessRecord endProc = mLruProcesses.get(endIndex);
+ if (endProc.info.uid == uid) {
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Found next group of app: " + endProc + " @ "
+ + endIndex);
+ break;
+ }
+ }
+ if (endIndex >= bottomI) {
+ final ProcessRecord endProc = mLruProcesses.get(endIndex);
+ for (endIndex--; endIndex >= bottomI; endIndex--) {
+ final ProcessRecord nextEndProc = mLruProcesses.get(endIndex);
+ if (nextEndProc.info.uid != uid
+ || nextEndProc.connectionGroup != endProc.connectionGroup) {
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Found next group or app: " + nextEndProc + " @ "
+ + endIndex + " group=" + nextEndProc.connectionGroup);
+ break;
+ }
+ }
+ }
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Bumping scan position to " + endIndex);
+ i = endIndex;
+ } else {
+ i--;
+ }
+ }
+ }
+
final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
ProcessRecord client) {
final boolean hasActivity = app.hasActivitiesOrRecentTasks() || app.hasClientActivities()
@@ -2349,91 +2538,31 @@ public final class ProcessList {
if (!app.hasActivitiesOrRecentTasks() && !app.treatLikeActivity
&& mLruProcessActivityStart < (N - 1)) {
// Process doesn't have activities, but has clients with
- // activities... move it up, but one below the top (the top
- // should always have a real activity).
+ // activities... move it up, but below the app that is binding to it.
if (DEBUG_LRU) Slog.d(TAG_LRU,
- "Adding to second-top of LRU activity list: " + app);
- mLruProcesses.add(N - 1, app);
- // If this process is part of a group, need to pull up any other processes
- // in that group to be with it.
- final int uid = app.info.uid;
- int endIndex = N - 2;
- nextActivityIndex = N - 2;
- if (app.connectionGroup > 0) {
- int endImportance = app.connectionImportance;
- for (int i = endIndex; i >= mLruProcessActivityStart; i--) {
- final ProcessRecord subProc = mLruProcesses.get(i);
- if (subProc.info.uid == uid
- && subProc.connectionGroup == subProc.connectionGroup) {
- if (i == endIndex && subProc.connectionImportance >= endImportance) {
- // This process is already in the group, and its importance
- // is not as strong as the process before it, so it keep it
- // correctly positioned in the group.
- endIndex--;
- endImportance = subProc.connectionImportance;
- } else {
- // We want to pull this up to be with the rest of the group,
- // and order within the group by importance.
- boolean moved = false;
- for (int pos = N - 1; pos > endIndex; pos--) {
- final ProcessRecord posProc = mLruProcesses.get(pos);
- if (subProc.connectionImportance
- <= posProc.connectionImportance) {
- mLruProcesses.remove(i);
- mLruProcesses.add(pos, subProc);
- moved = true;
- endIndex--;
- break;
- }
- }
- if (!moved) {
- // Goes to the end of the group.
- mLruProcesses.remove(i);
- mLruProcesses.add(endIndex - 1, subProc);
- endIndex--;
- endImportance = subProc.connectionImportance;
- }
- }
- }
+ "Adding to second-top of LRU activity list: " + app
+ + " group=" + app.connectionGroup
+ + " importance=" + app.connectionImportance);
+ int pos = N - 1;
+ while (pos > mLruProcessActivityStart) {
+ final ProcessRecord posproc = mLruProcesses.get(pos);
+ if (posproc.info.uid == app.info.uid) {
+ // Technically this app could have multiple processes with different
+ // activities and so we should be looking for the actual process that
+ // is bound to the target proc... but I don't really care, do you?
+ break;
}
-
+ pos--;
}
- // To keep it from spamming the LRU list (by making a bunch of clients),
- // we will distribute other entries owned by it to be in-between other apps.
- for (int i = endIndex; i >= mLruProcessActivityStart; i--) {
- final ProcessRecord subProc = mLruProcesses.get(i);
- if (subProc.info.uid != uid) {
- // This is a different app... if we have gone through some of the
- // target app, pull this up to be before them.
- if (i < endIndex) {
- mLruProcesses.remove(i);
- mLruProcesses.add(endIndex, subProc);
- }
- // Find the end of the next group of processes for target app. This
- // is after any entries of different apps (so we don't change the existing
- // relative order of apps) and then after the next last group of processes
- // of the target app.
- for (endIndex--; endIndex >= mLruProcessActivityStart; endIndex--) {
- final ProcessRecord endProc = mLruProcesses.get(endIndex);
- if (endProc.info.uid == uid) {
- break;
- }
- }
- if (endIndex >= mLruProcessActivityStart) {
- final ProcessRecord endProc = mLruProcesses.get(endIndex);
- for (endIndex--; endIndex >= mLruProcessActivityStart; endIndex--) {
- final ProcessRecord nextEndProc = mLruProcesses.get(endIndex);
- if (nextEndProc.info.uid != uid
- || nextEndProc.connectionGroup != endProc.connectionGroup) {
- break;
- }
- }
- }
- if (i > endIndex) {
- i = endIndex;
- }
- }
+ mLruProcesses.add(pos, app);
+ // If this process is part of a group, need to pull up any other processes
+ // in that group to be with it.
+ int endIndex = pos - 1;
+ if (endIndex < mLruProcessActivityStart) {
+ endIndex = mLruProcessActivityStart;
}
+ nextActivityIndex = endIndex;
+ updateClientActivitiesOrdering(app, pos, mLruProcessActivityStart, endIndex);
} else {
// Process has activities, put it at the very tipsy-top.
if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app);
@@ -2469,6 +2598,9 @@ public final class ProcessList {
nextIndex = index - 1;
mLruProcessActivityStart++;
mLruProcessServiceStart++;
+ if (index > 1) {
+ updateClientActivitiesOrdering(app, mLruProcessServiceStart - 1, 0, index - 1);
+ }
}
app.lruSeq = mLruSeq;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 013de93c7f24..4826f486da89 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -586,7 +586,7 @@ final class ProcessRecord implements WindowProcessListener {
}
origBase.makeInactive();
}
- baseProcessTracker = tracker.getProcessStateLocked(info.packageName, uid,
+ baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid,
info.longVersionCode, processName);
baseProcessTracker.makeActive();
for (int i=0; i<pkgList.size(); i++) {
@@ -594,7 +594,7 @@ final class ProcessRecord implements WindowProcessListener {
if (holder.state != null && holder.state != origBase) {
holder.state.makeInactive();
}
- tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), uid,
+ tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), info.uid,
info.longVersionCode, processName);
if (holder.state != baseProcessTracker) {
holder.state.makeActive();
@@ -760,19 +760,25 @@ final class ProcessRecord implements WindowProcessListener {
@Override
public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ writeToProto(proto, fieldId, -1);
+ }
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId, int lruIndex) {
long token = proto.start(fieldId);
proto.write(ProcessRecordProto.PID, pid);
proto.write(ProcessRecordProto.PROCESS_NAME, processName);
- if (info.uid < Process.FIRST_APPLICATION_UID) {
- proto.write(ProcessRecordProto.UID, uid);
- } else {
+ proto.write(ProcessRecordProto.UID, info.uid);
+ if (UserHandle.getAppId(info.uid) >= Process.FIRST_APPLICATION_UID) {
proto.write(ProcessRecordProto.USER_ID, userId);
proto.write(ProcessRecordProto.APP_ID, UserHandle.getAppId(info.uid));
- if (uid != info.uid) {
- proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid));
- }
+ }
+ if (uid != info.uid) {
+ proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid));
}
proto.write(ProcessRecordProto.PERSISTENT, mPersistent);
+ if (lruIndex >= 0) {
+ proto.write(ProcessRecordProto.LRU_INDEX, lruIndex);
+ }
proto.end(token);
}
@@ -864,7 +870,8 @@ final class ProcessRecord implements WindowProcessListener {
ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
versionCode);
if (baseProcessTracker != null) {
- tracker.updateProcessStateHolderLocked(holder, pkg, uid, versionCode, processName);
+ tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode,
+ processName);
pkgList.put(pkg, holder);
if (holder.state != baseProcessTracker) {
holder.state.makeActive();
@@ -925,7 +932,7 @@ final class ProcessRecord implements WindowProcessListener {
pkgList.clear();
ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
info.longVersionCode);
- tracker.updateProcessStateHolderLocked(holder, info.packageName, uid,
+ tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid,
info.longVersionCode, processName);
pkgList.put(info.packageName, holder);
if (holder.state != baseProcessTracker) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 09f8c3eee3b6..da5ce1c45610 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -121,6 +121,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
long nextRestartTime; // time when restartDelay will expire.
boolean destroying; // set when we have started destroying the service
long destroyTime; // time at which destory was initiated.
+ int pendingConnectionGroup; // To be filled in to ProcessRecord once it connects
+ int pendingConnectionImportance; // To be filled in to ProcessRecord once it connects
String stringName; // caching of toString
@@ -386,6 +388,11 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
pw.print(" restartTime=");
TimeUtils.formatDuration(restartTime, now, pw);
pw.print(" createdFromFg="); pw.println(createdFromFg);
+ if (pendingConnectionGroup != 0) {
+ pw.print(prefix); pw.print(" pendingConnectionGroup=");
+ pw.print(pendingConnectionGroup);
+ pw.print(" Importance="); pw.println(pendingConnectionImportance);
+ }
if (startRequested || delayedStop || lastStartId != 0) {
pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
pw.print(" delayedStop="); pw.print(delayedStop);
@@ -461,7 +468,11 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
serviceInfo = sInfo;
appInfo = sInfo.applicationInfo;
packageName = sInfo.applicationInfo.packageName;
- processName = sInfo.processName;
+ if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
+ processName = sInfo.processName + ":" + instanceName.getClassName();
+ } else {
+ processName = sInfo.processName;
+ }
permission = sInfo.permission;
exported = sInfo.exported;
this.restarter = restarter;
@@ -507,6 +518,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
public void setProcess(ProcessRecord _proc) {
app = _proc;
+ if (pendingConnectionGroup > 0) {
+ app.connectionService = this;
+ app.connectionGroup = pendingConnectionGroup;
+ app.connectionImportance = pendingConnectionImportance;
+ pendingConnectionGroup = pendingConnectionImportance = 0;
+ }
if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS) {
for (int conni = connections.size() - 1; conni >= 0; conni--) {
ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 353f787f9005..271b37ec7568 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1144,7 +1144,7 @@ class UserController implements Handler.Callback {
/**
* Attempt to unlock user without a credential token. This typically
* succeeds when the device doesn't have credential-encrypted storage, or
- * when the the credential-encrypted storage isn't tied to a user-provided
+ * when the credential-encrypted storage isn't tied to a user-provided
* PIN or pattern.
*/
private boolean maybeUnlockUser(final int userId) {
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 0b6786cf8c07..521fa236cf7d 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -16,6 +16,8 @@
package com.android.server.display;
+import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TypeEvaluator;
@@ -29,8 +31,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
+import android.hardware.display.IColorDisplayManager;
import android.net.Uri;
import android.opengl.Matrix;
+import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
@@ -39,6 +43,7 @@ import android.util.MathUtils;
import android.util.Slog;
import android.view.animation.AnimationUtils;
+import com.android.internal.R;
import com.android.internal.app.ColorDisplayController;
import com.android.server.SystemService;
import com.android.server.twilight.TwilightListener;
@@ -49,12 +54,8 @@ import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
-import com.android.internal.R;
-
-import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
-
/**
- * Tints the display at night.
+ * Controls the display's color transforms.
*/
public final class ColorDisplayService extends SystemService
implements ColorDisplayController.Callback {
@@ -101,7 +102,7 @@ public final class ColorDisplayService extends SystemService
@Override
public void onStart() {
- // Nothing to publish.
+ publishBinderService(Context.COLOR_DISPLAY_SERVICE, new BinderService());
}
@Override
@@ -171,7 +172,7 @@ public final class ColorDisplayService extends SystemService
}
};
cr.registerContentObserver(Secure.getUriFor(Secure.USER_SETUP_COMPLETE),
- false /* notifyForDescendents */, mUserSetupObserver, mCurrentUser);
+ false /* notifyForDescendants */, mUserSetupObserver, mCurrentUser);
} else if (mBootCompleted) {
setUp();
}
@@ -405,8 +406,8 @@ public final class ColorDisplayService extends SystemService
}
/**
- * Returns the first date time corresponding to the local time that occurs before the
- * provided date time.
+ * Returns the first date time corresponding to the local time that occurs before the provided
+ * date time.
*
* @param compareTime the LocalDateTime to compare against
* @return the prior LocalDateTime corresponding to this local time
@@ -420,8 +421,8 @@ public final class ColorDisplayService extends SystemService
}
/**
- * Returns the first date time corresponding to this local time that occurs after the
- * provided date time.
+ * Returns the first date time corresponding to this local time that occurs after the provided
+ * date time.
*
* @param compareTime the LocalDateTime to compare against
* @return the next LocalDateTime corresponding to this local time
@@ -434,6 +435,11 @@ public final class ColorDisplayService extends SystemService
return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
}
+ private boolean isDeviceColorManagedInternal() {
+ final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+ return dtm.isDeviceColorManaged();
+ }
+
private abstract class AutoMode implements ColorDisplayController.Callback {
public abstract void onStart();
@@ -616,4 +622,16 @@ public final class ColorDisplayService extends SystemService
return mResultMatrix;
}
}
+
+ private final class BinderService extends IColorDisplayManager.Stub {
+ @Override
+ public boolean isDeviceColorManaged() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return isDeviceColorManagedInternal();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index d6931e006479..5ca1755131ab 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -16,7 +16,6 @@
package com.android.server.display;
-import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.opengl.Matrix;
import android.os.IBinder;
@@ -27,8 +26,10 @@ import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.ColorDisplayController;
+
import java.util.Arrays;
/**
@@ -59,10 +60,6 @@ public class DisplayTransformManager {
private static final int SURFACE_FLINGER_TRANSACTION_COLOR_MATRIX = 1015;
private static final int SURFACE_FLINGER_TRANSACTION_DALTONIZER = 1014;
-
- private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
- private static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
-
/**
* SurfaceFlinger global saturation factor.
*/
@@ -71,6 +68,10 @@ public class DisplayTransformManager {
* SurfaceFlinger display color (managed, unmanaged, etc.).
*/
private static final int SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR = 1023;
+ private static final int SURFACE_FLINGER_TRANSACTION_QUERY_WIDE_COLOR = 1030;
+
+ private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
+ private static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
private static final float COLOR_SATURATION_NATURAL = 1.0f;
private static final float COLOR_SATURATION_BOOSTED = 1.1f;
@@ -269,6 +270,29 @@ public class DisplayTransformManager {
}
/**
+ * Returns whether the screen is wide color gamut via SurfaceFlinger's
+ * {@link #SURFACE_FLINGER_TRANSACTION_QUERY_WIDE_COLOR}.
+ */
+ public boolean isDeviceColorManaged() {
+ final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
+ if (flinger != null) {
+ final Parcel data = Parcel.obtain();
+ final Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ try {
+ flinger.transact(SURFACE_FLINGER_TRANSACTION_QUERY_WIDE_COLOR, data, reply, 0);
+ return reply.readBoolean();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to query wide color support", ex);
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+ return false;
+ }
+
+ /**
* Propagates the provided saturation to the SurfaceFlinger.
*/
private void applySaturation(float saturation) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b148a2f3fff5..c0d3fdfb8f91 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -980,7 +980,7 @@ public class HdmiControlService extends SystemService {
* @param sourceAddress a logical address of source device where sends polling message
* @param pickStrategy strategy how to pick polling candidates
* @param retryCount the number of retry used to send polling message to remote devices
- * @throw IllegalArgumentException if {@code pickStrategy} is invalid value
+ * @throws IllegalArgumentException if {@code pickStrategy} is invalid value
*/
@ServiceThreadOnly
void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy,
diff --git a/services/core/java/com/android/server/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 1759ce195485..96095d89687e 100644
--- a/services/core/java/com/android/server/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.infra;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -39,6 +39,9 @@ import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
import java.io.PrintWriter;
import java.util.List;
@@ -211,6 +214,66 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
}
/**
+ * Temporary sets the service implementation.
+ *
+ * <p>Typically used by Shell command and/or CTS tests.
+ *
+ * @param componentName name of the new component
+ * @param durationMs how long the change will be valid (the service will be automatically reset
+ * to the default component after this timeout expires).
+ * @throws SecurityException if caller is not allowed to manage this service's settings.
+ * @throws IllegalArgumentException if value of {@code durationMs} is higher than
+ * {@link #getMaximumTemporaryServiceDurationMs()}.
+ */
+ public final void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
+ int durationMs) {
+ Slog.i(mTag, "setTemporaryService(" + userId + ") to " + componentName + " for "
+ + durationMs + "ms");
+ enforceCallingPermissionForManagement();
+
+ Preconditions.checkNotNull(componentName);
+ final int maxDurationMs = getMaximumTemporaryServiceDurationMs();
+ if (durationMs > maxDurationMs) {
+ throw new IllegalArgumentException(
+ "Max duration is " + maxDurationMs + " (called with " + durationMs + ")");
+ }
+
+ synchronized (mLock) {
+ final S service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.setTemporaryServiceLocked(componentName, durationMs);
+ }
+ }
+ }
+
+ /**
+ * Gets the maximum time the service implementation can be changed.
+ *
+ * @throws UnsupportedOperationException if subclass doesn't override it.
+ */
+ protected int getMaximumTemporaryServiceDurationMs() {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
+
+ /**
+ * Resets the temporary service implementation to the default component.
+ *
+ * <p>Typically used by Shell command and/or CTS tests.
+ *
+ * @throws SecurityException if caller is not allowed to manage this service's settings.
+ */
+ public final void resetTemporaryService(@UserIdInt int userId) {
+ Slog.i(mTag, "resetTemporaryService(): " + userId);
+ enforceCallingPermissionForManagement();
+ synchronized (mLock) {
+ final S service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.resetTemporaryServiceLocked();
+ }
+ }
+ }
+
+ /**
* Asserts that the caller has permissions to manage this service.
*
* <p>Typically called by {@code ShellCommand} implementations.
diff --git a/services/core/java/com/android/server/AbstractMultiplePendingRequestsRemoteService.java b/services/core/java/com/android/server/infra/AbstractMultiplePendingRequestsRemoteService.java
index f532b22cb8d4..513a6a3eeec8 100644
--- a/services/core/java/com/android/server/AbstractMultiplePendingRequestsRemoteService.java
+++ b/services/core/java/com/android/server/infra/AbstractMultiplePendingRequestsRemoteService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.infra;
import android.annotation.NonNull;
import android.content.ComponentName;
diff --git a/services/core/java/com/android/server/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
index 001d85f1b798..dfe8a369db44 100644
--- a/services/core/java/com/android/server/AbstractPerUserSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.infra;
import android.annotation.CallSuper;
import android.annotation.NonNull;
@@ -26,12 +26,17 @@ import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
+import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
@@ -49,6 +54,9 @@ import java.io.PrintWriter;
public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSystemService<S, M>,
M extends AbstractMasterSystemService<M, S>> {
+ /** Handler message to {@link #resetTemporaryServiceLocked()} */
+ private static final int MSG_RESET_TEMPORARY_SERVICE = 0;
+
protected final @UserIdInt int mUserId;
protected final Object mLock;
protected final String mTag = getClass().getSimpleName();
@@ -70,6 +78,26 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
@GuardedBy("mLock")
private ServiceInfo mServiceInfo;
+ /**
+ * Temporary service name set by {@link #setTemporaryServiceLocked(String, int)}.
+ *
+ * <p>Typically used by Shell command and/or CTS tests.
+ */
+ @GuardedBy("mLock")
+ private String mTemporaryServiceName;
+
+ /**
+ * When the temporary service will expire (and reset back to the default).
+ */
+ @GuardedBy("mLock")
+ private long mTemporaryServiceExpiration;
+
+ /**
+ * Handler used to reset the temporary service name.
+ */
+ @GuardedBy("mLock")
+ private Handler mTemporaryHandler;
+
protected AbstractPerUserSystemService(@NonNull M master, @NonNull Object lock,
@UserIdInt int userId) {
mMaster = master;
@@ -130,7 +158,7 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
mDisabled = disabled;
ComponentName serviceComponent = null;
ServiceInfo serviceInfo = null;
- final String componentName = getComponentNameFromSettings();
+ final String componentName = getComponentNameLocked();
if (!TextUtils.isEmpty(componentName)) {
try {
serviceComponent = ComponentName.unflattenFromString(componentName);
@@ -191,6 +219,29 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
}
/**
+ * Gets the current name of the service, which is either the
+ * {@link #getDefaultComponentName() default service} or the
+ * {@link #setTemporaryServiceLocked(String, int) temporary one}.
+ */
+ protected final String getComponentNameLocked() {
+ if (mTemporaryServiceName != null) {
+ // Always log it, as it should only be used on CTS or during development
+ Slog.w(mTag, "getComponentName(): using temporary name " + mTemporaryServiceName);
+ return mTemporaryServiceName;
+ }
+ return getDefaultComponentName();
+ }
+
+ /**
+ * Gets the name of the default component for the service.
+ *
+ * <p>Typically implemented by returning {@link #getComponentNameFromSettings()} or by using
+ * a string from the system resources.
+ */
+ @Nullable
+ protected abstract String getDefaultComponentName();
+
+ /**
* Gets this name of the remote service this service binds to as defined by {@link Settings}.
*/
@Nullable
@@ -201,6 +252,66 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
}
/**
+ * Checks whether the current service for the user was temporarily set.
+ */
+ public final boolean isTemporaryServiceSetLocked() {
+ return mTemporaryServiceName != null;
+ }
+
+ /**
+ * Temporary sets the service implementation.
+ *
+ * @param componentName name of the new component
+ * @param durationMs how long the change will be valid (the service will be automatically reset
+ * to the default component after this timeout expires).
+ */
+ protected final void setTemporaryServiceLocked(@NonNull String componentName, int durationMs) {
+ mTemporaryServiceName = componentName;
+
+ if (mTemporaryHandler == null) {
+ mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_RESET_TEMPORARY_SERVICE) {
+ synchronized (mLock) {
+ resetTemporaryServiceLocked();
+ }
+ } else {
+ Slog.wtf(mTag, "invalid handler msg: " + msg);
+ }
+ }
+ };
+ } else {
+ removeResetTemporaryServiceMessageLocked();
+ }
+ mTemporaryServiceExpiration = SystemClock.elapsedRealtime() + durationMs;
+ mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs);
+
+ updateLocked(mDisabled);
+ }
+
+ private void removeResetTemporaryServiceMessageLocked() {
+ if (mMaster.verbose) {
+ Slog.v(mTag, "setTemporaryServiceLocked(): removing old message");
+ }
+ // NOTE: caller should already have checked it
+ mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE);
+ }
+
+ /**
+ * Resets the temporary service implementation to the default component.
+ */
+ protected final void resetTemporaryServiceLocked() {
+ Slog.i(mTag, "resetting temporary service from " + mTemporaryServiceName);
+ mTemporaryServiceName = null;
+ if (mTemporaryHandler != null) {
+ removeResetTemporaryServiceMessageLocked();
+ mTemporaryHandler = null;
+ }
+ updateLocked(mDisabled);
+ }
+
+ /**
* Gets the {@link ComponentName} of the remote service this service binds to, or {@code null}
* if the service is disabled.
*/
@@ -290,12 +401,14 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
pw.print(prefix); pw.print("Service UID: ");
pw.println(mServiceInfo.applicationInfo.uid);
}
- final String componentName = getComponentNameFromSettings();
- if (componentName != null) {
- pw.print(prefix); pw.print("Service name: ");
- pw.println(componentName);
+ if (mTemporaryServiceName != null) {
+ pw.print(prefix); pw.print("Temporary service name: "); pw.print(mTemporaryServiceName);
+ final long ttl = mTemporaryServiceExpiration - SystemClock.elapsedRealtime();
+ pw.print(" (expires in "); TimeUtils.formatDuration(ttl, pw); pw.println(")");
+ pw.print(prefix); pw.print(prefix);
+ pw.print("Default service name: "); pw.println(getDefaultComponentName());
} else {
- pw.println("No service package set");
+ pw.print(prefix); pw.print("Service name: "); pw.println(getDefaultComponentName());
}
}
}
diff --git a/services/core/java/com/android/server/AbstractRemoteService.java b/services/core/java/com/android/server/infra/AbstractRemoteService.java
index f636487c666b..7af1d4ca94ef 100644
--- a/services/core/java/com/android/server/AbstractRemoteService.java
+++ b/services/core/java/com/android/server/infra/AbstractRemoteService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.infra;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -33,6 +33,7 @@ import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.FgThread;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
diff --git a/services/core/java/com/android/server/AbstractSinglePendingRequestRemoteService.java b/services/core/java/com/android/server/infra/AbstractSinglePendingRequestRemoteService.java
index 8e1f540a4d5e..8f8b448a7a66 100644
--- a/services/core/java/com/android/server/AbstractSinglePendingRequestRemoteService.java
+++ b/services/core/java/com/android/server/infra/AbstractSinglePendingRequestRemoteService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.infra;
import android.annotation.NonNull;
import android.content.ComponentName;
diff --git a/services/core/java/com/android/server/infra/package.html b/services/core/java/com/android/server/infra/package.html
new file mode 100644
index 000000000000..61a4c433cdaf
--- /dev/null
+++ b/services/core/java/com/android/server/infra/package.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+Contains common classes providing the plumbing infrastructure necessary to implement a system
+service
+</body>
+</html> \ No newline at end of file
diff --git a/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java b/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java
index d5be26ac3389..f424869a428e 100644
--- a/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java
+++ b/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java
@@ -16,10 +16,12 @@
package com.android.server.intelligence;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.os.Bundle;
import android.os.IBinder;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
/**
@@ -53,6 +55,7 @@ public abstract class IntelligenceManagerInternal {
* @param activityToken activity that originated this request.
* @param autofillSessionId autofill session id (must be used on {@code client} calls.
* @param focusedId id of the the field that triggered this request.
+ * @param focusedValue current value of the field that triggered this request.
*
* @return {@code false} if the service cannot handle this request, {@code true} otherwise.
* <b>NOTE: </b> it must return right away; typically it will return {@code false} if the
@@ -60,7 +63,8 @@ public abstract class IntelligenceManagerInternal {
*/
public abstract AugmentedAutofillCallback requestAutofill(@UserIdInt int userId,
@NonNull IAutoFillManagerClient client, @NonNull IBinder activityToken,
- int autofillSessionId, @NonNull AutofillId focusedId);
+ int autofillSessionId, @NonNull AutofillId focusedId,
+ @Nullable AutofillValue focusedValue);
/**
* Callback used by the Autofill Session to communicate with the Augmented Autofill service.
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index b3f0629ea2d3..ea295de5909f 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -78,7 +78,6 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
@@ -97,6 +96,7 @@ import com.android.server.job.controllers.ContentObserverController;
import com.android.server.job.controllers.DeviceIdleJobsController;
import com.android.server.job.controllers.IdleController;
import com.android.server.job.controllers.JobStatus;
+import com.android.server.job.controllers.QuotaController;
import com.android.server.job.controllers.StateController;
import com.android.server.job.controllers.StorageController;
import com.android.server.job.controllers.TimeController;
@@ -245,11 +245,11 @@ public class JobSchedulerService extends com.android.server.SystemService
* Named indices into the STANDBY_BEATS array, for clarity in referring to
* specific buckets' bookkeeping.
*/
- static final int ACTIVE_INDEX = 0;
- static final int WORKING_INDEX = 1;
- static final int FREQUENT_INDEX = 2;
- static final int RARE_INDEX = 3;
- static final int NEVER_INDEX = 4;
+ public static final int ACTIVE_INDEX = 0;
+ public static final int WORKING_INDEX = 1;
+ public static final int FREQUENT_INDEX = 2;
+ public static final int RARE_INDEX = 3;
+ public static final int NEVER_INDEX = 4;
/**
* Bookkeeping about when jobs last run. We keep our own record in heartbeat time,
@@ -308,6 +308,10 @@ public class JobSchedulerService extends com.android.server.SystemService
try {
mConstants.updateConstantsLocked(Settings.Global.getString(mResolver,
Settings.Global.JOB_SCHEDULER_CONSTANTS));
+ for (int controller = 0; controller < mControllers.size(); controller++) {
+ final StateController sc = mControllers.get(controller);
+ sc.onConstantsUpdatedLocked();
+ }
} catch (IllegalArgumentException e) {
// Failed to parse the settings string, log this and move on
// with defaults.
@@ -315,8 +319,10 @@ public class JobSchedulerService extends com.android.server.SystemService
}
}
- // Reset the heartbeat alarm based on the new heartbeat duration
- setNextHeartbeatAlarm();
+ if (mConstants.USE_HEARTBEATS) {
+ // Reset the heartbeat alarm based on the new heartbeat duration
+ setNextHeartbeatAlarm();
+ }
}
}
@@ -352,6 +358,19 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final String KEY_STANDBY_RARE_BEATS = "standby_rare_beats";
private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
+ private static final String KEY_USE_HEARTBEATS = "use_heartbeats";
+ private static final String KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
+ "qc_allowed_time_per_period_ms";
+ private static final String KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
+ "qc_in_quota_buffer_ms";
+ private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
+ "qc_window_size_active_ms";
+ private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
+ "qc_window_size_working_ms";
+ private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
+ "qc_window_size_frequent_ms";
+ private static final String KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
+ "qc_window_size_rare_ms";
private static final int DEFAULT_MIN_IDLE_COUNT = 1;
private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -377,6 +396,19 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final int DEFAULT_STANDBY_RARE_BEATS = 130; // ~ 24 hours
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
+ private static final boolean DEFAULT_USE_HEARTBEATS = true;
+ private static final long DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
+ 10 * 60 * 1000L; // 10 minutes
+ private static final long DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
+ 30 * 1000L; // 30 seconds
+ private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
+ 10 * 60 * 1000L; // 10 minutes for ACTIVE -- ACTIVE apps can run jobs at any time
+ private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
+ 2 * 60 * 60 * 1000L; // 2 hours
+ private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
+ 8 * 60 * 60 * 1000L; // 8 hours
+ private static final long DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
+ 24 * 60 * 60 * 1000L; // 24 hours
/**
* Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -495,6 +527,54 @@ public class JobSchedulerService extends com.android.server.SystemService
* we consider matching it against a metered network.
*/
public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC;
+ /**
+ * Whether to use heartbeats or rolling window for quota management. True will use
+ * heartbeats, false will use a rolling window.
+ */
+ public boolean USE_HEARTBEATS = DEFAULT_USE_HEARTBEATS;
+
+ /** How much time each app will have to run jobs within their standby bucket window. */
+ public long QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
+ DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS;
+
+ /**
+ * How much time the package should have before transitioning from out-of-quota to in-quota.
+ * This should not affect processing if the package is already in-quota.
+ */
+ public long QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
+ DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS;
+
+ /**
+ * The quota window size of the particular standby bucket. Apps in this standby bucket are
+ * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * WINDOW_SIZE_MS.
+ */
+ public long QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
+ DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS;
+
+ /**
+ * The quota window size of the particular standby bucket. Apps in this standby bucket are
+ * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * WINDOW_SIZE_MS.
+ */
+ public long QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
+ DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS;
+
+ /**
+ * The quota window size of the particular standby bucket. Apps in this standby bucket are
+ * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * WINDOW_SIZE_MS.
+ */
+ public long QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
+ DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS;
+
+ /**
+ * The quota window size of the particular standby bucket. Apps in this standby bucket are
+ * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * WINDOW_SIZE_MS.
+ */
+ public long QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
+ DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -567,6 +647,25 @@ public class JobSchedulerService extends com.android.server.SystemService
DEFAULT_CONN_CONGESTION_DELAY_FRAC);
CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC,
DEFAULT_CONN_PREFETCH_RELAX_FRAC);
+ USE_HEARTBEATS = mParser.getBoolean(KEY_USE_HEARTBEATS, DEFAULT_USE_HEARTBEATS);
+ QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = mParser.getDurationMillis(
+ KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS,
+ DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS);
+ QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = mParser.getDurationMillis(
+ KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS,
+ DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS);
+ QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = mParser.getDurationMillis(
+ KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS,
+ DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS);
+ QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = mParser.getDurationMillis(
+ KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS,
+ DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS);
+ QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = mParser.getDurationMillis(
+ KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS,
+ DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS);
+ QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = mParser.getDurationMillis(
+ KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS,
+ DEFAULT_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS);
}
void dump(IndentingPrintWriter pw) {
@@ -600,6 +699,19 @@ public class JobSchedulerService extends com.android.server.SystemService
pw.println('}');
pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
+ pw.printPair(KEY_USE_HEARTBEATS, USE_HEARTBEATS).println();
+ pw.printPair(KEY_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS,
+ QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS).println();
+ pw.printPair(KEY_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS,
+ QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS).println();
+ pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS,
+ QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS).println();
+ pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS,
+ QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS).println();
+ pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS,
+ QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS).println();
+ pw.printPair(KEY_QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS,
+ QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS).println();
pw.decreaseIndent();
}
@@ -629,6 +741,23 @@ public class JobSchedulerService extends com.android.server.SystemService
}
proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC);
proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC);
+ proto.write(ConstantsProto.USE_HEARTBEATS, USE_HEARTBEATS);
+
+ final long qcToken = proto.start(ConstantsProto.QUOTA_CONTROLLER);
+ proto.write(ConstantsProto.QuotaController.ALLOWED_TIME_PER_PERIOD_MS,
+ QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS);
+ proto.write(ConstantsProto.QuotaController.IN_QUOTA_BUFFER_MS,
+ QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS);
+ proto.write(ConstantsProto.QuotaController.ACTIVE_WINDOW_SIZE_MS,
+ QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS);
+ proto.write(ConstantsProto.QuotaController.WORKING_WINDOW_SIZE_MS,
+ QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS);
+ proto.write(ConstantsProto.QuotaController.FREQUENT_WINDOW_SIZE_MS,
+ QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS);
+ proto.write(ConstantsProto.QuotaController.RARE_WINDOW_SIZE_MS,
+ QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS);
+ proto.end(qcToken);
+
proto.end(token);
}
}
@@ -1162,6 +1291,7 @@ public class JobSchedulerService extends com.android.server.SystemService
mControllers.add(new ContentObserverController(this));
mDeviceIdleJobsController = new DeviceIdleJobsController(this);
mControllers.add(mDeviceIdleJobsController);
+ mControllers.add(new QuotaController(this));
// If the job store determined that it can't yet reschedule persisted jobs,
// we need to start watching the clock.
@@ -1225,7 +1355,9 @@ public class JobSchedulerService extends com.android.server.SystemService
mAppStateTracker = Preconditions.checkNotNull(
LocalServices.getService(AppStateTracker.class));
- setNextHeartbeatAlarm();
+ if (mConstants.USE_HEARTBEATS) {
+ setNextHeartbeatAlarm();
+ }
// Register br for package removals and user removals.
final IntentFilter filter = new IntentFilter();
@@ -1869,6 +2001,9 @@ public class JobSchedulerService extends com.android.server.SystemService
// Intentionally does not touch the alarm timing
void advanceHeartbeatLocked(long beatsElapsed) {
+ if (!mConstants.USE_HEARTBEATS) {
+ return;
+ }
mHeartbeat += beatsElapsed;
if (DEBUG_STANDBY) {
Slog.v(TAG, "Advancing standby heartbeat by " + beatsElapsed
@@ -1904,6 +2039,9 @@ public class JobSchedulerService extends com.android.server.SystemService
void setNextHeartbeatAlarm() {
final long heartbeatLength;
synchronized (mLock) {
+ if (!mConstants.USE_HEARTBEATS) {
+ return;
+ }
heartbeatLength = mConstants.STANDBY_HEARTBEAT_TIME;
}
final long now = sElapsedRealtimeClock.millis();
@@ -1976,48 +2114,51 @@ public class JobSchedulerService extends com.android.server.SystemService
return false;
}
- // If the app is in a non-active standby bucket, make sure we've waited
- // an appropriate amount of time since the last invocation. During device-
- // wide parole, standby bucketing is ignored.
- //
- // Jobs in 'active' apps are not subject to standby, nor are jobs that are
- // specifically marked as exempt.
- if (DEBUG_STANDBY) {
- Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
- + " parole=" + mInParole + " active=" + job.uidActive
- + " exempt=" + job.getJob().isExemptedFromAppStandby());
- }
- if (!mInParole
- && !job.uidActive
- && !job.getJob().isExemptedFromAppStandby()) {
- final int bucket = job.getStandbyBucket();
+ if (mConstants.USE_HEARTBEATS) {
+ // If the app is in a non-active standby bucket, make sure we've waited
+ // an appropriate amount of time since the last invocation. During device-
+ // wide parole, standby bucketing is ignored.
+ //
+ // Jobs in 'active' apps are not subject to standby, nor are jobs that are
+ // specifically marked as exempt.
if (DEBUG_STANDBY) {
- Slog.v(TAG, " bucket=" + bucket + " heartbeat=" + mHeartbeat
- + " next=" + mNextBucketHeartbeat[bucket]);
- }
- if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
- // Only skip this job if the app is still waiting for the end of its nominal
- // bucket interval. Once it's waited that long, we let it go ahead and clear.
- // The final (NEVER) bucket is special; we never age those apps' jobs into
- // runnability.
- final long appLastRan = heartbeatWhenJobsLastRun(job);
- if (bucket >= mConstants.STANDBY_BEATS.length
- || (mHeartbeat > appLastRan
- && mHeartbeat < appLastRan + mConstants.STANDBY_BEATS[bucket])) {
- // TODO: log/trace that we're deferring the job due to bucketing if we hit this
- if (job.getWhenStandbyDeferred() == 0) {
+ Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
+ + " parole=" + mInParole + " active=" + job.uidActive
+ + " exempt=" + job.getJob().isExemptedFromAppStandby());
+ }
+ if (!mInParole
+ && !job.uidActive
+ && !job.getJob().isExemptedFromAppStandby()) {
+ final int bucket = job.getStandbyBucket();
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, " bucket=" + bucket + " heartbeat=" + mHeartbeat
+ + " next=" + mNextBucketHeartbeat[bucket]);
+ }
+ if (mHeartbeat < mNextBucketHeartbeat[bucket]) {
+ // Only skip this job if the app is still waiting for the end of its nominal
+ // bucket interval. Once it's waited that long, we let it go ahead and clear.
+ // The final (NEVER) bucket is special; we never age those apps' jobs into
+ // runnability.
+ final long appLastRan = heartbeatWhenJobsLastRun(job);
+ if (bucket >= mConstants.STANDBY_BEATS.length
+ || (mHeartbeat > appLastRan
+ && mHeartbeat < appLastRan + mConstants.STANDBY_BEATS[bucket])) {
+ // TODO: log/trace that we're deferring the job due to bucketing if we
+ // hit this
+ if (job.getWhenStandbyDeferred() == 0) {
+ if (DEBUG_STANDBY) {
+ Slog.v(TAG, "Bucket deferral: " + mHeartbeat + " < "
+ + (appLastRan + mConstants.STANDBY_BEATS[bucket])
+ + " for " + job);
+ }
+ job.setWhenStandbyDeferred(sElapsedRealtimeClock.millis());
+ }
+ return false;
+ } else {
if (DEBUG_STANDBY) {
- Slog.v(TAG, "Bucket deferral: " + mHeartbeat + " < "
- + (appLastRan + mConstants.STANDBY_BEATS[bucket])
- + " for " + job);
+ Slog.v(TAG, "Bucket deferred job aged into runnability at "
+ + mHeartbeat + " : " + job);
}
- job.setWhenStandbyDeferred(sElapsedRealtimeClock.millis());
- }
- return false;
- } else {
- if (DEBUG_STANDBY) {
- Slog.v(TAG, "Bucket deferred job aged into runnability at "
- + mHeartbeat + " : " + job);
}
}
}
@@ -2364,32 +2505,7 @@ public class JobSchedulerService extends com.android.server.SystemService
@Override
public void onAppIdleStateChanged(final String packageName, final @UserIdInt int userId,
boolean idle, int bucket, int reason) {
- final int uid = mLocalPM.getPackageUid(packageName,
- PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
- if (uid < 0) {
- if (DEBUG_STANDBY) {
- Slog.i(TAG, "App idle state change for unknown app "
- + packageName + "/" + userId);
- }
- return;
- }
-
- final int bucketIndex = standbyBucketToBucketIndex(bucket);
- // update job bookkeeping out of band
- BackgroundThread.getHandler().post(() -> {
- if (DEBUG_STANDBY) {
- Slog.i(TAG, "Moving uid " + uid + " to bucketIndex " + bucketIndex);
- }
- synchronized (mLock) {
- mJobs.forEachJobForSourceUid(uid, job -> {
- // double-check uid vs package name to disambiguate shared uids
- if (packageName.equals(job.getSourcePackageName())) {
- job.setStandbyBucket(bucketIndex);
- }
- });
- onControllerStateChanged();
- }
- });
+ // QuotaController handles this now.
}
@Override
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 35fc29ee69fc..6deecbd9a83b 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -77,6 +77,7 @@ public final class JobStatus {
static final int CONSTRAINT_CONNECTIVITY = 1<<28;
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<25;
+ static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24;
static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22;
// Soft override: ignore constraints like time that don't affect API availability
@@ -192,6 +193,10 @@ public final class JobStatus {
* Flag for {@link #trackingControllers}: the time controller is currently tracking this job.
*/
public static final int TRACKING_TIME = 1<<5;
+ /**
+ * Flag for {@link #trackingControllers}: the quota controller is currently tracking this job.
+ */
+ public static final int TRACKING_QUOTA = 1 << 6;
/**
* Bit mask of controllers that are currently tracking the job.
@@ -291,6 +296,9 @@ public final class JobStatus {
*/
private boolean mReadyNotRestrictedInBg;
+ /** The job is within its quota based on its standby bucket. */
+ private boolean mReadyWithinQuota;
+
/** Provide a handle to the service that this job will be run on. */
public int getServiceToken() {
return callingUid;
@@ -675,7 +683,6 @@ public final class JobStatus {
return baseHeartbeat;
}
- // Called only by the standby monitoring code
public void setStandbyBucket(int newBucket) {
standbyBucket = newBucket;
}
@@ -876,22 +883,27 @@ public final class JobStatus {
mPersistedUtcTimes = null;
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setChargingConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setBatteryNotLowConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_BATTERY_NOT_LOW, state);
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setStorageNotLowConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_STORAGE_NOT_LOW, state);
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setTimingDelayConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setDeadlineConstraintSatisfied(boolean state) {
if (setConstraintSatisfied(CONSTRAINT_DEADLINE, state)) {
// The constraint was changed. Update the ready flag.
@@ -901,18 +913,22 @@ public final class JobStatus {
return false;
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setIdleConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_IDLE, state);
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setConnectivityConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setContentTriggerConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setDeviceNotDozingConstraintSatisfied(boolean state, boolean whitelisted) {
dozeWhitelisted = whitelisted;
if (setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state)) {
@@ -923,6 +939,7 @@ public final class JobStatus {
return false;
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setBackgroundNotRestrictedConstraintSatisfied(boolean state) {
if (setConstraintSatisfied(CONSTRAINT_BACKGROUND_NOT_RESTRICTED, state)) {
// The constraint was changed. Update the ready flag.
@@ -932,6 +949,17 @@ public final class JobStatus {
return false;
}
+ /** @return true if the constraint was changed, false otherwise. */
+ boolean setQuotaConstraintSatisfied(boolean state) {
+ if (setConstraintSatisfied(CONSTRAINT_WITHIN_QUOTA, state)) {
+ // The constraint was changed. Update the ready flag.
+ mReadyWithinQuota = state;
+ return true;
+ }
+ return false;
+ }
+
+ /** @return true if the state was changed, false otherwise. */
boolean setUidActive(final boolean newActiveState) {
if (newActiveState != uidActive) {
uidActive = newActiveState;
@@ -940,6 +968,7 @@ public final class JobStatus {
return false; /* unchanged */
}
+ /** @return true if the constraint was changed, false otherwise. */
boolean setConstraintSatisfied(int constraint, boolean state) {
boolean old = (satisfiedConstraints&constraint) != 0;
if (old == state) {
@@ -978,9 +1007,13 @@ public final class JobStatus {
* @return Whether or not this job is ready to run, based on its requirements.
*/
public boolean isReady() {
- // Deadline constraint trumps other constraints (except for periodic jobs where deadline
- // is an implementation detail. A periodic job should only run if its constraints are
- // satisfied).
+ // Quota constraints trumps all other constraints.
+ if (!mReadyWithinQuota) {
+ return false;
+ }
+ // Deadline constraint trumps other constraints besides quota (except for periodic jobs
+ // where deadline is an implementation detail. A periodic job should only run if its
+ // constraints are satisfied).
// DeviceNotDozing implicit constraint must be satisfied
// NotRestrictedInBackground implicit constraint must be satisfied
return mReadyNotDozing && mReadyNotRestrictedInBg && (mReadyDeadlineSatisfied
@@ -1169,6 +1202,9 @@ public final class JobStatus {
if ((constraints&CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
pw.print(" BACKGROUND_NOT_RESTRICTED");
}
+ if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
+ pw.print(" WITHIN_QUOTA");
+ }
if (constraints != 0) {
pw.print(" [0x");
pw.print(Integer.toHexString(constraints));
@@ -1205,6 +1241,9 @@ public final class JobStatus {
if ((constraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_DEVICE_NOT_DOZING);
}
+ if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
+ proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_WITHIN_QUOTA);
+ }
}
private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) {
@@ -1237,6 +1276,13 @@ public final class JobStatus {
* Returns a bucket name based on the normalized bucket indices, not the AppStandby constants.
*/
String getBucketName() {
+ return bucketName(standbyBucket);
+ }
+
+ /**
+ * Returns a bucket name based on the normalized bucket indices, not the AppStandby constants.
+ */
+ static String bucketName(int standbyBucket) {
switch (standbyBucket) {
case 0: return "ACTIVE";
case 1: return "WORKING_SET";
@@ -1367,7 +1413,8 @@ public final class JobStatus {
dumpConstraints(pw, satisfiedConstraints);
pw.println();
pw.print(prefix); pw.print("Unsatisfied constraints:");
- dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints));
+ dumpConstraints(pw,
+ ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints));
pw.println();
if (dozeWhitelisted) {
pw.print(prefix); pw.println("Doze whitelisted: true");
@@ -1375,6 +1422,9 @@ public final class JobStatus {
if (uidActive) {
pw.print(prefix); pw.println("Uid: active");
}
+ if (job.isExemptedFromAppStandby()) {
+ pw.print(prefix); pw.println("Is exempted from app standby");
+ }
}
if (trackingControllers != 0) {
pw.print(prefix); pw.print("Tracking:");
@@ -1384,6 +1434,7 @@ public final class JobStatus {
if ((trackingControllers&TRACKING_IDLE) != 0) pw.print(" IDLE");
if ((trackingControllers&TRACKING_STORAGE) != 0) pw.print(" STORAGE");
if ((trackingControllers&TRACKING_TIME) != 0) pw.print(" TIME");
+ if ((trackingControllers & TRACKING_QUOTA) != 0) pw.print(" QUOTA");
pw.println();
}
@@ -1546,8 +1597,11 @@ public final class JobStatus {
if (full) {
dumpConstraints(proto, JobStatusDumpProto.SATISFIED_CONSTRAINTS, satisfiedConstraints);
dumpConstraints(proto, JobStatusDumpProto.UNSATISFIED_CONSTRAINTS,
- (requiredConstraints & ~satisfiedConstraints));
+ ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA) & ~satisfiedConstraints));
proto.write(JobStatusDumpProto.IS_DOZE_WHITELISTED, dozeWhitelisted);
+ proto.write(JobStatusDumpProto.IS_UID_ACTIVE, uidActive);
+ proto.write(JobStatusDumpProto.IS_EXEMPTED_FROM_APP_STANDBY,
+ job.isExemptedFromAppStandby());
}
// Tracking controllers
@@ -1575,6 +1629,10 @@ public final class JobStatus {
proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
JobStatusDumpProto.TRACKING_TIME);
}
+ if ((trackingControllers & TRACKING_QUOTA) != 0) {
+ proto.write(JobStatusDumpProto.TRACKING_CONTROLLERS,
+ JobStatusDumpProto.TRACKING_QUOTA);
+ }
// Implicit constraints
final long icToken = proto.start(JobStatusDumpProto.IMPLICIT_CONSTRAINTS);
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
new file mode 100644
index 000000000000..f73ffac96dfa
--- /dev/null
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -0,0 +1,1299 @@
+/*
+ * Copyright (C) 2018 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.job.controllers;
+
+import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
+import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
+import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
+import static com.android.server.job.JobSchedulerService.RARE_INDEX;
+import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AlarmManager;
+import android.app.usage.UsageStatsManagerInternal;
+import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateControllerProto;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * Controller that tracks whether a package has exceeded its standby bucket quota.
+ *
+ * Each job in each bucket is given 10 minutes to run within its respective time window. Active
+ * jobs can run indefinitely, working set jobs can run for 10 minutes within a 2 hour window,
+ * frequent jobs get to run 10 minutes in an 8 hour window, and rare jobs get to run 10 minutes in
+ * a 24 hour window. The windows are rolling, so as soon as a job would have some quota based on its
+ * bucket, it will be eligible to run. When a job's bucket changes, its new quota is immediately
+ * applied to it.
+ *
+ * Test: atest com.android.server.job.controllers.QuotaControllerTest
+ */
+public final class QuotaController extends StateController {
+ private static final String TAG = "JobScheduler.Quota";
+ private static final boolean DEBUG = JobSchedulerService.DEBUG
+ || Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final long MINUTE_IN_MILLIS = 60 * 1000L;
+
+ private static final String ALARM_TAG_CLEANUP = "*job.cleanup*";
+ private static final String ALARM_TAG_QUOTA_CHECK = "*job.quota_check*";
+
+ /**
+ * A sparse array of ArrayMaps, which is suitable for holding (userId, packageName)->object
+ * associations.
+ */
+ private static class UserPackageMap<T> {
+ private final SparseArray<ArrayMap<String, T>> mData = new SparseArray<>();
+
+ public void add(int userId, @NonNull String packageName, @Nullable T obj) {
+ ArrayMap<String, T> data = mData.get(userId);
+ if (data == null) {
+ data = new ArrayMap<String, T>();
+ mData.put(userId, data);
+ }
+ data.put(packageName, obj);
+ }
+
+ @Nullable
+ public T get(int userId, @NonNull String packageName) {
+ ArrayMap<String, T> data = mData.get(userId);
+ if (data != null) {
+ return data.get(packageName);
+ }
+ return null;
+ }
+
+ /** Returns the userId at the given index. */
+ public int keyAt(int index) {
+ return mData.keyAt(index);
+ }
+
+ /** Returns the package name at the given index. */
+ @NonNull
+ public String keyAt(int userIndex, int packageIndex) {
+ return mData.valueAt(userIndex).keyAt(packageIndex);
+ }
+
+ /** Returns the size of the outer (userId) array. */
+ public int numUsers() {
+ return mData.size();
+ }
+
+ public int numPackagesForUser(int userId) {
+ ArrayMap<String, T> data = mData.get(userId);
+ return data == null ? 0 : data.size();
+ }
+
+ /** Returns the value T at the given user and index. */
+ @Nullable
+ public T valueAt(int userIndex, int packageIndex) {
+ return mData.valueAt(userIndex).valueAt(packageIndex);
+ }
+
+ public void forEach(Consumer<T> consumer) {
+ for (int i = numUsers() - 1; i >= 0; --i) {
+ ArrayMap<String, T> data = mData.valueAt(i);
+ for (int j = data.size() - 1; j >= 0; --j) {
+ consumer.accept(data.valueAt(j));
+ }
+ }
+ }
+ }
+
+ /**
+ * Standardize the output of userId-packageName combo.
+ */
+ private static String string(int userId, String packageName) {
+ return "<" + userId + ">" + packageName;
+ }
+
+ @VisibleForTesting
+ static final class Package {
+ public final String packageName;
+ public final int userId;
+
+ Package(int userId, String packageName) {
+ this.userId = userId;
+ this.packageName = packageName;
+ }
+
+ @Override
+ public String toString() {
+ return string(userId, packageName);
+ }
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+
+ proto.write(StateControllerProto.QuotaController.Package.USER_ID, userId);
+ proto.write(StateControllerProto.QuotaController.Package.NAME, packageName);
+
+ proto.end(token);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Package) {
+ Package other = (Package) obj;
+ return userId == other.userId && Objects.equals(packageName, other.packageName);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return packageName.hashCode() + userId;
+ }
+ }
+
+ /** List of all tracked jobs keyed by source package-userId combo. */
+ private final UserPackageMap<ArraySet<JobStatus>> mTrackedJobs = new UserPackageMap<>();
+
+ /** Timer for each package-userId combo. */
+ private final UserPackageMap<Timer> mPkgTimers = new UserPackageMap<>();
+
+ /** List of all timing sessions for a package-userId combo, in chronological order. */
+ private final UserPackageMap<List<TimingSession>> mTimingSessions = new UserPackageMap<>();
+
+ /**
+ * List of alarm listeners for each package that listen for when each package comes back within
+ * quota.
+ */
+ private final UserPackageMap<QcAlarmListener> mInQuotaAlarmListeners = new UserPackageMap<>();
+
+ private final AlarmManager mAlarmManager;
+ private final ChargingTracker mChargeTracker;
+ private final Handler mHandler;
+
+ private volatile boolean mInParole;
+
+ /**
+ * If the QuotaController should throttle apps based on their standby bucket and job activity.
+ * If false, all jobs will have their CONSTRAINT_WITHIN_QUOTA bit set to true immediately and
+ * indefinitely.
+ */
+ private boolean mShouldThrottle;
+
+ /** How much time each app will have to run jobs within their standby bucket window. */
+ private long mAllowedTimePerPeriodMs = 10 * MINUTE_IN_MILLIS;
+
+ /**
+ * How much time the package should have before transitioning from out-of-quota to in-quota.
+ * This should not affect processing if the package is already in-quota.
+ */
+ private long mQuotaBufferMs = 30 * 1000L; // 30 seconds
+
+ private long mNextCleanupTimeElapsed = 0;
+ private final AlarmManager.OnAlarmListener mSessionCleanupAlarmListener =
+ new AlarmManager.OnAlarmListener() {
+ @Override
+ public void onAlarm() {
+ mHandler.obtainMessage(MSG_CLEAN_UP_SESSIONS).sendToTarget();
+ }
+ };
+
+ /**
+ * The rolling window size for each standby bucket. Within each window, an app will have 10
+ * minutes to run its jobs.
+ */
+ private final long[] mBucketPeriodsMs = new long[] {
+ 10 * MINUTE_IN_MILLIS, // 10 minutes for ACTIVE -- ACTIVE apps can run jobs at any time
+ 2 * 60 * MINUTE_IN_MILLIS, // 2 hours for WORKING
+ 8 * 60 * MINUTE_IN_MILLIS, // 8 hours for FREQUENT
+ 24 * 60 * MINUTE_IN_MILLIS // 24 hours for RARE
+ };
+
+ /** The maximum period any bucket can have. */
+ private static final long MAX_PERIOD_MS = 24 * 60 * MINUTE_IN_MILLIS;
+
+ /** A package has reached its quota. The message should contain a {@link Package} object. */
+ private static final int MSG_REACHED_QUOTA = 0;
+ /** Drop any old timing sessions. */
+ private static final int MSG_CLEAN_UP_SESSIONS = 1;
+ /** Check if a package is now within its quota. */
+ private static final int MSG_CHECK_PACKAGE = 2;
+
+ public QuotaController(JobSchedulerService service) {
+ super(service);
+ mHandler = new QcHandler(mContext.getMainLooper());
+ mChargeTracker = new ChargingTracker();
+ mChargeTracker.startTracking();
+ mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
+ // Set up the app standby bucketing tracker
+ UsageStatsManagerInternal usageStats = LocalServices.getService(
+ UsageStatsManagerInternal.class);
+ usageStats.addAppIdleStateChangeListener(new StandbyTracker());
+
+ onConstantsUpdatedLocked();
+ }
+
+ @Override
+ public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
+ // Still need to track jobs even if mShouldThrottle is false in case it's set to true at
+ // some point.
+ ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUserId(),
+ jobStatus.getSourcePackageName());
+ if (jobs == null) {
+ jobs = new ArraySet<>();
+ mTrackedJobs.add(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), jobs);
+ }
+ jobs.add(jobStatus);
+ jobStatus.setTrackingController(JobStatus.TRACKING_QUOTA);
+ jobStatus.setQuotaConstraintSatisfied(!mShouldThrottle || isWithinQuotaLocked(jobStatus));
+ }
+
+ @Override
+ public void prepareForExecutionLocked(JobStatus jobStatus) {
+ if (DEBUG) Slog.d(TAG, "Prepping for " + jobStatus.toShortString());
+ final int userId = jobStatus.getSourceUserId();
+ final String packageName = jobStatus.getSourcePackageName();
+ Timer timer = mPkgTimers.get(userId, packageName);
+ if (timer == null) {
+ timer = new Timer(userId, packageName);
+ mPkgTimers.add(userId, packageName, timer);
+ }
+ timer.startTrackingJob(jobStatus);
+ }
+
+ @Override
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
+ boolean forUpdate) {
+ if (jobStatus.clearTrackingController(JobStatus.TRACKING_QUOTA)) {
+ Timer timer = mPkgTimers.get(jobStatus.getSourceUserId(),
+ jobStatus.getSourcePackageName());
+ if (timer != null) {
+ timer.stopTrackingJob(jobStatus);
+ }
+ ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUserId(),
+ jobStatus.getSourcePackageName());
+ if (jobs != null) {
+ jobs.remove(jobStatus);
+ }
+ }
+ }
+
+ @Override
+ public void onConstantsUpdatedLocked() {
+ boolean changed = false;
+ if (mShouldThrottle == mConstants.USE_HEARTBEATS) {
+ mShouldThrottle = !mConstants.USE_HEARTBEATS;
+ changed = true;
+ }
+ long newAllowedTimeMs = Math.min(MAX_PERIOD_MS,
+ Math.max(MINUTE_IN_MILLIS, mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS));
+ if (mAllowedTimePerPeriodMs != newAllowedTimeMs) {
+ mAllowedTimePerPeriodMs = newAllowedTimeMs;
+ changed = true;
+ }
+ long newQuotaBufferMs = Math.max(0,
+ Math.min(5 * MINUTE_IN_MILLIS, mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS));
+ if (mQuotaBufferMs != newQuotaBufferMs) {
+ mQuotaBufferMs = newQuotaBufferMs;
+ changed = true;
+ }
+ long newActivePeriodMs = Math.max(mAllowedTimePerPeriodMs,
+ Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS));
+ if (mBucketPeriodsMs[ACTIVE_INDEX] != newActivePeriodMs) {
+ mBucketPeriodsMs[ACTIVE_INDEX] = newActivePeriodMs;
+ changed = true;
+ }
+ long newWorkingPeriodMs = Math.max(mAllowedTimePerPeriodMs,
+ Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS));
+ if (mBucketPeriodsMs[WORKING_INDEX] != newWorkingPeriodMs) {
+ mBucketPeriodsMs[WORKING_INDEX] = newWorkingPeriodMs;
+ changed = true;
+ }
+ long newFrequentPeriodMs = Math.max(mAllowedTimePerPeriodMs,
+ Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS));
+ if (mBucketPeriodsMs[FREQUENT_INDEX] != newFrequentPeriodMs) {
+ mBucketPeriodsMs[FREQUENT_INDEX] = newFrequentPeriodMs;
+ changed = true;
+ }
+ long newRarePeriodMs = Math.max(mAllowedTimePerPeriodMs,
+ Math.min(MAX_PERIOD_MS, mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS));
+ if (mBucketPeriodsMs[RARE_INDEX] != newRarePeriodMs) {
+ mBucketPeriodsMs[RARE_INDEX] = newRarePeriodMs;
+ changed = true;
+ }
+
+ if (changed) {
+ // Update job bookkeeping out of band.
+ BackgroundThread.getHandler().post(() -> {
+ synchronized (mLock) {
+ maybeUpdateAllConstraintsLocked();
+ }
+ });
+ }
+ }
+
+ /**
+ * Returns an appropriate standby bucket for the job, taking into account any standby
+ * exemptions.
+ */
+ private int getEffectiveStandbyBucket(@NonNull final JobStatus jobStatus) {
+ if (jobStatus.uidActive || jobStatus.getJob().isExemptedFromAppStandby()) {
+ // Treat these cases as if they're in the ACTIVE bucket so that they get throttled
+ // like other ACTIVE apps.
+ return ACTIVE_INDEX;
+ }
+ return jobStatus.getStandbyBucket();
+ }
+
+ private boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
+ final int standbyBucket = getEffectiveStandbyBucket(jobStatus);
+ return isWithinQuotaLocked(jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(),
+ standbyBucket);
+ }
+
+ private boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
+ final int standbyBucket) {
+ if (standbyBucket == NEVER_INDEX) return false;
+ if (standbyBucket == ACTIVE_INDEX) return true;
+ // This check is needed in case the flag is toggled after a job has been registered.
+ if (!mShouldThrottle) return true;
+
+ // Quota constraint is not enforced while charging or when parole is on.
+ return mChargeTracker.isCharging() || mInParole
+ || getRemainingExecutionTimeLocked(userId, packageName, standbyBucket) > 0;
+ }
+
+ @VisibleForTesting
+ long getRemainingExecutionTimeLocked(@NonNull final JobStatus jobStatus) {
+ return getRemainingExecutionTimeLocked(jobStatus.getSourceUserId(),
+ jobStatus.getSourcePackageName(),
+ getEffectiveStandbyBucket(jobStatus));
+ }
+
+ @VisibleForTesting
+ long getRemainingExecutionTimeLocked(final int userId, @NonNull final String packageName) {
+ final int standbyBucket = JobSchedulerService.standbyBucketForPackage(packageName,
+ userId, sElapsedRealtimeClock.millis());
+ return getRemainingExecutionTimeLocked(userId, packageName, standbyBucket);
+ }
+
+ /**
+ * Returns the amount of time, in milliseconds, that this job has remaining to run based on its
+ * current standby bucket. Time remaining could be negative if the app was moved from a less
+ * restricted to a more restricted bucket.
+ */
+ private long getRemainingExecutionTimeLocked(final int userId,
+ @NonNull final String packageName, final int standbyBucket) {
+ if (standbyBucket == NEVER_INDEX) {
+ return 0;
+ }
+ final long bucketWindowSizeMs = mBucketPeriodsMs[standbyBucket];
+ final long trailingRunDurationMs = getTrailingExecutionTimeLocked(
+ userId, packageName, bucketWindowSizeMs);
+ return mAllowedTimePerPeriodMs - trailingRunDurationMs;
+ }
+
+ /** Returns how long the uid has had jobs running within the most recent window. */
+ @VisibleForTesting
+ long getTrailingExecutionTimeLocked(final int userId, @NonNull final String packageName,
+ final long windowSizeMs) {
+ long totalTime = 0;
+
+ Timer timer = mPkgTimers.get(userId, packageName);
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ if (timer != null && timer.isActive()) {
+ totalTime = timer.getCurrentDuration(nowElapsed);
+ }
+
+ List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
+ if (sessions == null || sessions.size() == 0) {
+ return totalTime;
+ }
+
+ final long startElapsed = nowElapsed - windowSizeMs;
+ // Sessions are non-overlapping and in order of occurrence, so iterating backwards will get
+ // the most recent ones.
+ for (int i = sessions.size() - 1; i >= 0; --i) {
+ TimingSession session = sessions.get(i);
+ if (startElapsed < session.startTimeElapsed) {
+ totalTime += session.endTimeElapsed - session.startTimeElapsed;
+ } else if (startElapsed < session.endTimeElapsed) {
+ // The session started before the window but ended within the window. Only include
+ // the portion that was within the window.
+ totalTime += session.endTimeElapsed - startElapsed;
+ } else {
+ // This session ended before the window. No point in going any further.
+ return totalTime;
+ }
+ }
+ return totalTime;
+ }
+
+ @VisibleForTesting
+ void saveTimingSession(final int userId, @NonNull final String packageName,
+ @NonNull final TimingSession session) {
+ synchronized (mLock) {
+ List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
+ if (sessions == null) {
+ sessions = new ArrayList<>();
+ mTimingSessions.add(userId, packageName, sessions);
+ }
+ sessions.add(session);
+
+ maybeScheduleCleanupAlarmLocked();
+ }
+ }
+
+ private final class EarliestEndTimeFunctor implements Consumer<List<TimingSession>> {
+ public long earliestEndElapsed = Long.MAX_VALUE;
+
+ @Override
+ public void accept(List<TimingSession> sessions) {
+ if (sessions != null && sessions.size() > 0) {
+ earliestEndElapsed = Math.min(earliestEndElapsed, sessions.get(0).endTimeElapsed);
+ }
+ }
+
+ void reset() {
+ earliestEndElapsed = Long.MAX_VALUE;
+ }
+ }
+
+ private final EarliestEndTimeFunctor mEarliestEndTimeFunctor = new EarliestEndTimeFunctor();
+
+ /** Schedule a cleanup alarm if necessary and there isn't already one scheduled. */
+ @VisibleForTesting
+ void maybeScheduleCleanupAlarmLocked() {
+ if (mNextCleanupTimeElapsed > sElapsedRealtimeClock.millis()) {
+ // There's already an alarm scheduled. Just stick with that one. There's no way we'll
+ // end up scheduling an earlier alarm.
+ if (DEBUG) {
+ Slog.v(TAG, "Not scheduling cleanup since there's already one at "
+ + mNextCleanupTimeElapsed + " (in " + (mNextCleanupTimeElapsed
+ - sElapsedRealtimeClock.millis()) + "ms)");
+ }
+ return;
+ }
+ mEarliestEndTimeFunctor.reset();
+ mTimingSessions.forEach(mEarliestEndTimeFunctor);
+ final long earliestEndElapsed = mEarliestEndTimeFunctor.earliestEndElapsed;
+ if (earliestEndElapsed == Long.MAX_VALUE) {
+ // Couldn't find a good time to clean up. Maybe this was called after we deleted all
+ // timing sessions.
+ if (DEBUG) Slog.d(TAG, "Didn't find a time to schedule cleanup");
+ return;
+ }
+ // Need to keep sessions for all apps up to the max period, regardless of their current
+ // standby bucket.
+ long nextCleanupElapsed = earliestEndElapsed + MAX_PERIOD_MS;
+ if (nextCleanupElapsed - mNextCleanupTimeElapsed <= 10 * MINUTE_IN_MILLIS) {
+ // No need to clean up too often. Delay the alarm if the next cleanup would be too soon
+ // after it.
+ nextCleanupElapsed += 10 * MINUTE_IN_MILLIS;
+ }
+ mNextCleanupTimeElapsed = nextCleanupElapsed;
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, nextCleanupElapsed, ALARM_TAG_CLEANUP,
+ mSessionCleanupAlarmListener, mHandler);
+ if (DEBUG) Slog.d(TAG, "Scheduled next cleanup for " + mNextCleanupTimeElapsed);
+ }
+
+ private void handleNewChargingStateLocked() {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ final boolean isCharging = mChargeTracker.isCharging();
+ if (DEBUG) Slog.d(TAG, "handleNewChargingStateLocked: " + isCharging);
+ // Deal with Timers first.
+ mPkgTimers.forEach((t) -> t.onChargingChanged(nowElapsed, isCharging));
+ // Now update jobs.
+ maybeUpdateAllConstraintsLocked();
+ }
+
+ private void maybeUpdateAllConstraintsLocked() {
+ boolean changed = false;
+ for (int u = 0; u < mTrackedJobs.numUsers(); ++u) {
+ final int userId = mTrackedJobs.keyAt(u);
+ for (int p = 0; p < mTrackedJobs.numPackagesForUser(userId); ++p) {
+ final String packageName = mTrackedJobs.keyAt(u, p);
+ changed |= maybeUpdateConstraintForPkgLocked(userId, packageName);
+ }
+ }
+ if (changed) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ }
+
+ /**
+ * Update the CONSTRAINT_WITHIN_QUOTA bit for all of the Jobs for a given package.
+ *
+ * @return true if at least one job had its bit changed
+ */
+ private boolean maybeUpdateConstraintForPkgLocked(final int userId,
+ @NonNull final String packageName) {
+ ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, packageName);
+ if (jobs == null || jobs.size() == 0) {
+ return false;
+ }
+
+ // Quota is the same for all jobs within a package.
+ final int realStandbyBucket = jobs.valueAt(0).getStandbyBucket();
+ final boolean realInQuota = isWithinQuotaLocked(userId, packageName, realStandbyBucket);
+ boolean changed = false;
+ for (int i = jobs.size() - 1; i >= 0; --i) {
+ final JobStatus js = jobs.valueAt(i);
+ if (realStandbyBucket == getEffectiveStandbyBucket(js)) {
+ changed |= js.setQuotaConstraintSatisfied(realInQuota);
+ } else {
+ // This job is somehow exempted. Need to determine its own quota status.
+ changed |= js.setQuotaConstraintSatisfied(isWithinQuotaLocked(js));
+ }
+ }
+ if (!realInQuota) {
+ // Don't want to use the effective standby bucket here since that bump the bucket to
+ // ACTIVE for one of the jobs, which doesn't help with other jobs that aren't
+ // exempted.
+ maybeScheduleStartAlarmLocked(userId, packageName, realStandbyBucket);
+ } else {
+ QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
+ if (alarmListener != null) {
+ mAlarmManager.cancel(alarmListener);
+ // Set the trigger time to 0 so that the alarm doesn't think it's still waiting.
+ alarmListener.setTriggerTime(0);
+ }
+ }
+ return changed;
+ }
+
+ /**
+ * Maybe schedule a non-wakeup alarm for the next time this package will have quota to run
+ * again. This should only be called if the package is already out of quota.
+ */
+ @VisibleForTesting
+ void maybeScheduleStartAlarmLocked(final int userId, @NonNull final String packageName,
+ final int standbyBucket) {
+ final String pkgString = string(userId, packageName);
+ if (standbyBucket == NEVER_INDEX) {
+ return;
+ } else if (standbyBucket == ACTIVE_INDEX) {
+ // ACTIVE apps are "always" in quota.
+ if (DEBUG) {
+ Slog.w(TAG, "maybeScheduleStartAlarmLocked called for " + pkgString
+ + " even though it is active");
+ }
+ mHandler.obtainMessage(MSG_CHECK_PACKAGE, userId, 0, packageName).sendToTarget();
+
+ QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
+ if (alarmListener != null) {
+ // Cancel any pending alarm.
+ mAlarmManager.cancel(alarmListener);
+ // Set the trigger time to 0 so that the alarm doesn't think it's still waiting.
+ alarmListener.setTriggerTime(0);
+ }
+ return;
+ }
+
+ List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
+ if (sessions == null || sessions.size() == 0) {
+ // If there are no sessions, then the job is probably in quota.
+ if (DEBUG) {
+ Slog.wtf(TAG, "maybeScheduleStartAlarmLocked called for " + pkgString
+ + " even though it is likely within its quota.");
+ }
+ mHandler.obtainMessage(MSG_CHECK_PACKAGE, userId, 0, packageName).sendToTarget();
+ return;
+ }
+
+ final long bucketWindowSizeMs = mBucketPeriodsMs[standbyBucket];
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ // How far back we need to look.
+ final long startElapsed = nowElapsed - bucketWindowSizeMs;
+
+ long totalTime = 0;
+ long cutoffTimeElapsed = nowElapsed;
+ for (int i = sessions.size() - 1; i >= 0; i--) {
+ TimingSession session = sessions.get(i);
+ if (startElapsed < session.startTimeElapsed) {
+ cutoffTimeElapsed = session.startTimeElapsed;
+ totalTime += session.endTimeElapsed - session.startTimeElapsed;
+ } else if (startElapsed < session.endTimeElapsed) {
+ // The session started before the window but ended within the window. Only
+ // include the portion that was within the window.
+ cutoffTimeElapsed = startElapsed;
+ totalTime += session.endTimeElapsed - startElapsed;
+ } else {
+ // This session ended before the window. No point in going any further.
+ break;
+ }
+ if (totalTime >= mAllowedTimePerPeriodMs) {
+ break;
+ }
+ }
+ if (totalTime < mAllowedTimePerPeriodMs) {
+ // Already in quota. Why was this method called?
+ if (DEBUG) {
+ Slog.w(TAG, "maybeScheduleStartAlarmLocked called for " + pkgString
+ + " even though it already has " + (mAllowedTimePerPeriodMs - totalTime)
+ + "ms in its quota.");
+ }
+ mHandler.obtainMessage(MSG_CHECK_PACKAGE, userId, 0, packageName).sendToTarget();
+ return;
+ }
+
+ QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
+ if (alarmListener == null) {
+ alarmListener = new QcAlarmListener(userId, packageName);
+ mInQuotaAlarmListeners.add(userId, packageName, alarmListener);
+ }
+
+ // We add all the way back to the beginning of a session (or the window) even when we don't
+ // need to (in order to simplify the for loop above), so there might be some extra we
+ // need to add back.
+ final long extraTimeMs = totalTime - mAllowedTimePerPeriodMs;
+ // The time this app will have quota again.
+ final long inQuotaTimeElapsed =
+ cutoffTimeElapsed + extraTimeMs + mQuotaBufferMs + bucketWindowSizeMs;
+ // Only schedule the alarm if:
+ // 1. There isn't one currently scheduled
+ // 2. The new alarm is significantly earlier than the previous alarm (which could be the
+ // case if the package moves into a higher standby bucket). If it's earlier but not
+ // significantly so, then we essentially delay the job a few extra minutes.
+ // 3. The alarm is after the current alarm by more than the quota buffer.
+ // TODO: this might be overengineering. Simplify if proven safe.
+ if (!alarmListener.isWaiting()
+ || inQuotaTimeElapsed < alarmListener.getTriggerTimeElapsed() - 3 * MINUTE_IN_MILLIS
+ || alarmListener.getTriggerTimeElapsed() < inQuotaTimeElapsed - mQuotaBufferMs) {
+ if (DEBUG) Slog.d(TAG, "Scheduling start alarm for " + pkgString);
+ // If the next time this app will have quota is at least 3 minutes before the
+ // alarm is supposed to go off, reschedule the alarm.
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, inQuotaTimeElapsed,
+ ALARM_TAG_QUOTA_CHECK, alarmListener, mHandler);
+ alarmListener.setTriggerTime(inQuotaTimeElapsed);
+ }
+ }
+
+ private final class ChargingTracker extends BroadcastReceiver {
+ /**
+ * Track whether we're charging. This has a slightly different definition than that of
+ * BatteryController.
+ */
+ private boolean mCharging;
+
+ ChargingTracker() {
+ }
+
+ public void startTracking() {
+ IntentFilter filter = new IntentFilter();
+
+ // Charging/not charging.
+ filter.addAction(BatteryManager.ACTION_CHARGING);
+ filter.addAction(BatteryManager.ACTION_DISCHARGING);
+ mContext.registerReceiver(this, filter);
+
+ // Initialise tracker state.
+ BatteryManagerInternal batteryManagerInternal =
+ LocalServices.getService(BatteryManagerInternal.class);
+ mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
+ }
+
+ public boolean isCharging() {
+ return mCharging;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mLock) {
+ final String action = intent.getAction();
+ if (BatteryManager.ACTION_CHARGING.equals(action)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received charging intent, fired @ "
+ + sElapsedRealtimeClock.millis());
+ }
+ mCharging = true;
+ handleNewChargingStateLocked();
+ } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Disconnected from power.");
+ }
+ mCharging = false;
+ handleNewChargingStateLocked();
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static final class TimingSession {
+ // Start timestamp in elapsed realtime timebase.
+ public final long startTimeElapsed;
+ // End timestamp in elapsed realtime timebase.
+ public final long endTimeElapsed;
+ // How many jobs ran during this session.
+ public final int jobCount;
+
+ TimingSession(long startElapsed, long endElapsed, int jobCount) {
+ this.startTimeElapsed = startElapsed;
+ this.endTimeElapsed = endElapsed;
+ this.jobCount = jobCount;
+ }
+
+ @Override
+ public String toString() {
+ return "TimingSession{" + startTimeElapsed + "->" + endTimeElapsed + ", " + jobCount
+ + "}";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof TimingSession) {
+ TimingSession other = (TimingSession) obj;
+ return startTimeElapsed == other.startTimeElapsed
+ && endTimeElapsed == other.endTimeElapsed
+ && jobCount == other.jobCount;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(new long[] {startTimeElapsed, endTimeElapsed, jobCount});
+ }
+
+ public void dump(IndentingPrintWriter pw) {
+ pw.print(startTimeElapsed);
+ pw.print(" -> ");
+ pw.print(endTimeElapsed);
+ pw.print(" (");
+ pw.print(endTimeElapsed - startTimeElapsed);
+ pw.print("), ");
+ pw.print(jobCount);
+ pw.print(" jobs.");
+ pw.println();
+ }
+
+ public void dump(@NonNull ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+
+ proto.write(StateControllerProto.QuotaController.TimingSession.START_TIME_ELAPSED,
+ startTimeElapsed);
+ proto.write(StateControllerProto.QuotaController.TimingSession.END_TIME_ELAPSED,
+ endTimeElapsed);
+ proto.write(StateControllerProto.QuotaController.TimingSession.JOB_COUNT, jobCount);
+
+ proto.end(token);
+ }
+ }
+
+ private final class Timer {
+ private final Package mPkg;
+
+ // List of jobs currently running for this package.
+ private final ArraySet<JobStatus> mRunningJobs = new ArraySet<>();
+ private long mStartTimeElapsed;
+ private int mJobCount;
+
+ Timer(int userId, String packageName) {
+ mPkg = new Package(userId, packageName);
+ }
+
+ void startTrackingJob(@NonNull JobStatus jobStatus) {
+ if (DEBUG) Slog.v(TAG, "Starting to track " + jobStatus.toShortString());
+ synchronized (mLock) {
+ // Always track jobs, even when charging.
+ mRunningJobs.add(jobStatus);
+ if (!mChargeTracker.isCharging()) {
+ mJobCount++;
+ if (mRunningJobs.size() == 1) {
+ // Started tracking the first job.
+ mStartTimeElapsed = sElapsedRealtimeClock.millis();
+ scheduleCutoff();
+ }
+ }
+ }
+ }
+
+ void stopTrackingJob(@NonNull JobStatus jobStatus) {
+ if (DEBUG) Slog.v(TAG, "Stopping tracking of " + jobStatus.toShortString());
+ synchronized (mLock) {
+ if (mRunningJobs.size() == 0) {
+ // maybeStopTrackingJobLocked can be called when an app cancels a job, so a
+ // timer may not be running when it's asked to stop tracking a job.
+ if (DEBUG) {
+ Slog.d(TAG, "Timer isn't tracking any jobs but still told to stop");
+ }
+ return;
+ }
+ mRunningJobs.remove(jobStatus);
+ if (!mChargeTracker.isCharging() && mRunningJobs.size() == 0) {
+ emitSessionLocked(sElapsedRealtimeClock.millis());
+ cancelCutoff();
+ }
+ }
+ }
+
+ private void emitSessionLocked(long nowElapsed) {
+ if (mJobCount <= 0) {
+ // Nothing to emit.
+ return;
+ }
+ TimingSession ts = new TimingSession(mStartTimeElapsed, nowElapsed, mJobCount);
+ saveTimingSession(mPkg.userId, mPkg.packageName, ts);
+ mJobCount = 0;
+ // Don't reset the tracked jobs list as we need to keep tracking the current number
+ // of jobs.
+ // However, cancel the currently scheduled cutoff since it's not currently useful.
+ cancelCutoff();
+ }
+
+ /**
+ * Returns true if the Timer is actively tracking, as opposed to passively ref counting
+ * during charging.
+ */
+ public boolean isActive() {
+ synchronized (mLock) {
+ return mJobCount > 0;
+ }
+ }
+
+ long getCurrentDuration(long nowElapsed) {
+ synchronized (mLock) {
+ return !isActive() ? 0 : nowElapsed - mStartTimeElapsed;
+ }
+ }
+
+ void onChargingChanged(long nowElapsed, boolean isCharging) {
+ synchronized (mLock) {
+ if (isCharging) {
+ emitSessionLocked(nowElapsed);
+ } else {
+ // Start timing from unplug.
+ if (mRunningJobs.size() > 0) {
+ mStartTimeElapsed = nowElapsed;
+ // NOTE: this does have the unfortunate consequence that if the device is
+ // repeatedly plugged in and unplugged, the job count for a package may be
+ // artificially high.
+ mJobCount = mRunningJobs.size();
+ // Schedule cutoff since we're now actively tracking for quotas again.
+ scheduleCutoff();
+ }
+ }
+ }
+ }
+
+ void rescheduleCutoff() {
+ cancelCutoff();
+ scheduleCutoff();
+ }
+
+ private void scheduleCutoff() {
+ // Each package can only be in one standby bucket, so we only need to have one
+ // message per timer. We only need to reschedule when restarting timer or when
+ // standby bucket changes.
+ synchronized (mLock) {
+ if (!isActive()) {
+ return;
+ }
+ Message msg = mHandler.obtainMessage(MSG_REACHED_QUOTA, mPkg);
+ final long timeRemainingMs = getRemainingExecutionTimeLocked(mPkg.userId,
+ mPkg.packageName);
+ if (DEBUG) {
+ Slog.i(TAG, "Job for " + mPkg + " has " + timeRemainingMs + "ms left.");
+ }
+ // If the job was running the entire time, then the system would be up, so it's
+ // fine to use uptime millis for these messages.
+ mHandler.sendMessageDelayed(msg, timeRemainingMs);
+ }
+ }
+
+ private void cancelCutoff() {
+ mHandler.removeMessages(MSG_REACHED_QUOTA, mPkg);
+ }
+
+ public void dump(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
+ pw.print("Timer{");
+ pw.print(mPkg);
+ pw.print("} ");
+ if (isActive()) {
+ pw.print("started at ");
+ pw.print(mStartTimeElapsed);
+ } else {
+ pw.print("NOT active");
+ }
+ pw.print(", ");
+ pw.print(mJobCount);
+ pw.print(" running jobs");
+ pw.println();
+ pw.increaseIndent();
+ for (int i = 0; i < mRunningJobs.size(); i++) {
+ JobStatus js = mRunningJobs.valueAt(i);
+ if (predicate.test(js)) {
+ pw.println(js.toShortString());
+ }
+ }
+
+ pw.decreaseIndent();
+ }
+
+ public void dump(ProtoOutputStream proto, long fieldId, Predicate<JobStatus> predicate) {
+ final long token = proto.start(fieldId);
+
+ mPkg.writeToProto(proto, StateControllerProto.QuotaController.Timer.PKG);
+ proto.write(StateControllerProto.QuotaController.Timer.IS_ACTIVE, isActive());
+ proto.write(StateControllerProto.QuotaController.Timer.START_TIME_ELAPSED,
+ mStartTimeElapsed);
+ proto.write(StateControllerProto.QuotaController.Timer.JOB_COUNT, mJobCount);
+ for (int i = 0; i < mRunningJobs.size(); i++) {
+ JobStatus js = mRunningJobs.valueAt(i);
+ if (predicate.test(js)) {
+ js.writeToShortProto(proto,
+ StateControllerProto.QuotaController.Timer.RUNNING_JOBS);
+ }
+ }
+
+ proto.end(token);
+ }
+ }
+
+ /**
+ * Tracking of app assignments to standby buckets
+ */
+ final class StandbyTracker extends AppIdleStateChangeListener {
+
+ @Override
+ public void onAppIdleStateChanged(final String packageName, final @UserIdInt int userId,
+ boolean idle, int bucket, int reason) {
+ // Update job bookkeeping out of band.
+ BackgroundThread.getHandler().post(() -> {
+ final int bucketIndex = JobSchedulerService.standbyBucketToBucketIndex(bucket);
+ if (DEBUG) {
+ Slog.i(TAG, "Moving pkg " + string(userId, packageName) + " to bucketIndex "
+ + bucketIndex);
+ }
+ synchronized (mLock) {
+ ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, packageName);
+ if (jobs == null || jobs.size() == 0) {
+ return;
+ }
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ JobStatus js = jobs.valueAt(i);
+ js.setStandbyBucket(bucketIndex);
+ }
+ Timer timer = mPkgTimers.get(userId, packageName);
+ if (timer != null && timer.isActive()) {
+ timer.rescheduleCutoff();
+ }
+ if (!mShouldThrottle || maybeUpdateConstraintForPkgLocked(userId,
+ packageName)) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onParoleStateChanged(final boolean isParoleOn) {
+ mInParole = isParoleOn;
+ if (DEBUG) Slog.i(TAG, "Global parole state now " + (isParoleOn ? "ON" : "OFF"));
+ // Update job bookkeeping out of band.
+ BackgroundThread.getHandler().post(() -> {
+ synchronized (mLock) {
+ maybeUpdateAllConstraintsLocked();
+ }
+ });
+ }
+ }
+
+ private final class DeleteTimingSessionsFunctor implements Consumer<List<TimingSession>> {
+ private final Predicate<TimingSession> mTooOld = new Predicate<TimingSession>() {
+ public boolean test(TimingSession ts) {
+ return ts.endTimeElapsed <= sElapsedRealtimeClock.millis() - MAX_PERIOD_MS;
+ }
+ };
+
+ @Override
+ public void accept(List<TimingSession> sessions) {
+ if (sessions != null) {
+ // Remove everything older than MAX_PERIOD_MS time ago.
+ sessions.removeIf(mTooOld);
+ }
+ }
+ }
+
+ private final DeleteTimingSessionsFunctor mDeleteOldSessionsFunctor =
+ new DeleteTimingSessionsFunctor();
+
+ @VisibleForTesting
+ void deleteObsoleteSessionsLocked() {
+ mTimingSessions.forEach(mDeleteOldSessionsFunctor);
+ }
+
+ private class QcHandler extends Handler {
+ QcHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ synchronized (mLock) {
+ switch (msg.what) {
+ case MSG_REACHED_QUOTA: {
+ Package pkg = (Package) msg.obj;
+ if (DEBUG) Slog.d(TAG, "Checking if " + pkg + " has reached its quota.");
+
+ long timeRemainingMs = getRemainingExecutionTimeLocked(pkg.userId,
+ pkg.packageName);
+ if (timeRemainingMs <= 50) {
+ // Less than 50 milliseconds left. Start process of shutting down jobs.
+ if (DEBUG) Slog.d(TAG, pkg + " has reached its quota.");
+ if (maybeUpdateConstraintForPkgLocked(pkg.userId, pkg.packageName)) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ } else {
+ // This could potentially happen if an old session phases out while a
+ // job is currently running.
+ // Reschedule message
+ Message rescheduleMsg = obtainMessage(MSG_REACHED_QUOTA, pkg);
+ if (DEBUG) {
+ Slog.d(TAG, pkg + " has " + timeRemainingMs + "ms left.");
+ }
+ sendMessageDelayed(rescheduleMsg, timeRemainingMs);
+ }
+ break;
+ }
+ case MSG_CLEAN_UP_SESSIONS:
+ if (DEBUG) Slog.d(TAG, "Cleaning up timing sessions.");
+ deleteObsoleteSessionsLocked();
+ maybeScheduleCleanupAlarmLocked();
+
+ break;
+ case MSG_CHECK_PACKAGE: {
+ String packageName = (String) msg.obj;
+ int userId = msg.arg1;
+ if (DEBUG) Slog.d(TAG, "Checking pkg " + string(userId, packageName));
+ if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private class QcAlarmListener implements AlarmManager.OnAlarmListener {
+ private final int mUserId;
+ private final String mPackageName;
+ private volatile long mTriggerTimeElapsed;
+
+ QcAlarmListener(int userId, String packageName) {
+ mUserId = userId;
+ mPackageName = packageName;
+ }
+
+ boolean isWaiting() {
+ return mTriggerTimeElapsed > 0;
+ }
+
+ void setTriggerTime(long timeElapsed) {
+ mTriggerTimeElapsed = timeElapsed;
+ }
+
+ long getTriggerTimeElapsed() {
+ return mTriggerTimeElapsed;
+ }
+
+ @Override
+ public void onAlarm() {
+ mHandler.obtainMessage(MSG_CHECK_PACKAGE, mUserId, 0, mPackageName).sendToTarget();
+ mTriggerTimeElapsed = 0;
+ }
+ }
+
+ //////////////////////// TESTING HELPERS /////////////////////////////
+
+ @VisibleForTesting
+ long getAllowedTimePerPeriodMs() {
+ return mAllowedTimePerPeriodMs;
+ }
+
+ @VisibleForTesting
+ @NonNull
+ long[] getBucketWindowSizes() {
+ return mBucketPeriodsMs;
+ }
+
+ @VisibleForTesting
+ @NonNull
+ Handler getHandler() {
+ return mHandler;
+ }
+
+ @VisibleForTesting
+ long getInQuotaBufferMs() {
+ return mQuotaBufferMs;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ List<TimingSession> getTimingSessions(int userId, String packageName) {
+ return mTimingSessions.get(userId, packageName);
+ }
+
+ //////////////////////////// DATA DUMP //////////////////////////////
+
+ @Override
+ public void dumpControllerStateLocked(final IndentingPrintWriter pw,
+ final Predicate<JobStatus> predicate) {
+ pw.println("Is throttling: " + mShouldThrottle);
+ pw.println("Is charging: " + mChargeTracker.isCharging());
+ pw.println("In parole: " + mInParole);
+ pw.println();
+
+ mTrackedJobs.forEach((jobs) -> {
+ for (int j = 0; j < jobs.size(); j++) {
+ final JobStatus js = jobs.valueAt(j);
+ if (!predicate.test(js)) {
+ continue;
+ }
+ pw.print("#");
+ js.printUniqueId(pw);
+ pw.print(" from ");
+ UserHandle.formatUid(pw, js.getSourceUid());
+ pw.println();
+
+ pw.increaseIndent();
+ pw.print(JobStatus.bucketName(getEffectiveStandbyBucket(js)));
+ pw.print(", ");
+ if (js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) {
+ pw.print("within quota");
+ } else {
+ pw.print("not within quota");
+ }
+ pw.print(", ");
+ pw.print(getRemainingExecutionTimeLocked(js));
+ pw.print("ms remaining in quota");
+ pw.decreaseIndent();
+ pw.println();
+ }
+ });
+
+ pw.println();
+ for (int u = 0; u < mPkgTimers.numUsers(); ++u) {
+ final int userId = mPkgTimers.keyAt(u);
+ for (int p = 0; p < mPkgTimers.numPackagesForUser(userId); ++p) {
+ final String pkgName = mPkgTimers.keyAt(u, p);
+ mPkgTimers.valueAt(u, p).dump(pw, predicate);
+ pw.println();
+ List<TimingSession> sessions = mTimingSessions.get(userId, pkgName);
+ if (sessions != null) {
+ pw.increaseIndent();
+ pw.println("Saved sessions:");
+ pw.increaseIndent();
+ for (int j = sessions.size() - 1; j >= 0; j--) {
+ TimingSession session = sessions.get(j);
+ session.dump(pw);
+ }
+ pw.decreaseIndent();
+ pw.decreaseIndent();
+ pw.println();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
+ Predicate<JobStatus> predicate) {
+ final long token = proto.start(fieldId);
+ final long mToken = proto.start(StateControllerProto.QUOTA);
+
+ proto.write(StateControllerProto.QuotaController.IS_CHARGING, mChargeTracker.isCharging());
+ proto.write(StateControllerProto.QuotaController.IS_IN_PAROLE, mInParole);
+
+ mTrackedJobs.forEach((jobs) -> {
+ for (int j = 0; j < jobs.size(); j++) {
+ final JobStatus js = jobs.valueAt(j);
+ if (!predicate.test(js)) {
+ continue;
+ }
+ final long jsToken = proto.start(
+ StateControllerProto.QuotaController.TRACKED_JOBS);
+ js.writeToShortProto(proto,
+ StateControllerProto.QuotaController.TrackedJob.INFO);
+ proto.write(StateControllerProto.QuotaController.TrackedJob.SOURCE_UID,
+ js.getSourceUid());
+ proto.write(
+ StateControllerProto.QuotaController.TrackedJob.EFFECTIVE_STANDBY_BUCKET,
+ getEffectiveStandbyBucket(js));
+ proto.write(StateControllerProto.QuotaController.TrackedJob.HAS_QUOTA,
+ js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ proto.write(StateControllerProto.QuotaController.TrackedJob.REMAINING_QUOTA_MS,
+ getRemainingExecutionTimeLocked(js));
+ proto.end(jsToken);
+ }
+ });
+
+ for (int u = 0; u < mPkgTimers.numUsers(); ++u) {
+ final int userId = mPkgTimers.keyAt(u);
+ for (int p = 0; p < mPkgTimers.numPackagesForUser(userId); ++p) {
+ final String pkgName = mPkgTimers.keyAt(u, p);
+ final long psToken = proto.start(
+ StateControllerProto.QuotaController.PACKAGE_STATS);
+ mPkgTimers.valueAt(u, p).dump(proto,
+ StateControllerProto.QuotaController.PackageStats.TIMER, predicate);
+
+ List<TimingSession> sessions = mTimingSessions.get(userId, pkgName);
+ if (sessions != null) {
+ for (int j = sessions.size() - 1; j >= 0; j--) {
+ TimingSession session = sessions.get(j);
+ session.dump(proto,
+ StateControllerProto.QuotaController.PackageStats.SAVED_SESSIONS);
+ }
+ }
+
+ proto.end(psToken);
+ }
+ }
+
+ proto.end(mToken);
+ proto.end(token);
+ }
+}
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index c2be28336406..b439c0ddd028 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -53,22 +53,31 @@ public abstract class StateController {
* preexisting tasks.
*/
public abstract void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob);
+
/**
* Optionally implement logic here to prepare the job to be executed.
*/
public void prepareForExecutionLocked(JobStatus jobStatus) {
}
+
/**
* Remove task - this will happen if the task is cancelled, completed, etc.
*/
public abstract void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
boolean forUpdate);
+
/**
* Called when a new job is being created to reschedule an old failed job.
*/
public void rescheduleForFailureLocked(JobStatus newJob, JobStatus failureToReschedule) {
}
+ /**
+ * Called when the JobScheduler.Constants are updated.
+ */
+ public void onConstantsUpdatedLocked() {
+ }
+
public abstract void dumpControllerStateLocked(IndentingPrintWriter pw,
Predicate<JobStatus> predicate);
public abstract void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index 2584187fffe6..9b9f4de7a18f 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -15,12 +15,15 @@
*/
package com.android.server.notification;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+
import android.app.Notification;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.provider.Settings;
import android.telecom.TelecomManager;
import com.android.internal.util.NotificationMessagingUtil;
@@ -47,6 +50,21 @@ public class NotificationComparator
@Override
public int compare(NotificationRecord left, NotificationRecord right) {
+ final int leftImportance = left.getImportance();
+ final int rightImportance = right.getImportance();
+ final boolean isLeftHighImportance = leftImportance >= IMPORTANCE_DEFAULT;
+ final boolean isRightHighImportance = rightImportance >= IMPORTANCE_DEFAULT;
+
+ // With new interruption model, prefer importance bucket above all other criteria
+ // (to ensure buckets are contiguous)
+ if (Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL, 1) == 1) {
+ if (isLeftHighImportance != isRightHighImportance) {
+ // by importance bucket, high importance higher than low importance
+ return -1 * Boolean.compare(isLeftHighImportance, isRightHighImportance);
+ }
+ }
+
// first all colorized notifications
boolean leftImportantColorized = isImportantColorized(left);
boolean rightImportantColorized = isImportantColorized(right);
@@ -86,8 +104,6 @@ public class NotificationComparator
return -1 * Boolean.compare(leftPeople, rightPeople);
}
- final int leftImportance = left.getImportance();
- final int rightImportance = right.getImportance();
if (leftImportance != rightImportance) {
// by importance, high to low
return -1 * Integer.compare(leftImportance, rightImportance);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6c2549e9b04d..95e1962fdbfb 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -207,7 +207,6 @@ import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.DeviceIdleController;
import com.android.server.EventLogTags;
-import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.lights.Light;
@@ -266,7 +265,7 @@ public class NotificationManagerService extends SystemService {
// message codes
static final int MESSAGE_DURATION_REACHED = 2;
- // 3: removed to a different handler
+ static final int MESSAGE_SAVE_POLICY_FILE = 3;
static final int MESSAGE_SEND_RANKING_UPDATE = 4;
static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
@@ -428,6 +427,7 @@ public class NotificationManagerService extends SystemService {
private GroupHelper mGroupHelper;
private int mAutoGroupAtCount;
private boolean mIsTelevision;
+ private boolean mIsAutomotive;
private MetricsLogger mMetricsLogger;
private Predicate<String> mAllowedManagedServicePackages;
@@ -573,7 +573,7 @@ public class NotificationManagerService extends SystemService {
mListeners.migrateToXml();
mAssistants.migrateToXml();
mConditionProviders.migrateToXml();
- handleSavePolicyFile();
+ savePolicyFile();
}
mAssistants.ensureAssistant();
@@ -603,28 +603,34 @@ public class NotificationManagerService extends SystemService {
}
}
+ /**
+ * Saves notification policy
+ */
+ public void savePolicyFile() {
+ mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
+ mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
+ }
+
private void handleSavePolicyFile() {
- IoThread.getHandler().post(() -> {
- if (DBG) Slog.d(TAG, "handleSavePolicyFile");
- synchronized (mPolicyFile) {
- final FileOutputStream stream;
- try {
- stream = mPolicyFile.startWrite();
- } catch (IOException e) {
- Slog.w(TAG, "Failed to save policy file", e);
- return;
- }
+ if (DBG) Slog.d(TAG, "handleSavePolicyFile");
+ synchronized (mPolicyFile) {
+ final FileOutputStream stream;
+ try {
+ stream = mPolicyFile.startWrite();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to save policy file", e);
+ return;
+ }
- try {
- writePolicyXml(stream, false /*forBackup*/);
- mPolicyFile.finishWrite(stream);
- } catch (IOException e) {
- Slog.w(TAG, "Failed to save policy file, restoring backup", e);
- mPolicyFile.failWrite(stream);
- }
+ try {
+ writePolicyXml(stream, false /*forBackup*/);
+ mPolicyFile.finishWrite(stream);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to save policy file, restoring backup", e);
+ mPolicyFile.failWrite(stream);
}
- BackupManager.dataChanged(getContext().getPackageName());
- });
+ }
+ BackupManager.dataChanged(getContext().getPackageName());
}
private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
@@ -1132,8 +1138,8 @@ public class NotificationManagerService extends SystemService {
}
}
-
mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList);
+ savePolicyFile();
}
}
};
@@ -1200,7 +1206,7 @@ public class NotificationManagerService extends SystemService {
mListeners.onUserRemoved(userId);
mConditionProviders.onUserRemoved(userId);
mAssistants.onUserRemoved(userId);
- handleSavePolicyFile();
+ savePolicyFile();
} else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
mUserProfiles.updateCache(context);
@@ -1388,6 +1394,11 @@ public class NotificationManagerService extends SystemService {
}
@VisibleForTesting
+ void setIsAutomotive(boolean isAutomotive) {
+ mIsAutomotive = isAutomotive;
+ }
+
+ @VisibleForTesting
void setIsTelevision(boolean isTelevision) {
mIsTelevision = isTelevision;
}
@@ -1451,7 +1462,7 @@ public class NotificationManagerService extends SystemService {
mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
@Override
public void onConfigChanged() {
- handleSavePolicyFile();
+ savePolicyFile();
}
@Override
@@ -1543,6 +1554,9 @@ public class NotificationManagerService extends SystemService {
mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
|| mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
+
+ mIsAutomotive =
+ mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
}
@Override
@@ -1750,7 +1764,7 @@ public class NotificationManagerService extends SystemService {
modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
}
- handleSavePolicyFile();
+ savePolicyFile();
}
private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
@@ -2218,7 +2232,7 @@ public class NotificationManagerService extends SystemService {
Slog.w(TAG, "Can't notify app about app block change", e);
}
- handleSavePolicyFile();
+ savePolicyFile();
}
/**
@@ -2275,7 +2289,7 @@ public class NotificationManagerService extends SystemService {
public void setShowBadge(String pkg, int uid, boolean showBadge) {
checkCallerIsSystem();
mPreferencesHelper.setShowBadge(pkg, uid, showBadge);
- handleSavePolicyFile();
+ savePolicyFile();
}
@Override
@@ -2291,7 +2305,7 @@ public class NotificationManagerService extends SystemService {
if (info != null) {
mPreferencesHelper.setNotificationDelegate(
callingPkg, callingUid, delegate, info.uid);
- handleSavePolicyFile();
+ savePolicyFile();
}
} catch (RemoteException e) {
// :(
@@ -2302,7 +2316,7 @@ public class NotificationManagerService extends SystemService {
public void revokeNotificationDelegate(String callingPkg) {
checkCallerIsSameApp(callingPkg);
mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
- handleSavePolicyFile();
+ savePolicyFile();
}
@Override
@@ -2337,7 +2351,7 @@ public class NotificationManagerService extends SystemService {
NotificationChannelGroup group) throws RemoteException {
enforceSystemOrSystemUI("Caller not system or systemui");
createNotificationChannelGroup(pkg, uid, group, false, false);
- handleSavePolicyFile();
+ savePolicyFile();
}
@Override
@@ -2350,7 +2364,7 @@ public class NotificationManagerService extends SystemService {
final NotificationChannelGroup group = groups.get(i);
createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
}
- handleSavePolicyFile();
+ savePolicyFile();
}
private void createNotificationChannelsImpl(String pkg, int uid,
@@ -2368,7 +2382,7 @@ public class NotificationManagerService extends SystemService {
mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
}
- handleSavePolicyFile();
+ savePolicyFile();
}
@Override
@@ -2413,7 +2427,7 @@ public class NotificationManagerService extends SystemService {
UserHandle.getUserHandleForUid(callingUid),
mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
- handleSavePolicyFile();
+ savePolicyFile();
}
@Override
@@ -2455,7 +2469,7 @@ public class NotificationManagerService extends SystemService {
mListeners.notifyNotificationChannelGroupChanged(
pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
- handleSavePolicyFile();
+ savePolicyFile();
}
}
@@ -2588,7 +2602,7 @@ public class NotificationManagerService extends SystemService {
true, UserHandle.getCallingUserId(), packages, uids);
}
- handleSavePolicyFile();
+ savePolicyFile();
}
@@ -3376,7 +3390,7 @@ public class NotificationManagerService extends SystemService {
final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
try {
readPolicyXml(bais, true /*forRestore*/);
- handleSavePolicyFile();
+ savePolicyFile();
} catch (NumberFormatException | XmlPullParserException | IOException e) {
Slog.w(TAG, "applyRestore: error reading payload", e);
}
@@ -3417,7 +3431,7 @@ public class NotificationManagerService extends SystemService {
.setPackage(pkg)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
UserHandle.of(userId), null);
- handleSavePolicyFile();
+ savePolicyFile();
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -3561,7 +3575,7 @@ public class NotificationManagerService extends SystemService {
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
UserHandle.of(userId), null);
- handleSavePolicyFile();
+ savePolicyFile();
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -3587,7 +3601,7 @@ public class NotificationManagerService extends SystemService {
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
UserHandle.of(userId), null);
- handleSavePolicyFile();
+ savePolicyFile();
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -3670,7 +3684,7 @@ public class NotificationManagerService extends SystemService {
verifyPrivilegedListener(token, user, false);
createNotificationChannelGroup(
pkg, getUidForPackageAndUser(pkg, user), group, false, true);
- handleSavePolicyFile();
+ savePolicyFile();
}
@Override
@@ -3719,7 +3733,7 @@ public class NotificationManagerService extends SystemService {
}
if (allow != mLockScreenAllowSecureNotifications) {
mLockScreenAllowSecureNotifications = allow;
- handleSavePolicyFile();
+ savePolicyFile();
}
}
@@ -4478,7 +4492,7 @@ public class NotificationManagerService extends SystemService {
Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
}
mSnoozeHelper.update(userId, r);
- handleSavePolicyFile();
+ savePolicyFile();
return false;
}
@@ -4609,7 +4623,7 @@ public class NotificationManagerService extends SystemService {
mSnoozeHelper.snooze(r, mDuration);
}
r.recordSnoozed();
- handleSavePolicyFile();
+ savePolicyFile();
}
}
@@ -4687,7 +4701,7 @@ public class NotificationManagerService extends SystemService {
if (mReason != REASON_SNOOZED) {
final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId);
if (wasSnoozed) {
- handleSavePolicyFile();
+ savePolicyFile();
}
}
}
@@ -5131,7 +5145,9 @@ public class NotificationManagerService extends SystemService {
// Should this notification make noise, vibe, or use the LED?
final boolean aboveThreshold =
- record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
+ mIsAutomotive
+ ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT
+ : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
// Remember if this notification already owns the notification channels.
boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
@@ -5729,6 +5745,9 @@ public class NotificationManagerService extends SystemService {
case MESSAGE_FINISH_TOKEN_TIMEOUT:
handleKillTokenTimeout((ToastRecord) msg.obj);
break;
+ case MESSAGE_SAVE_POLICY_FILE:
+ handleSavePolicyFile();
+ break;
case MESSAGE_SEND_RANKING_UPDATE:
handleSendRankingUpdate();
break;
@@ -6246,7 +6265,7 @@ public class NotificationManagerService extends SystemService {
Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
}
mSnoozeHelper.repost(key);
- handleSavePolicyFile();
+ savePolicyFile();
}
@GuardedBy("mNotificationLock")
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8abb5000d544..dab4e79e141c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -58,6 +58,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
@@ -10299,12 +10300,21 @@ public class PackageManagerService extends IPackageManager.Stub
compareSignatures(
signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures,
pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) {
- // Treat mismatched signatures on system packages using a shared UID as
- // fatal for the system overall, rather than just failing to install
- // whichever package happened to be scanned later.
- throw new IllegalStateException(
- "Signature mismatch on system package " + pkg.packageName
- + " for shared user " + pkgSetting.sharedUser);
+ if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 28) {
+ // Mismatched signatures is an error and silently skipping system
+ // packages will likely break the device in unforeseen ways. However,
+ // we allow the device to boot anyway because, prior to P, vendors were
+ // not expecting the platform to crash in this situation.
+ throw new PackageManagerException(
+ INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ "Signature mismatch for shared user: " + pkgSetting.sharedUser);
+ } else {
+ // Treat mismatched signatures on system packages using a shared UID as
+ // fatal for the system overall, rather than just failing to install
+ // whichever package happened to be scanned later.
+ throw new IllegalStateException("Signature mismatch on system package "
+ + pkg.packageName + " for shared user " + pkgSetting.sharedUser);
+ }
}
signatureCheckPs.sharedUser.signatures.mSigningDetails = pkg.mSigningDetails;
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java b/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java
new file mode 100644
index 000000000000..7ce071faab04
--- /dev/null
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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.signedconfig;
+
+import android.content.Context;
+
+class SignedConfigApplicator {
+
+ static void applyConfig(Context context, String config, String signature) {
+ //TODO verify signature
+ //TODO parse & apply config
+ }
+
+}
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigService.java b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
new file mode 100644
index 000000000000..148568628397
--- /dev/null
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 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.signedconfig;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+
+/**
+ * Signed config service. This is not an Android Service, but just owns a broadcast receiver for
+ * receiving package install and update notifications from the package manager.
+ */
+public class SignedConfigService {
+
+ private static final boolean DBG = false;
+ private static final String TAG = "SignedConfig";
+
+ // TODO should these be elsewhere? In a public API?
+ private static final String KEY_CONFIG = "android.signedconfig";
+ private static final String KEY_CONFIG_SIGNATURE = "android.signedconfig.signature";
+
+ private static class UpdateReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ new SignedConfigService(context).handlePackageBroadcast(intent);
+ }
+ }
+
+ private final Context mContext;
+ private final PackageManagerInternal mPacMan;
+
+ public SignedConfigService(Context context) {
+ mContext = context;
+ mPacMan = LocalServices.getService(PackageManagerInternal.class);
+ }
+
+ void handlePackageBroadcast(Intent intent) {
+ if (DBG) Slog.d(TAG, "handlePackageBroadcast " + intent);
+ Uri packageData = intent.getData();
+ String packageName = packageData == null ? null : packageData.getSchemeSpecificPart();
+ if (DBG) Slog.d(TAG, "handlePackageBroadcast package=" + packageName);
+ if (packageName == null) {
+ return;
+ }
+ int userId = mContext.getUser().getIdentifier();
+ PackageInfo pi = mPacMan.getPackageInfo(packageName, PackageManager.GET_META_DATA,
+ android.os.Process.SYSTEM_UID, userId);
+ if (pi == null) {
+ Slog.w(TAG, "Got null PackageInfo for " + packageName + "; user " + userId);
+ return;
+ }
+ Bundle metaData = pi.applicationInfo.metaData;
+ if (metaData == null) {
+ if (DBG) Slog.d(TAG, "handlePackageBroadcast: no metadata");
+ return;
+ }
+ if (metaData.containsKey(KEY_CONFIG)
+ && metaData.containsKey(KEY_CONFIG_SIGNATURE)) {
+ String config = metaData.getString(KEY_CONFIG);
+ String signature = metaData.getString(KEY_CONFIG_SIGNATURE);
+ if (DBG) {
+ Slog.d(TAG, "Got signed config: " + config);
+ Slog.d(TAG, "Got config signature: " + signature);
+ }
+ SignedConfigApplicator.applyConfig(mContext, config, signature);
+ } else {
+ if (DBG) Slog.d(TAG, "Package has no config/signature.");
+ }
+ }
+
+ /**
+ * Register to receive broadcasts from the package manager.
+ */
+ public static void registerUpdateReceiver(Context context) {
+ if (DBG) Slog.d(TAG, "Registering receiver");
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addDataScheme("package");
+ context.registerReceiver(new UpdateReceiver(), filter);
+ }
+}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index e645b84e83a0..6e4c00eed181 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.statusbar;
import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
+import static android.view.Display.DEFAULT_DISPLAY;
import android.app.ActivityThread;
import android.app.Notification;
@@ -25,6 +26,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.graphics.Rect;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -40,7 +43,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
-import android.view.Display;
+import android.util.SparseArray;
import com.android.internal.R;
import com.android.internal.statusbar.IStatusBar;
@@ -63,7 +66,7 @@ import java.util.List;
* A note on locking: We rely on the fact that calls onto mBar are oneway or
* if they are local, that they just enqueue messages to not deadlock.
*/
-public class StatusBarManagerService extends IStatusBarService.Stub {
+public class StatusBarManagerService extends IStatusBarService.Stub implements DisplayListener {
private static final String TAG = "StatusBarManagerService";
private static final boolean SPEW = false;
@@ -79,24 +82,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
private GlobalActionsProvider.GlobalActionsListener mGlobalActionListener;
private IBinder mSysUiVisToken = new Binder();
- private int mDisabled1 = 0;
- private int mDisabled2 = 0;
private final Object mLock = new Object();
private final DeathRecipient mDeathRecipient = new DeathRecipient();
- // encompasses lights-out mode and other flags defined on View
- private int mSystemUiVisibility = 0;
- private int mFullscreenStackSysUiVisibility;
- private int mDockedStackSysUiVisibility;
- private final Rect mFullscreenStackBounds = new Rect();
- private final Rect mDockedStackBounds = new Rect();
- private boolean mMenuVisible = false;
- private int mImeWindowVis = 0;
- private int mImeBackDisposition;
- private boolean mShowImeSwitcher;
- private IBinder mImeToken = null;
private int mCurrentUserId;
+ private SparseArray<UiState> mDisplayUiState = new SparseArray<>();
+
private class DeathRecipient implements IBinder.DeathRecipient {
public void binderDied() {
mBar.asBinder().unlinkToDeath(this,0);
@@ -185,8 +177,29 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
LocalServices.addService(GlobalActionsProvider.class, mGlobalActionsProvider);
+
+ // We always have a default display.
+ final UiState state = new UiState();
+ mDisplayUiState.put(DEFAULT_DISPLAY, state);
+
+ final DisplayManager displayManager =
+ (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+ displayManager.registerDisplayListener(this, mHandler);
}
+ @Override
+ public void onDisplayAdded(int displayId) {}
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ synchronized (mLock) {
+ mDisplayUiState.remove(displayId);
+ }
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {}
+
/**
* Private API used by NotificationManagerService.
*/
@@ -240,22 +253,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
@Override
public void topAppWindowChanged(int displayId, boolean menuVisible) {
- if (displayId != Display.DEFAULT_DISPLAY) {
- // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
- return;
- }
- StatusBarManagerService.this.topAppWindowChanged(menuVisible);
+ StatusBarManagerService.this.topAppWindowChanged(displayId, menuVisible);
}
@Override
public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds,
String cause) {
- if (displayId != Display.DEFAULT_DISPLAY) {
- // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
- return;
- }
- StatusBarManagerService.this.setSystemUiVisibility(vis, fullscreenStackVis,
+ StatusBarManagerService.this.setSystemUiVisibility(displayId, vis, fullscreenStackVis,
dockedStackVis, mask, fullscreenBounds, dockedBounds, cause);
}
@@ -272,13 +277,9 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
@Override
public void appTransitionFinished(int displayId) {
enforceStatusBarService();
- if (displayId != Display.DEFAULT_DISPLAY) {
- // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
- return;
- }
if (mBar != null) {
try {
- mBar.appTransitionFinished();
+ mBar.appTransitionFinished(displayId);
} catch (RemoteException ex) {}
}
}
@@ -374,39 +375,27 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
@Override
public void setWindowState(int displayId, int window, int state) {
- if (displayId != Display.DEFAULT_DISPLAY) {
- // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
- return;
- }
if (mBar != null) {
try {
- mBar.setWindowState(window, state);
+ mBar.setWindowState(displayId, window, state);
} catch (RemoteException ex) {}
}
}
@Override
public void appTransitionPending(int displayId) {
- if (displayId != Display.DEFAULT_DISPLAY) {
- // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
- return;
- }
if (mBar != null) {
try {
- mBar.appTransitionPending();
+ mBar.appTransitionPending(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void appTransitionCancelled(int displayId) {
- if (displayId != Display.DEFAULT_DISPLAY) {
- // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
- return;
- }
if (mBar != null) {
try {
- mBar.appTransitionCancelled();
+ mBar.appTransitionCancelled(displayId);
} catch (RemoteException ex) {}
}
}
@@ -414,14 +403,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
@Override
public void appTransitionStarting(int displayId, long statusBarAnimationsStartTime,
long statusBarAnimationsDuration) {
- if (displayId != Display.DEFAULT_DISPLAY) {
- // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
- return;
- }
if (mBar != null) {
try {
mBar.appTransitionStarting(
- statusBarAnimationsStartTime, statusBarAnimationsDuration);
+ displayId, statusBarAnimationsStartTime, statusBarAnimationsDuration);
} catch (RemoteException ex) {}
}
}
@@ -449,6 +434,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
return false;
}
+ // TODO(b/118592525): support it per display if necessary.
@Override
public void onProposedRotationChanged(int rotation, boolean isValid) {
if (mBar != null){
@@ -462,7 +448,9 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
@Override
public boolean isGlobalActionsDisabled() {
- return (mDisabled2 & DISABLE2_GLOBAL_ACTIONS) != 0;
+ // TODO(b/118592525): support global actions for multi-display.
+ final int disabled2 = mDisplayUiState.get(DEFAULT_DISPLAY).getDisabled2();
+ return (disabled2 & DISABLE2_GLOBAL_ACTIONS) != 0;
}
@Override
@@ -664,20 +652,23 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
}
+ // TODO(b/117478341): make it aware of multi-display if needed.
@Override
public void disable(int what, IBinder token, String pkg) {
disableForUser(what, token, pkg, mCurrentUserId);
}
+ // TODO(b/117478341): make it aware of multi-display if needed.
@Override
public void disableForUser(int what, IBinder token, String pkg, int userId) {
enforceStatusBar();
synchronized (mLock) {
- disableLocked(userId, what, token, pkg, 1);
+ disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 1);
}
}
+ // TODO(b/117478341): make it aware of multi-display if needed.
/**
* Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags.
* To re-enable everything, pass {@link #DISABLE_NONE}.
@@ -689,6 +680,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
disable2ForUser(what, token, pkg, mCurrentUserId);
}
+ // TODO(b/117478341): make it aware of multi-display if needed.
/**
* Disable additional status bar features for a given user. Pass the bitwise-or of the
* DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}.
@@ -700,11 +692,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
enforceStatusBar();
synchronized (mLock) {
- disableLocked(userId, what, token, pkg, 2);
+ disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 2);
}
}
- private void disableLocked(int userId, int what, IBinder token, String pkg, int whichFlag) {
+ private void disableLocked(int displayId, int userId, int what, IBinder token, String pkg,
+ int whichFlag) {
// It's important that the the callback and the call to mBar get done
// in the same order when multiple threads are calling this function
// so they are paired correctly. The messages on the handler will be
@@ -723,22 +716,19 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
disabledData += " ([" + i + "] " + tok + "), ";
}
disabledData += " }";
- Log.d(TAG, "disabledlocked (b/113914868): net1=" + net1 + ", mDisabled1=" + mDisabled1
- + ", token=" + token + ", mDisableRecords=" + mDisableRecords.size() + " => "
- + disabledData);
- }
+ final UiState state = getUiState(displayId);
- if (net1 != mDisabled1 || net2 != mDisabled2) {
- mDisabled1 = net1;
- mDisabled2 = net2;
- mHandler.post(new Runnable() {
- public void run() {
- mNotificationDelegate.onSetDisabled(net1);
- }
- });
+ Log.d(TAG, "disabledlocked (b/113914868): displayId=" + displayId + "net1=" + net1
+ + ", mDisabled1=" + state.mDisabled1 + ", token=" + token
+ + ", mDisableRecords=" + mDisableRecords.size() + " => " + disabledData);
+ }
+ final UiState state = getUiState(displayId);
+ if (state.disableEquals(net1, net2)) {
+ state.setDisabled(net1, net2);
+ mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1));
if (mBar != null) {
try {
- mBar.disable(net1, net2);
+ mBar.disable(displayId, net1, net2);
} catch (RemoteException ex) {
}
}
@@ -808,26 +798,27 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
* response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set
* to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}.
*/
- private void topAppWindowChanged(final boolean menuVisible) {
+ private void topAppWindowChanged(int displayId, final boolean menuVisible) {
enforceStatusBar();
- if (SPEW) Slog.d(TAG, (menuVisible?"showing":"hiding") + " MENU key");
-
+ if (SPEW) {
+ Slog.d(TAG, "display#" + displayId + ": "
+ + (menuVisible ? "showing" : "hiding") + " MENU key");
+ }
synchronized(mLock) {
- mMenuVisible = menuVisible;
- mHandler.post(new Runnable() {
- public void run() {
- if (mBar != null) {
- try {
- mBar.topAppWindowChanged(menuVisible);
- } catch (RemoteException ex) {
- }
+ getUiState(displayId).setMenuVisible(menuVisible);
+ mHandler.post(() -> {
+ if (mBar != null) {
+ try {
+ mBar.topAppWindowChanged(displayId, menuVisible);
+ } catch (RemoteException ex) {
}
}
});
}
}
+ // TODO(b/117478341): support back button change when IME is showing on a external display.
@Override
public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition,
final boolean showImeSwitcher) {
@@ -841,39 +832,42 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
// In case of IME change, we need to call up setImeWindowStatus() regardless of
// mImeWindowVis because mImeWindowVis may not have been set to false when the
// previous IME was destroyed.
- mImeWindowVis = vis;
- mImeBackDisposition = backDisposition;
- mImeToken = token;
- mShowImeSwitcher = showImeSwitcher;
- mHandler.post(new Runnable() {
- public void run() {
- if (mBar != null) {
- try {
- mBar.setImeWindowStatus(token, vis, backDisposition, showImeSwitcher);
- } catch (RemoteException ex) {
- }
- }
- }
+ // TODO(b/117478341): support back button change when IME is showing on a external
+ // display.
+ getUiState(DEFAULT_DISPLAY)
+ .setImeWindowState(vis, backDisposition, showImeSwitcher, token);
+
+ mHandler.post(() -> {
+ if (mBar == null) return;
+ try {
+ // TODO(b/117478341): support back button change when IME is showing on a
+ // external display.
+ mBar.setImeWindowStatus(
+ DEFAULT_DISPLAY, token, vis, backDisposition, showImeSwitcher);
+ } catch (RemoteException ex) { }
});
}
}
@Override
- public void setSystemUiVisibility(int vis, int mask, String cause) {
- setSystemUiVisibility(vis, 0, 0, mask, mFullscreenStackBounds, mDockedStackBounds, cause);
+ public void setSystemUiVisibility(int displayId, int vis, int mask, String cause) {
+ final UiState state = getUiState(displayId);
+ setSystemUiVisibility(displayId, vis, 0, 0, mask,
+ state.mFullscreenStackBounds, state.mDockedStackBounds, cause);
}
- private void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
- Rect fullscreenBounds, Rect dockedBounds, String cause) {
+ private void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+ int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds, String cause) {
// also allows calls from window manager which is in this process.
enforceStatusBarService();
if (SPEW) Slog.d(TAG, "setSystemUiVisibility(0x" + Integer.toHexString(vis) + ")");
synchronized (mLock) {
- updateUiVisibilityLocked(vis, fullscreenStackVis, dockedStackVis, mask,
+ updateUiVisibilityLocked(displayId, vis, fullscreenStackVis, dockedStackVis, mask,
fullscreenBounds, dockedBounds);
disableLocked(
+ displayId,
mCurrentUserId,
vis & StatusBarManager.DISABLE_MASK,
mSysUiVisToken,
@@ -881,30 +875,107 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
}
- private void updateUiVisibilityLocked(final int vis,
+ private void updateUiVisibilityLocked(final int displayId, final int vis,
final int fullscreenStackVis, final int dockedStackVis, final int mask,
final Rect fullscreenBounds, final Rect dockedBounds) {
- if (mSystemUiVisibility != vis
- || mFullscreenStackSysUiVisibility != fullscreenStackVis
- || mDockedStackSysUiVisibility != dockedStackVis
- || !mFullscreenStackBounds.equals(fullscreenBounds)
- || !mDockedStackBounds.equals(dockedBounds)) {
+ final UiState state = getUiState(displayId);
+ if (!state.systemUiStateEquals(vis, fullscreenStackVis, dockedStackVis,
+ fullscreenBounds, dockedBounds)) {
+ state.setSystemUiState(vis, fullscreenStackVis, dockedStackVis, fullscreenBounds,
+ dockedBounds);
+ mHandler.post(() -> {
+ if (mBar != null) {
+ try {
+ mBar.setSystemUiVisibility(displayId, vis, fullscreenStackVis,
+ dockedStackVis, mask, fullscreenBounds, dockedBounds);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Can not get StatusBar!");
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * @return {@link UiState} specified by {@code displayId}.
+ *
+ * <p>
+ * Note: If {@link UiState} specified by {@code displayId} does not exist, {@link UiState}
+ * will be allocated and {@code mDisplayUiState} will be updated accordingly.
+ * <p/>
+ */
+ private UiState getUiState(int displayId) {
+ UiState state = mDisplayUiState.get(displayId);
+ if (state == null) {
+ state = new UiState();
+ mDisplayUiState.put(displayId, state);
+ }
+ return state;
+ }
+
+ private class UiState {
+ private int mSystemUiVisibility = 0;
+ private int mFullscreenStackSysUiVisibility = 0;
+ private int mDockedStackSysUiVisibility = 0;
+ private final Rect mFullscreenStackBounds = new Rect();
+ private final Rect mDockedStackBounds = new Rect();
+ private boolean mMenuVisible = false;
+ private int mDisabled1 = 0;
+ private int mDisabled2 = 0;
+ private int mImeWindowVis = 0;
+ private int mImeBackDisposition = 0;
+ private boolean mShowImeSwitcher = false;
+ private IBinder mImeToken = null;
+
+ private int getDisabled1() {
+ return mDisabled1;
+ }
+
+ private int getDisabled2() {
+ return mDisabled2;
+ }
+
+ private void setDisabled(int disabled1, int disabled2) {
+ mDisabled1 = disabled1;
+ mDisabled2 = disabled2;
+ }
+
+ private boolean isMenuVisible() {
+ return mMenuVisible;
+ }
+
+ private void setMenuVisible(boolean menuVisible) {
+ mMenuVisible = menuVisible;
+ }
+
+ private boolean disableEquals(int disabled1, int disabled2) {
+ return mDisabled1 == disabled1 && mDisabled2 == disabled2;
+ }
+
+ private void setSystemUiState(final int vis, final int fullscreenStackVis,
+ final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds) {
mSystemUiVisibility = vis;
mFullscreenStackSysUiVisibility = fullscreenStackVis;
mDockedStackSysUiVisibility = dockedStackVis;
mFullscreenStackBounds.set(fullscreenBounds);
mDockedStackBounds.set(dockedBounds);
- mHandler.post(new Runnable() {
- public void run() {
- if (mBar != null) {
- try {
- mBar.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis,
- mask, fullscreenBounds, dockedBounds);
- } catch (RemoteException ex) {
- }
- }
- }
- });
+ }
+
+ private boolean systemUiStateEquals(final int vis, final int fullscreenStackVis,
+ final int dockedStackVis, final Rect fullscreenBounds, final Rect dockedBounds) {
+ return mSystemUiVisibility == vis
+ && mFullscreenStackSysUiVisibility == fullscreenStackVis
+ && mDockedStackSysUiVisibility == dockedStackVis
+ && mFullscreenStackBounds.equals(fullscreenBounds)
+ && mDockedStackBounds.equals(dockedBounds);
+ }
+
+ private void setImeWindowState(final int vis, final int backDisposition,
+ final boolean showImeSwitcher, final IBinder token) {
+ mImeWindowVis = vis;
+ mImeBackDisposition = backDisposition;
+ mShowImeSwitcher = showImeSwitcher;
+ mImeToken = token;
}
}
@@ -939,6 +1010,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
// ================================================================================
// Callbacks from the status bar service.
// ================================================================================
+ // TODO(b/118592525): refactor it as an IStatusBar API.
@Override
public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
@@ -956,18 +1028,21 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
}
synchronized (mLock) {
+ // TODO(b/118592525): Currently, status bar only works on the default display.
+ // Make it aware of multi-display if needed.
+ final UiState state = mDisplayUiState.get(DEFAULT_DISPLAY);
switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1);
- switches[1] = mSystemUiVisibility;
- switches[2] = mMenuVisible ? 1 : 0;
- switches[3] = mImeWindowVis;
- switches[4] = mImeBackDisposition;
- switches[5] = mShowImeSwitcher ? 1 : 0;
+ switches[1] = state.mSystemUiVisibility;
+ switches[2] = state.mMenuVisible ? 1 : 0;
+ switches[3] = state.mImeWindowVis;
+ switches[4] = state.mImeBackDisposition;
+ switches[5] = state.mShowImeSwitcher ? 1 : 0;
switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
- switches[7] = mFullscreenStackSysUiVisibility;
- switches[8] = mDockedStackSysUiVisibility;
- binders.add(mImeToken);
- fullscreenStackBounds.set(mFullscreenStackBounds);
- dockedStackBounds.set(mDockedStackBounds);
+ switches[7] = state.mFullscreenStackSysUiVisibility;
+ switches[8] = state.mDockedStackSysUiVisibility;
+ binders.add(state.mImeToken);
+ fullscreenStackBounds.set(state.mFullscreenStackBounds);
+ dockedStackBounds.set(state.mDockedStackBounds);
}
}
@@ -1309,8 +1384,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
synchronized (mLock) {
- pw.println(" mDisabled1=0x" + Integer.toHexString(mDisabled1));
- pw.println(" mDisabled2=0x" + Integer.toHexString(mDisabled2));
+ for (int i = 0; i < mDisplayUiState.size(); i++) {
+ final int key = mDisplayUiState.keyAt(i);
+ final UiState state = mDisplayUiState.get(key);
+ pw.println(" displayId=" + key);
+ pw.println(" mDisabled1=0x" + Integer.toHexString(state.getDisabled1()));
+ pw.println(" mDisabled2=0x" + Integer.toHexString(state.getDisabled2()));
+ }
final int N = mDisableRecords.size();
pw.println(" mDisableRecords.size=" + N);
for (int i=0; i<N; i++) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index cfec8effeede..64ff9cf21ba0 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2822,8 +2822,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
IoUtils.closeQuietly(stream);
if (!success) {
- wpdData.mWidth = -1;
- wpdData.mHeight = -1;
wallpaper.cropHint.set(0, 0, 0, 0);
wpdData.mPadding.set(0, 0, 0, 0);
wallpaper.name = "";
@@ -2839,6 +2837,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
+ ensureSaneWallpaperDisplaySize(wpdData, DEFAULT_DISPLAY);
ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY);
WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
if (lockWallpaper != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 255a003bb542..daf4b8ba6d48 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1640,7 +1640,6 @@ final class ActivityRecord extends ConfigurationContainer {
final IAppTransitionAnimationSpecsFuture specsFuture =
pendingOptions.getSpecsFuture();
if (specsFuture != null) {
- // TODO(multidisplay): Shouldn't be really used anymore from next CL.
displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture(
specsFuture, pendingOptions.getOnAnimationStartListener(),
animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP);
@@ -1669,7 +1668,6 @@ final class ActivityRecord extends ConfigurationContainer {
.overridePendingAppTransitionStartCrossProfileApps();
break;
case ANIM_REMOTE_ANIMATION:
- // TODO(multidisplay): Will pass displayId and adjust dependencies from next CL.
displayContent.mAppTransition.overridePendingAppTransitionRemote(
pendingOptions.getRemoteAnimationAdapter());
break;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 0cdbedba7318..0fc890a39fed 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -402,7 +402,8 @@ public abstract class ActivityTaskManagerInternal {
int wakefulness);
/** Writes the current window process states to the proto stream. */
- public abstract void writeProcessesToProto(ProtoOutputStream proto, String dumpPackage);
+ public abstract void writeProcessesToProto(ProtoOutputStream proto, String dumpPackage,
+ int wakeFullness, boolean testPssMode);
/** Dump the current activities state. */
public abstract boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0967afda6d2d..61eb9d4b8abf 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -863,6 +863,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
*/
Configuration getGlobalConfigurationForCallingPid() {
final int pid = Binder.getCallingPid();
+ return getGlobalConfigurationForPid(pid);
+ }
+
+ /**
+ * Return the global configuration used by the process corresponding to the given pid.
+ */
+ Configuration getGlobalConfigurationForPid(int pid) {
if (pid == MY_PID || pid < 0) {
return getGlobalConfiguration();
}
@@ -4701,26 +4708,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
- void writeSleepStateToProto(ProtoOutputStream proto) {
+ private void writeSleepStateToProto(ProtoOutputStream proto, int wakeFullness,
+ boolean testPssMode) {
+ final long sleepToken = proto.start(ActivityManagerServiceDumpProcessesProto.SLEEP_STATUS);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.WAKEFULNESS,
+ PowerManagerInternal.wakefulnessToProtoEnum(wakeFullness));
for (ActivityTaskManagerInternal.SleepToken st : mRootActivityContainer.mSleepTokens) {
proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SLEEP_TOKENS,
st.toString());
}
-
- if (mRunningVoice != null) {
- final long vrToken = proto.start(
- ActivityManagerServiceDumpProcessesProto.RUNNING_VOICE);
- proto.write(ActivityManagerServiceDumpProcessesProto.Voice.SESSION,
- mRunningVoice.toString());
- mVoiceWakeLock.writeToProto(
- proto, ActivityManagerServiceDumpProcessesProto.Voice.WAKELOCK);
- proto.end(vrToken);
- }
-
proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SLEEPING, mSleeping);
proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.SHUTTING_DOWN,
mShuttingDown);
- mVrController.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.VR_CONTROLLER);
+ proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.TEST_PSS_MODE,
+ testPssMode);
+ proto.end(sleepToken);
}
int getCurrentUserId() {
@@ -6599,12 +6601,24 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void writeProcessesToProto(ProtoOutputStream proto, String dumpPackage) {
+ public void writeProcessesToProto(ProtoOutputStream proto, String dumpPackage,
+ int wakeFullness, boolean testPssMode) {
synchronized (mGlobalLock) {
if (dumpPackage == null) {
getGlobalConfiguration().writeToProto(proto, GLOBAL_CONFIGURATION);
proto.write(CONFIG_WILL_CHANGE, getTopDisplayFocusedStack().mConfigWillChange);
- writeSleepStateToProto(proto);
+ writeSleepStateToProto(proto, wakeFullness, testPssMode);
+ if (mRunningVoice != null) {
+ final long vrToken = proto.start(
+ ActivityManagerServiceDumpProcessesProto.RUNNING_VOICE);
+ proto.write(ActivityManagerServiceDumpProcessesProto.Voice.SESSION,
+ mRunningVoice.toString());
+ mVoiceWakeLock.writeToProto(
+ proto, ActivityManagerServiceDumpProcessesProto.Voice.WAKELOCK);
+ proto.end(vrToken);
+ }
+ mVrController.writeToProto(proto,
+ ActivityManagerServiceDumpProcessesProto.VR_CONTROLLER);
if (mController != null) {
final long token = proto.start(CONTROLLER);
proto.write(CONTROLLER, mController.toString());
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 64553a8c7ade..e779d1bb20f5 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -319,6 +319,13 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
onOverrideConfigurationChanged(mTmpConfig);
}
+ /** Sets the windowing mode for the configuration container. */
+ void setDisplayWindowingMode(int windowingMode) {
+ mTmpConfig.setTo(getOverrideConfiguration());
+ mTmpConfig.windowConfiguration.setDisplayWindowingMode(windowingMode);
+ onOverrideConfigurationChanged(mTmpConfig);
+ }
+
/**
* Returns true if this container is currently in multi-window mode. I.e. sharing the screen
* with another activity.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 05e82676a40a..aba2eb38ce15 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1546,6 +1546,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final int dh = displayInfo.logicalHeight;
config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
config.windowConfiguration.setWindowingMode(getWindowingMode());
+ config.windowConfiguration.setDisplayWindowingMode(getWindowingMode());
config.windowConfiguration.setRotation(displayInfo.rotation);
final float density = mDisplayMetrics.density;
@@ -1953,6 +1954,17 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mWmService.mWindowsChanged = true;
}
+ @Override
+ public void setWindowingMode(int windowingMode) {
+ super.setWindowingMode(windowingMode);
+ super.setDisplayWindowingMode(windowingMode);
+ }
+
+ @Override
+ void setDisplayWindowingMode(int windowingMode) {
+ setWindowingMode(windowingMode);
+ }
+
/**
* In split-screen mode we process the IME containers above the docked divider
* rather than directly above their target.
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 581cec928334..d4bd91b008d4 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -222,6 +222,7 @@ public class DisplayPolicy {
private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
private volatile boolean mHdmiPlugged;
+ private volatile boolean mHasStatusBar;
private volatile boolean mHasNavigationBar;
// Can the navigation bar ever move to the side?
private volatile boolean mNavigationBarCanMove;
@@ -523,6 +524,7 @@ public class DisplayPolicy {
mNavigationBarCanMove = width != height && shortSizeDp < 600;
if (mDisplayContent.isDefaultDisplay) {
+ mHasStatusBar = true;
mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
// Allow a system property to override this. Used by the emulator.
@@ -534,6 +536,7 @@ public class DisplayPolicy {
mHasNavigationBar = true;
}
} else {
+ mHasStatusBar = false;
mHasNavigationBar = mDisplayContent.getDisplay().supportsSystemDecorations();
}
}
@@ -589,6 +592,10 @@ public class DisplayPolicy {
return mHasNavigationBar;
}
+ public boolean hasStatusBar() {
+ return mHasStatusBar;
+ }
+
public boolean navigationBarCanMove() {
return mNavigationBarCanMove;
}
@@ -2493,12 +2500,19 @@ public class DisplayPolicy {
final int landscapeRotation = displayRotation.getLandscapeRotation();
final int seascapeRotation = displayRotation.getSeascapeRotation();
- mStatusBarHeightForRotation[portraitRotation] =
- mStatusBarHeightForRotation[upsideDownRotation] =
- res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
- mStatusBarHeightForRotation[landscapeRotation] =
- mStatusBarHeightForRotation[seascapeRotation] =
- res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
+ if (hasStatusBar()) {
+ mStatusBarHeightForRotation[portraitRotation] =
+ mStatusBarHeightForRotation[upsideDownRotation] =
+ res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
+ mStatusBarHeightForRotation[landscapeRotation] =
+ mStatusBarHeightForRotation[seascapeRotation] =
+ res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
+ } else {
+ mStatusBarHeightForRotation[portraitRotation] =
+ mStatusBarHeightForRotation[upsideDownRotation] =
+ mStatusBarHeightForRotation[landscapeRotation] =
+ mStatusBarHeightForRotation[seascapeRotation] = 0;
+ }
// Height of the navigation bar when presented horizontally at bottom
mNavigationBarHeightForRotationDefault[portraitRotation] =
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 88b22cb5e01e..c1e9a7353fd5 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -194,7 +194,7 @@ final class InputMonitor {
final boolean hasFocus, final boolean hasWallpaper) {
// Add a window to our list of input windows.
inputWindowHandle.name = child.toString();
- flags = child.getTouchableRegion(inputWindowHandle.touchableRegion, flags);
+ flags = child.getSurfaceTouchableRegion(inputWindowHandle.touchableRegion, flags);
inputWindowHandle.layoutParamsFlags = flags;
inputWindowHandle.layoutParamsType = type;
inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 58b7e02b3d12..83ba384c9069 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -504,10 +504,12 @@ public class RecentsAnimationController implements DeathRecipient {
public void binderDied() {
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
- // Clear associated input consumers on runner death
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
- inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
+ synchronized (mService.getWindowManagerLock()) {
+ // Clear associated input consumers on runner death
+ final InputMonitor inputMonitor =
+ mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
+ }
}
void checkAnimationReady(WallpaperController wallpaperController) {
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 4ae2a79e2697..1fb7979fa3e2 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -44,6 +44,7 @@ import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Build;
import android.util.Slog;
@@ -526,12 +527,24 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
adjustBoundsToAvoidConflict(display, inOutBounds);
}
+ private int convertOrientationToScreenOrientation(int orientation) {
+ switch (orientation) {
+ case Configuration.ORIENTATION_LANDSCAPE:
+ return SCREEN_ORIENTATION_LANDSCAPE;
+ case Configuration.ORIENTATION_PORTRAIT:
+ return SCREEN_ORIENTATION_PORTRAIT;
+ default:
+ return SCREEN_ORIENTATION_UNSPECIFIED;
+ }
+ }
+
private int resolveOrientation(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
@NonNull Rect bounds) {
int orientation = resolveOrientation(root);
if (orientation == SCREEN_ORIENTATION_LOCKED) {
- orientation = bounds.isEmpty() ? display.getConfiguration().orientation
+ orientation = bounds.isEmpty()
+ ? convertOrientationToScreenOrientation(display.getConfiguration().orientation)
: orientationFromBounds(bounds);
if (DEBUG) {
appendLog(bounds.isEmpty() ? "locked-orientation-from-display=" + orientation
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index e83b8634925e..9f1a58770611 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -19,7 +19,6 @@ package com.android.server.wm;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ClipData;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerInternal;
@@ -449,11 +448,4 @@ public abstract class WindowManagerInternal {
* Return the display Id for given window.
*/
public abstract int getDisplayIdForWindow(IBinder windowToken);
-
- // TODO: use WindowProcessController once go/wm-unified is done.
- /**
- * Notifies the window manager that configuration of the process associated with the input pid
- * changed.
- */
- public abstract void onProcessConfigurationChanged(int pid, Configuration newConfig);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 52b24b3e7307..002d6d409abe 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -735,6 +735,7 @@ public class WindowManagerService extends IWindowManager.Stub
final InputManagerService mInputManager;
final DisplayManagerInternal mDisplayManagerInternal;
final DisplayManager mDisplayManager;
+ final ActivityTaskManagerService mAtmService;
// Indicates whether this device supports wide color gamut / HDR rendering
private boolean mHasWideColorGamutSupport;
@@ -897,11 +898,10 @@ public class WindowManagerService extends IWindowManager.Stub
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
- final WindowManagerGlobalLock globalLock) {
+ ActivityTaskManagerService atm) {
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
- globalLock),
- 0);
+ atm), 0);
return sInstance;
}
@@ -923,9 +923,10 @@ public class WindowManagerService extends IWindowManager.Stub
private WindowManagerService(Context context, InputManagerService inputManager,
boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
- WindowManagerGlobalLock globalLock) {
+ ActivityTaskManagerService atm) {
installLock(this, INDEX_WINDOW);
- mGlobalLock = globalLock;
+ mGlobalLock = atm.getGlobalLock();
+ mAtmService = atm;
mContext = context;
mAllowBootMessages = showBootMsgs;
mOnlyCore = onlyCore;
@@ -7281,19 +7282,6 @@ public class WindowManagerService extends IWindowManager.Stub
return Display.INVALID_DISPLAY;
}
}
-
- @Override
- public void onProcessConfigurationChanged(int pid, Configuration newConfig) {
- synchronized (mGlobalLock) {
- Configuration currentConfig = mProcessConfigurations.get(pid);
- if (currentConfig == null) {
- currentConfig = new Configuration(newConfig);
- } else {
- currentConfig.setTo(newConfig);
- }
- mProcessConfigurations.put(pid, currentConfig);
- }
- }
}
void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ad43e74eca2f..e115fed4db9a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2143,7 +2143,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- int getTouchableRegion(Region region, int flags) {
+ int getSurfaceTouchableRegion(Region region, int flags) {
final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
if (modal && mAppToken != null) {
// Limit the outer touch to the activity stack region.
@@ -2171,12 +2171,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
region.translate(-mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top);
} else {
// Not modal or full screen modal
- getTouchableRegion(region);
+ getTouchableRegion(region, true /* forSurface */);
}
- // The area containing the shadows is not touchable.
- region.translate(mAttrs.surfaceInsets.left, mAttrs.surfaceInsets.top);
-
return flags;
}
@@ -2266,8 +2263,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// For child windows we want to use the pid for the parent window in case the the child
// window was added from another process.
final int pid = getParentWindow() != null ? getParentWindow().mSession.mPid : mSession.mPid;
- mTempConfiguration.setTo(mWmService.mProcessConfigurations.get(
- pid, mWmService.mRoot.getConfiguration()));
+ final Configuration processConfig =
+ mWmService.mAtmService.getGlobalConfigurationForPid(pid);
+ mTempConfiguration.setTo(processConfig == null
+ ? mWmService.mRoot.getConfiguration() : processConfig);
return mTempConfiguration;
}
@@ -2808,7 +2807,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
frame.right - inset.right, frame.bottom - inset.bottom);
}
+ /** Get the touchable region in global coordinates. */
void getTouchableRegion(Region outRegion) {
+ getTouchableRegion(outRegion, false /* forSurface */);
+ }
+
+ /** If {@param forSuface} is {@code true}, the region will be translated to surface based. */
+ private void getTouchableRegion(Region outRegion, boolean forSurface) {
if (inPinnedWindowingMode() && !isFocused()) {
outRegion.setEmpty();
return;
@@ -2819,22 +2824,26 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
default:
case TOUCHABLE_INSETS_FRAME:
outRegion.set(frame);
- outRegion.translate(-frame.left, -frame.top);
break;
case TOUCHABLE_INSETS_CONTENT:
applyInsets(outRegion, frame, mGivenContentInsets);
- outRegion.translate(-frame.left, -frame.top);
break;
case TOUCHABLE_INSETS_VISIBLE:
applyInsets(outRegion, frame, mGivenVisibleInsets);
- outRegion.translate(-frame.left, -frame.top);
break;
case TOUCHABLE_INSETS_REGION: {
outRegion.set(mGivenTouchableRegion);
break;
}
}
- outRegion.translate(mAttrs.surfaceInsets.left, mAttrs.surfaceInsets.top);
+
+ if (forSurface) {
+ if (mTouchableInsets != TOUCHABLE_INSETS_REGION) {
+ outRegion.translate(-frame.left, -frame.top);
+ }
+ outRegion.getBounds(mTmpRect);
+ applyInsets(outRegion, mTmpRect, mAttrs.surfaceInsets);
+ }
}
private void cropRegionToStackBoundsIfNeeded(Region region) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index b9dabb9ee7ec..65d32450b27f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -120,4 +120,9 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
int userHandle) {
return false;
}
+
+ @Override
+ public List<String> getCrossProfileCalendarPackagesForUser(int userHandle) {
+ return Collections.emptyList();
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6fbb850e4e40..f68f4d7424f4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -13426,10 +13426,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
enforceCrossUsersPermission(userHandle);
synchronized (getLockObject()) {
final ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
- if (admin != null && admin.mCrossProfileCalendarPackages != null) {
+ if (admin != null) {
return admin.mCrossProfileCalendarPackages.contains(packageName);
}
}
return false;
}
+
+ @Override
+ public List<String> getCrossProfileCalendarPackagesForUser(int userHandle) {
+ if (!mHasFeature) {
+ return Collections.emptyList();
+ }
+ enforceCrossUsersPermission(userHandle);
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
+ if (admin != null) {
+ return new ArrayList<String>(admin.mCrossProfileCalendarPackages);
+ }
+ }
+ return Collections.emptyList();
+ }
}
diff --git a/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java b/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java
index 14912c474995..05b8201f112e 100644
--- a/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java
+++ b/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java
@@ -16,6 +16,7 @@
package com.android.server.intelligence;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.os.IBinder;
@@ -25,12 +26,13 @@ import android.service.intelligence.SmartSuggestionsService;
import android.service.intelligence.SnapshotData;
import android.util.Slog;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import android.view.intelligence.ContentCaptureEvent;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
-import com.android.server.AbstractRemoteService;
+import com.android.server.infra.AbstractRemoteService;
import com.android.server.intelligence.IntelligenceManagerInternal.AugmentedAutofillCallback;
import com.android.server.intelligence.RemoteIntelligenceService.RemoteIntelligenceServiceCallbacks;
@@ -98,8 +100,10 @@ final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks
* Requests the service to autofill the given field.
*/
public AugmentedAutofillCallback requestAutofillLocked(@NonNull IAutoFillManagerClient client,
- int autofillSessionId, @NonNull AutofillId focusedId) {
- mRemoteService.onRequestAutofillLocked(mId, client, autofillSessionId, focusedId);
+ int autofillSessionId, @NonNull AutofillId focusedId,
+ @Nullable AutofillValue focusedValue) {
+ mRemoteService.onRequestAutofillLocked(mId, client, autofillSessionId, focusedId,
+ focusedValue);
if (mAutofillCallback == null) {
mAutofillCallback = () -> mRemoteService.onDestroyAutofillWindowsRequest(mId);
}
diff --git a/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java b/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java
index 4c68064b46f6..a760cbd039e4 100644
--- a/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java
+++ b/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java
@@ -35,6 +35,7 @@ import android.os.UserManager;
import android.service.intelligence.InteractionSessionId;
import android.util.Slog;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import android.view.intelligence.ContentCaptureEvent;
import android.view.intelligence.IIntelligenceManager;
@@ -43,8 +44,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
-import com.android.server.AbstractMasterSystemService;
import com.android.server.LocalServices;
+import com.android.server.infra.AbstractMasterSystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -65,6 +66,8 @@ public final class IntelligenceManagerService extends
static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
+ private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+
@GuardedBy("mLock")
private ActivityManagerInternal mAm;
@@ -75,12 +78,6 @@ public final class IntelligenceManagerService extends
}
@Override // from AbstractMasterSystemService
- protected String getServiceSettingsProperty() {
- // TODO(b/111276913): STOPSHIP temporary settings, until it's set by resourcs + cmd
- return "smart_suggestions_service";
- }
-
- @Override // from AbstractMasterSystemService
protected IntelligencePerUserService newServiceLocked(@UserIdInt int resolvedUserId,
boolean disabled) {
return new IntelligencePerUserService(this, mLock, resolvedUserId);
@@ -104,6 +101,11 @@ public final class IntelligenceManagerService extends
getContext().enforceCallingPermission(MANAGE_SMART_SUGGESTIONS, TAG);
}
+ @Override // from AbstractMasterSystemService
+ protected int getMaximumTemporaryServiceDurationMs() {
+ return MAX_TEMP_SERVICE_DURATION_MS;
+ }
+
// Called by Shell command.
void destroySessions(@UserIdInt int userId, @NonNull IResultReceiver receiver) {
Slog.i(TAG, "destroySessions() for userId " + userId);
@@ -256,12 +258,13 @@ public final class IntelligenceManagerService extends
@Override
public AugmentedAutofillCallback requestAutofill(@UserIdInt int userId,
@NonNull IAutoFillManagerClient client, @NonNull IBinder activityToken,
- int autofillSessionId, @NonNull AutofillId focusedId) {
+ int autofillSessionId, @NonNull AutofillId focusedId,
+ @Nullable AutofillValue focusedValue) {
synchronized (mLock) {
final IntelligencePerUserService service = peekServiceForUserLocked(userId);
if (service != null) {
return service.requestAutofill(client, activityToken, autofillSessionId,
- focusedId);
+ focusedId, focusedValue);
}
}
return null;
diff --git a/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java b/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java
index dbf8601849bb..c8448e142902 100644
--- a/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java
+++ b/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java
@@ -36,16 +36,18 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.service.intelligence.InteractionSessionId;
import android.service.intelligence.SnapshotData;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import android.view.intelligence.ContentCaptureEvent;
import android.view.intelligence.ContentCaptureManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
-import com.android.server.AbstractPerUserSystemService;
+import com.android.server.infra.AbstractPerUserSystemService;
import com.android.server.intelligence.IntelligenceManagerInternal.AugmentedAutofillCallback;
import java.io.PrintWriter;
@@ -77,17 +79,24 @@ final class IntelligencePerUserService
protected ServiceInfo newServiceInfo(@NonNull ComponentName serviceComponent)
throws NameNotFoundException {
+ int flags = PackageManager.GET_META_DATA;
+ final boolean isTemp = isTemporaryServiceSetLocked();
+ if (!isTemp) {
+ flags |= PackageManager.MATCH_SYSTEM_ONLY;
+ }
+
ServiceInfo si;
try {
- // TODO(b/111276913): must check that either the service is from a system component,
- // or it matches a service set by shell cmd (so it can be used on CTS tests and when
- // OEMs are implementing the real service
- si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
- PackageManager.GET_META_DATA, mUserId);
+ si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, flags, mUserId);
} catch (RemoteException e) {
Slog.w(TAG, "Could not get service for " + serviceComponent + ": " + e);
return null;
}
+ if (si == null) {
+ Slog.w(TAG, "Could not get serviceInfo for " + (isTemp ? " (temp)" : "(default system)")
+ + " " + serviceComponent.flattenToShortString());
+ return null;
+ }
if (!Manifest.permission.BIND_SMART_SUGGESTIONS_SERVICE.equals(si.permission)) {
Slog.w(TAG, "SmartSuggestionsService from '" + si.packageName
+ "' does not require permission "
@@ -105,6 +114,13 @@ final class IntelligencePerUserService
return super.updateLocked(disabled);
}
+ @Override // from PerUserSystemService
+ protected String getDefaultComponentName() {
+ final String name = getContext()
+ .getString(com.android.internal.R.string.config_defaultSmartSuggestionsService);
+ return TextUtils.isEmpty(name) ? null : name;
+ }
+
// TODO(b/111276913): log metrics
@GuardedBy("mLock")
public void startSessionLocked(@NonNull IBinder activityToken,
@@ -274,13 +290,15 @@ final class IntelligencePerUserService
}
public AugmentedAutofillCallback requestAutofill(@NonNull IAutoFillManagerClient client,
- @NonNull IBinder activityToken, int autofillSessionId, @NonNull AutofillId focusedId) {
+ @NonNull IBinder activityToken, int autofillSessionId, @NonNull AutofillId focusedId,
+ @Nullable AutofillValue focusedValue) {
synchronized (mLock) {
final ContentCaptureSession session = getSession(activityToken);
if (session != null) {
// TODO(b/111330312): log metrics
if (mMaster.verbose) Slog.v(TAG, "requestAugmentedAutofill()");
- return session.requestAutofillLocked(client, autofillSessionId, focusedId);
+ return session.requestAutofillLocked(client, autofillSessionId, focusedId,
+ focusedValue);
}
if (mMaster.debug) {
Slog.d(TAG, "requestAutofill(): no session for " + activityToken);
diff --git a/services/intelligence/java/com/android/server/intelligence/IntelligenceServiceShellCommand.java b/services/intelligence/java/com/android/server/intelligence/IntelligenceServiceShellCommand.java
index b7c1f789e46c..0d92a972aa96 100644
--- a/services/intelligence/java/com/android/server/intelligence/IntelligenceServiceShellCommand.java
+++ b/services/intelligence/java/com/android/server/intelligence/IntelligenceServiceShellCommand.java
@@ -75,6 +75,10 @@ public final class IntelligenceServiceShellCommand extends ShellCommand {
pw.println(" set bind-instant-service-allowed [true | false]");
pw.println(" Sets whether binding to services provided by instant apps is allowed");
pw.println("");
+ pw.println(" set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+ pw.println(" Temporarily (for DURATION ms) changes the service implemtation.");
+ pw.println(" To reset, call with just the USER_ID argument.");
+ pw.println("");
pw.println(" list sessions [--user USER_ID]");
pw.println(" Lists all pending sessions.");
pw.println("");
@@ -101,6 +105,8 @@ public final class IntelligenceServiceShellCommand extends ShellCommand {
switch(what) {
case "bind-instant-service-allowed":
return setBindInstantService(pw);
+ case "temporary-service":
+ return setTemporaryService();
default:
pw.println("Invalid set: " + what);
return -1;
@@ -131,6 +137,18 @@ public final class IntelligenceServiceShellCommand extends ShellCommand {
}
}
+ private int setTemporaryService() {
+ final int userId = getNextIntArgRequired();
+ final String serviceName = getNextArg();
+ if (serviceName == null) {
+ mService.resetTemporaryService(userId);
+ return 0;
+ }
+ final int duration = getNextIntArgRequired();
+ mService.setTemporaryService(userId, serviceName, duration);
+ return 0;
+ }
+
private int requestDestroy(PrintWriter pw) {
if (!isNextArgSessions(pw)) {
return -1;
@@ -204,4 +222,8 @@ public final class IntelligenceServiceShellCommand extends ShellCommand {
}
return UserHandle.USER_ALL;
}
+
+ private int getNextIntArgRequired() {
+ return Integer.parseInt(getNextArgRequired());
+ }
}
diff --git a/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java b/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java
index d9f4f20dc971..c4fbdca0ff2f 100644
--- a/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java
+++ b/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java
@@ -23,6 +23,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.service.intelligence.ContentCaptureEventsRequest;
import android.service.intelligence.IIntelligenceService;
import android.service.intelligence.InteractionContext;
@@ -32,11 +33,12 @@ import android.text.format.DateUtils;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
+import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import android.view.intelligence.ContentCaptureEvent;
import com.android.internal.os.IResultReceiver;
-import com.android.server.AbstractMultiplePendingRequestsRemoteService;
+import com.android.server.infra.AbstractMultiplePendingRequestsRemoteService;
import java.util.List;
@@ -114,10 +116,10 @@ final class RemoteIntelligenceService
*/
public void onRequestAutofillLocked(@NonNull InteractionSessionId sessionId,
@NonNull IAutoFillManagerClient client, int autofillSessionId,
- @NonNull AutofillId focusedId) {
+ @NonNull AutofillId focusedId, @Nullable AutofillValue focusedValue) {
cancelScheduledUnbind();
scheduleRequest(new PendingAutofillRequest(this, sessionId, client, autofillSessionId,
- focusedId));
+ focusedId, focusedValue));
}
/**
@@ -222,16 +224,20 @@ final class RemoteIntelligenceService
private static final class PendingAutofillRequest extends MyPendingRequest {
private final @NonNull AutofillId mFocusedId;
+ private final @Nullable AutofillValue mFocusedValue;
private final @NonNull IAutoFillManagerClient mClient;
private final int mAutofillSessionId;
+ private final long mRequestTime = SystemClock.elapsedRealtime();
protected PendingAutofillRequest(@NonNull RemoteIntelligenceService service,
@NonNull InteractionSessionId sessionId, @NonNull IAutoFillManagerClient client,
- int autofillSessionId, @NonNull AutofillId focusedId) {
+ int autofillSessionId, @NonNull AutofillId focusedId,
+ @Nullable AutofillValue focusedValue) {
super(service, sessionId);
mClient = client;
mAutofillSessionId = autofillSessionId;
mFocusedId = focusedId;
+ mFocusedValue = focusedValue;
}
@Override // from MyPendingRequest
@@ -243,7 +249,7 @@ final class RemoteIntelligenceService
final IBinder realClient = resultData
.getBinder(AutofillManager.EXTRA_AUGMENTED_AUTOFILL_CLIENT);
remoteService.mService.onAutofillRequest(mSessionId, realClient,
- mAutofillSessionId, mFocusedId);
+ mAutofillSessionId, mFocusedId, mFocusedValue, mRequestTime);
}
};
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9c6f4b356a0b..c4d2a914facf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -22,6 +22,7 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
import static android.view.Display.DEFAULT_DISPLAY;
+import android.annotation.NonNull;
import android.app.ActivityThread;
import android.app.INotificationManager;
import android.app.usage.UsageStatsManagerInternal;
@@ -55,7 +56,9 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.IStorageManager;
+import android.provider.Settings;
import android.sysprop.VoldProperties;
+import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Slog;
@@ -121,6 +124,7 @@ import com.android.server.restrictions.RestrictionsManagerService;
import com.android.server.role.RoleManagerService;
import com.android.server.security.KeyAttestationApplicationIdProviderService;
import com.android.server.security.KeyChainSystemService;
+import com.android.server.signedconfig.SignedConfigService;
import com.android.server.soundtrigger.SoundTriggerService;
import com.android.server.stats.StatsCompanionService;
import com.android.server.statusbar.StatusBarManagerService;
@@ -797,10 +801,6 @@ public final class SystemServer {
boolean disableSystemTextClassifier = SystemProperties.getBoolean(
"config.disable_systemtextclassifier", false);
- //TODO(b/111276913): temporarily disabled until the manager is properly implemented to
- // ignore events when disabled and buffer when enabled
- boolean disableIntelligence = SystemProperties.getBoolean(
- "config.disable_intelligence", true);
boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime",
false);
boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
@@ -926,7 +926,7 @@ public final class SystemServer {
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
mSensorServiceStart = null;
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
- new PhoneWindowManager(), mWindowManagerGlobalLock);
+ new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
@@ -995,6 +995,11 @@ public final class SystemServer {
traceBeginAndSlog("PinnerService");
mSystemServiceManager.startService(PinnerService.class);
traceEnd();
+
+ traceBeginAndSlog("SignedConfigService");
+ SignedConfigService.registerUpdateReceiver(mSystemContext);
+ traceEnd();
+
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
@@ -1131,13 +1136,7 @@ public final class SystemServer {
traceEnd();
}
- if (!disableIntelligence) {
- traceBeginAndSlog("StartIntelligenceService");
- mSystemServiceManager.startService(INTELLIGENCE_MANAGER_SERVICE_CLASS);
- traceEnd();
- } else {
- Slog.d(TAG, "IntelligenceService disabled");
- }
+ startIntelligenceService(context);
// NOTE: ClipboardService indirectly depends on IntelligenceService
traceBeginAndSlog("StartClipboardService");
@@ -2101,6 +2100,37 @@ public final class SystemServer {
}, BOOT_TIMINGS_TRACE_LOG);
}
+ private void startIntelligenceService(@NonNull Context context) {
+
+ // First check if it was explicitly enabled by Settings
+ boolean explicitlySupported = false;
+ final String settings = Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED);
+ if (settings != null) {
+ explicitlySupported = Boolean.parseBoolean(settings);
+ if (explicitlySupported) {
+ Slog.d(TAG, "IntelligenceService explicitly enabled by Settings");
+ } else {
+ Slog.d(TAG, "IntelligenceService explicitly disabled by Settings");
+ return;
+ }
+ }
+
+ // Then check if OEM overlaid the resource that defines the service.
+ if (!explicitlySupported) {
+ final String serviceName = context
+ .getString(com.android.internal.R.string.config_defaultSmartSuggestionsService);
+ if (TextUtils.isEmpty(serviceName)) {
+ Slog.d(TAG, "IntelligenceService disabled because config resource is not overlaid");
+ return;
+ }
+ }
+
+ traceBeginAndSlog("StartIntelligenceService");
+ mSystemServiceManager.startService(INTELLIGENCE_MANAGER_SERVICE_CLASS);
+ traceEnd();
+ }
+
static final void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
diff --git a/services/robotests/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManagerTest.java b/services/robotests/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManagerTest.java
new file mode 100644
index 000000000000..5342efa18a97
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyManagerTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2018 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.backup.encryption.keys;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.RecoveryController;
+
+import com.android.server.testing.shadows.ShadowInternalRecoveryServiceException;
+import com.android.server.testing.shadows.ShadowRecoveryController;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.security.SecureRandom;
+import java.util.Optional;
+
+/** Tests for {@link RecoverableKeyStoreSecondaryKeyManager}. */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+@Config(shadows = {ShadowRecoveryController.class, ShadowInternalRecoveryServiceException.class})
+public class RecoverableKeyStoreSecondaryKeyManagerTest {
+ private static final String BACKUP_KEY_ALIAS_PREFIX =
+ "com.android.server.backup/recoverablekeystore/";
+ private static final int BITS_PER_BYTE = 8;
+ private static final int BACKUP_KEY_SUFFIX_LENGTH_BYTES = 128 / BITS_PER_BYTE;
+ private static final int HEX_PER_BYTE = 2;
+ private static final int BACKUP_KEY_ALIAS_LENGTH =
+ BACKUP_KEY_ALIAS_PREFIX.length() + BACKUP_KEY_SUFFIX_LENGTH_BYTES * HEX_PER_BYTE;
+ private static final String NONEXISTENT_KEY_ALIAS = "NONEXISTENT_KEY_ALIAS";
+
+ private RecoverableKeyStoreSecondaryKeyManager mRecoverableKeyStoreSecondaryKeyManager;
+ private Context mContext;
+
+ /** Create a new {@link RecoverableKeyStoreSecondaryKeyManager} to use in tests. */
+ @Before
+ public void setUp() throws Exception {
+ mContext = RuntimeEnvironment.application;
+
+ mRecoverableKeyStoreSecondaryKeyManager =
+ new RecoverableKeyStoreSecondaryKeyManager(
+ RecoveryController.getInstance(mContext), new SecureRandom());
+ }
+
+ /** Reset the {@link ShadowRecoveryController}. */
+ @After
+ public void tearDown() throws Exception {
+ ShadowRecoveryController.reset();
+ }
+
+ /** The generated key should always have the prefix {@code BACKUP_KEY_ALIAS_PREFIX}. */
+ @Test
+ public void generate_generatesKeyWithExpectedPrefix() throws Exception {
+ RecoverableKeyStoreSecondaryKey key = mRecoverableKeyStoreSecondaryKeyManager.generate();
+
+ assertThat(key.getAlias()).startsWith(BACKUP_KEY_ALIAS_PREFIX);
+ }
+
+ /** The generated key should always have length {@code BACKUP_KEY_ALIAS_LENGTH}. */
+ @Test
+ public void generate_generatesKeyWithExpectedLength() throws Exception {
+ RecoverableKeyStoreSecondaryKey key = mRecoverableKeyStoreSecondaryKeyManager.generate();
+
+ assertThat(key.getAlias()).hasLength(BACKUP_KEY_ALIAS_LENGTH);
+ }
+
+ /** Ensure that hidden API exceptions are rethrown when generating keys. */
+ @Test
+ public void generate_encounteringHiddenApiException_rethrowsException() {
+ ShadowRecoveryController.setThrowsInternalError(true);
+
+ assertThrows(
+ InternalRecoveryServiceException.class,
+ mRecoverableKeyStoreSecondaryKeyManager::generate);
+ }
+
+ /** Ensure that retrieved keys correspond to those generated earlier. */
+ @Test
+ public void get_getsKeyGeneratedByController() throws Exception {
+ RecoverableKeyStoreSecondaryKey key = mRecoverableKeyStoreSecondaryKeyManager.generate();
+
+ Optional<RecoverableKeyStoreSecondaryKey> retrievedKey =
+ mRecoverableKeyStoreSecondaryKeyManager.get(key.getAlias());
+
+ assertThat(retrievedKey.isPresent()).isTrue();
+ assertThat(retrievedKey.get().getAlias()).isEqualTo(key.getAlias());
+ assertThat(retrievedKey.get().getSecretKey()).isEqualTo(key.getSecretKey());
+ }
+
+ /**
+ * Ensure that a call to {@link RecoverableKeyStoreSecondaryKeyManager#get(java.lang.String)}
+ * for nonexistent aliases returns an emtpy {@link Optional}.
+ */
+ @Test
+ public void get_forNonExistentKey_returnsEmptyOptional() throws Exception {
+ Optional<RecoverableKeyStoreSecondaryKey> retrievedKey =
+ mRecoverableKeyStoreSecondaryKeyManager.get(NONEXISTENT_KEY_ALIAS);
+
+ assertThat(retrievedKey.isPresent()).isFalse();
+ }
+
+ /**
+ * Ensure that exceptions occurring during {@link
+ * RecoverableKeyStoreSecondaryKeyManager#get(java.lang.String)} are not rethrown.
+ */
+ @Test
+ public void get_encounteringInternalException_doesNotPropagateException() throws Exception {
+ ShadowRecoveryController.setThrowsInternalError(true);
+
+ // Should not throw exception
+ mRecoverableKeyStoreSecondaryKeyManager.get(NONEXISTENT_KEY_ALIAS);
+ }
+
+ /** Ensure that keys are correctly removed from the store. */
+ @Test
+ public void remove_removesKeyFromRecoverableStore() throws Exception {
+ RecoverableKeyStoreSecondaryKey key = mRecoverableKeyStoreSecondaryKeyManager.generate();
+
+ mRecoverableKeyStoreSecondaryKeyManager.remove(key.getAlias());
+
+ assertThat(RecoveryController.getInstance(mContext).getAliases())
+ .doesNotContain(key.getAlias());
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyTest.java b/services/robotests/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyTest.java
new file mode 100644
index 000000000000..89977f82c145
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/keys/RecoverableKeyStoreSecondaryKeyTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 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.backup.encryption.keys;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.security.keystore.recovery.RecoveryController;
+
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey.Status;
+import com.android.server.backup.testing.CryptoTestUtils;
+import com.android.server.testing.shadows.ShadowInternalRecoveryServiceException;
+import com.android.server.testing.shadows.ShadowRecoveryController;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import javax.crypto.SecretKey;
+
+/** Tests for {@link RecoverableKeyStoreSecondaryKey}. */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+@Config(shadows = {ShadowRecoveryController.class, ShadowInternalRecoveryServiceException.class})
+public class RecoverableKeyStoreSecondaryKeyTest {
+ private static final String TEST_ALIAS = "test";
+ private static final int NONEXISTENT_STATUS_CODE = 42;
+
+ private RecoverableKeyStoreSecondaryKey mSecondaryKey;
+ private SecretKey mGeneratedSecretKey;
+ private Context mContext;
+
+ /** Instantiate a {@link RecoverableKeyStoreSecondaryKey} to use in tests. */
+ @Before
+ public void setUp() throws Exception {
+ mContext = RuntimeEnvironment.application;
+ mGeneratedSecretKey = CryptoTestUtils.generateAesKey();
+ mSecondaryKey = new RecoverableKeyStoreSecondaryKey(TEST_ALIAS, mGeneratedSecretKey);
+ }
+
+ /** Reset the {@link ShadowRecoveryController}. */
+ @After
+ public void tearDown() throws Exception {
+ ShadowRecoveryController.reset();
+ }
+
+ /**
+ * Checks that {@link RecoverableKeyStoreSecondaryKey#getAlias()} returns the value supplied in
+ * the constructor.
+ */
+ @Test
+ public void getAlias() {
+ String alias = mSecondaryKey.getAlias();
+
+ assertThat(alias).isEqualTo(TEST_ALIAS);
+ }
+
+ /**
+ * Checks that {@link RecoverableKeyStoreSecondaryKey#getSecretKey()} returns the value supplied
+ * in the constructor.
+ */
+ @Test
+ public void getSecretKey() {
+ SecretKey secretKey = mSecondaryKey.getSecretKey();
+
+ assertThat(secretKey).isEqualTo(mGeneratedSecretKey);
+ }
+
+ /**
+ * Checks that passing a secret key that is null to the constructor throws an exception.
+ */
+ @Test
+ public void constructor_withNullSecretKey_throwsNullPointerException() {
+ assertThrows(
+ NullPointerException.class,
+ () -> new RecoverableKeyStoreSecondaryKey(TEST_ALIAS, null));
+ }
+
+ /**
+ * Checks that passing an alias that is null to the constructor throws an exception.
+ */
+ @Test
+ public void constructor_withNullAlias_throwsNullPointerException() {
+ assertThrows(
+ NullPointerException.class,
+ () -> new RecoverableKeyStoreSecondaryKey(null, mGeneratedSecretKey));
+ }
+
+ /** Checks that the synced status is returned correctly. */
+ @Test
+ public void getStatus_whenSynced_returnsSynced() throws Exception {
+ setStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+
+ int status = mSecondaryKey.getStatus(mContext);
+
+ assertThat(status).isEqualTo(Status.SYNCED);
+ }
+
+ /** Checks that the in progress sync status is returned correctly. */
+ @Test
+ public void getStatus_whenNotSynced_returnsNotSynced() throws Exception {
+ setStatus(RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
+
+ int status = mSecondaryKey.getStatus(mContext);
+
+ assertThat(status).isEqualTo(Status.NOT_SYNCED);
+ }
+
+ /** Checks that the failure status is returned correctly. */
+ @Test
+ public void getStatus_onPermanentFailure_returnsDestroyed() throws Exception {
+ setStatus(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
+
+ int status = mSecondaryKey.getStatus(mContext);
+
+ assertThat(status).isEqualTo(Status.DESTROYED);
+ }
+
+ /** Checks that an unknown status results in {@code NOT_SYNCED} being returned. */
+ @Test
+ public void getStatus_forUnknownStatusCode_returnsNotSynced() throws Exception {
+ setStatus(NONEXISTENT_STATUS_CODE);
+
+ int status = mSecondaryKey.getStatus(mContext);
+
+ assertThat(status).isEqualTo(Status.NOT_SYNCED);
+ }
+
+ /** Checks that an internal error results in {@code NOT_SYNCED} being returned. */
+ @Test
+ public void getStatus_onInternalError_returnsNotSynced() throws Exception {
+ ShadowRecoveryController.setThrowsInternalError(true);
+
+ int status = mSecondaryKey.getStatus(mContext);
+
+ assertThat(status).isEqualTo(Status.NOT_SYNCED);
+ }
+
+ private void setStatus(int status) throws Exception {
+ ShadowRecoveryController.setRecoveryStatus(TEST_ALIAS, status);
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/encryption/keys/TertiaryKeyGeneratorTest.java b/services/robotests/src/com/android/server/backup/encryption/keys/TertiaryKeyGeneratorTest.java
new file mode 100644
index 000000000000..48216f8d7aca
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/keys/TertiaryKeyGeneratorTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 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.backup.encryption.keys;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.security.SecureRandom;
+
+import javax.crypto.SecretKey;
+
+/** Tests for {@link TertiaryKeyGenerator}. */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class TertiaryKeyGeneratorTest {
+ private static final String KEY_ALGORITHM = "AES";
+ private static final int KEY_SIZE_BITS = 256;
+
+ private TertiaryKeyGenerator mTertiaryKeyGenerator;
+
+ /** Instantiate a new {@link TertiaryKeyGenerator} for use in tests. */
+ @Before
+ public void setUp() {
+ mTertiaryKeyGenerator = new TertiaryKeyGenerator(new SecureRandom());
+ }
+
+ /** Generated keys should be AES keys. */
+ @Test
+ public void generate_generatesAESKeys() {
+ SecretKey secretKey = mTertiaryKeyGenerator.generate();
+
+ assertThat(secretKey.getAlgorithm()).isEqualTo(KEY_ALGORITHM);
+ }
+
+ /** Generated keys should be 256 bits in size. */
+ @Test
+ public void generate_generates256BitKeys() {
+ SecretKey secretKey = mTertiaryKeyGenerator.generate();
+
+ assertThat(secretKey.getEncoded()).hasLength(KEY_SIZE_BITS / 8);
+ }
+
+ /**
+ * Subsequent calls to {@link TertiaryKeyGenerator#generate()} should generate different keys.
+ */
+ @Test
+ public void generate_generatesNewKeys() {
+ SecretKey key1 = mTertiaryKeyGenerator.generate();
+ SecretKey key2 = mTertiaryKeyGenerator.generate();
+
+ assertThat(key1).isNotEqualTo(key2);
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/encryption/keys/TertiaryKeyRotationTrackerTest.java b/services/robotests/src/com/android/server/backup/encryption/keys/TertiaryKeyRotationTrackerTest.java
new file mode 100644
index 000000000000..49bb410ceb65
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/keys/TertiaryKeyRotationTrackerTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2018 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.backup.encryption.keys;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+/** Tests for {@link TertiaryKeyRotationTracker}. */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class TertiaryKeyRotationTrackerTest {
+ private static final String PACKAGE_1 = "com.package.one";
+ private static final int NUMBER_OF_BACKUPS_BEFORE_ROTATION = 31;
+
+ private TertiaryKeyRotationTracker mTertiaryKeyRotationTracker;
+
+ /** Instantiate a {@link TertiaryKeyRotationTracker} for use in tests. */
+ @Before
+ public void setUp() {
+ mTertiaryKeyRotationTracker = newInstance();
+ }
+
+ /** New packages should not be due for key rotation. */
+ @Test
+ public void isKeyRotationDue_forNewPackage_isFalse() {
+ // Simulate a new package by not calling simulateBackups(). As a result, PACKAGE_1 hasn't
+ // been seen by mTertiaryKeyRotationTracker before.
+ boolean keyRotationDue = mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1);
+
+ assertThat(keyRotationDue).isFalse();
+ }
+
+ /**
+ * Key rotation should not be due after less than {@code NUMBER_OF_BACKUPS_BEFORE_ROTATION}
+ * backups.
+ */
+ @Test
+ public void isKeyRotationDue_afterLessThanRotationAmountBackups_isFalse() {
+ simulateBackups(PACKAGE_1, NUMBER_OF_BACKUPS_BEFORE_ROTATION - 1);
+
+ boolean keyRotationDue = mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1);
+
+ assertThat(keyRotationDue).isFalse();
+ }
+
+ /** Key rotation should be due after {@code NUMBER_OF_BACKUPS_BEFORE_ROTATION} backups. */
+ @Test
+ public void isKeyRotationDue_afterRotationAmountBackups_isTrue() {
+ simulateBackups(PACKAGE_1, NUMBER_OF_BACKUPS_BEFORE_ROTATION);
+
+ boolean keyRotationDue = mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1);
+
+ assertThat(keyRotationDue).isTrue();
+ }
+
+ /**
+ * A call to {@link TertiaryKeyRotationTracker#resetCountdown(String)} should make sure no key
+ * rotation is due.
+ */
+ @Test
+ public void resetCountdown_makesKeyRotationNotDue() {
+ simulateBackups(PACKAGE_1, NUMBER_OF_BACKUPS_BEFORE_ROTATION);
+
+ mTertiaryKeyRotationTracker.resetCountdown(PACKAGE_1);
+
+ assertThat(mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1)).isFalse();
+ }
+
+ /**
+ * New instances of {@link TertiaryKeyRotationTracker} should read state about the number of
+ * backups from disk.
+ */
+ @Test
+ public void isKeyRotationDue_forNewInstance_readsStateFromDisk() {
+ simulateBackups(PACKAGE_1, NUMBER_OF_BACKUPS_BEFORE_ROTATION);
+
+ boolean keyRotationDueForNewInstance = newInstance().isKeyRotationDue(PACKAGE_1);
+
+ assertThat(keyRotationDueForNewInstance).isTrue();
+ }
+
+ /**
+ * A call to {@link TertiaryKeyRotationTracker#markAllForRotation()} should mark all previously
+ * seen packages for rotation.
+ */
+ @Test
+ public void markAllForRotation_marksSeenPackagesForKeyRotation() {
+ simulateBackups(PACKAGE_1, /*numberOfBackups=*/ 1);
+
+ mTertiaryKeyRotationTracker.markAllForRotation();
+
+ assertThat(mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1)).isTrue();
+ }
+
+ /**
+ * A call to {@link TertiaryKeyRotationTracker#markAllForRotation()} should not mark any new
+ * packages for rotation.
+ */
+ @Test
+ public void markAllForRotation_doesNotMarkUnseenPackages() {
+ mTertiaryKeyRotationTracker.markAllForRotation();
+
+ assertThat(mTertiaryKeyRotationTracker.isKeyRotationDue(PACKAGE_1)).isFalse();
+ }
+
+ private void simulateBackups(String packageName, int numberOfBackups) {
+ while (numberOfBackups > 0) {
+ mTertiaryKeyRotationTracker.recordBackup(packageName);
+ numberOfBackups--;
+ }
+ }
+
+ private static TertiaryKeyRotationTracker newInstance() {
+ return TertiaryKeyRotationTracker.getInstance(RuntimeEnvironment.application);
+ }
+}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowInternalRecoveryServiceException.java b/services/robotests/src/com/android/server/testing/shadows/ShadowInternalRecoveryServiceException.java
new file mode 100644
index 000000000000..9c06d81ce550
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowInternalRecoveryServiceException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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.testing.shadows;
+
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+/** Shadow {@link InternalRecoveryServiceException}. */
+@Implements(InternalRecoveryServiceException.class)
+public class ShadowInternalRecoveryServiceException {
+ private String mMessage;
+
+ @Implementation
+ public void __constructor__(String message) {
+ mMessage = message;
+ }
+
+ @Implementation
+ public void __constructor__(String message, Throwable cause) {
+ mMessage = message;
+ }
+
+ @Implementation
+ public String getMessage() {
+ return mMessage;
+ }
+}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowRecoveryController.java b/services/robotests/src/com/android/server/testing/shadows/ShadowRecoveryController.java
new file mode 100644
index 000000000000..7dad8a4e3ff3
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowRecoveryController.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 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.testing.shadows;
+
+import android.content.Context;
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.LockScreenRequiredException;
+import android.security.keystore.recovery.RecoveryController;
+
+import com.google.common.collect.ImmutableList;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import java.lang.reflect.Constructor;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.crypto.KeyGenerator;
+
+/**
+ * Shadow of {@link RecoveryController}.
+ *
+ * <p>Instead of generating keys via the {@link RecoveryController}, this shadow generates them in
+ * memory.
+ */
+@Implements(RecoveryController.class)
+public class ShadowRecoveryController {
+ private static final String KEY_GENERATOR_ALGORITHM = "AES";
+ private static final int KEY_SIZE_BITS = 256;
+
+ private static boolean sIsSupported = true;
+ private static boolean sThrowsInternalError = false;
+ private static HashMap<String, Key> sKeysByAlias = new HashMap<>();
+ private static HashMap<String, Integer> sKeyStatusesByAlias = new HashMap<>();
+
+ @Implementation
+ public void __constructor__() {
+ // do not throw
+ }
+
+ @Implementation
+ public static RecoveryController getInstance(Context context) {
+ // Call non-public constructor.
+ try {
+ Constructor<RecoveryController> constructor = RecoveryController.class.getConstructor();
+ return constructor.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Implementation
+ public static boolean isRecoverableKeyStoreEnabled(Context context) {
+ return sIsSupported;
+ }
+
+ @Implementation
+ public Key generateKey(String alias)
+ throws InternalRecoveryServiceException, LockScreenRequiredException {
+ maybeThrowError();
+ KeyGenerator keyGenerator;
+ try {
+ keyGenerator = KeyGenerator.getInstance(KEY_GENERATOR_ALGORITHM);
+ } catch (NoSuchAlgorithmException e) {
+ // Should never happen
+ throw new RuntimeException(e);
+ }
+
+ keyGenerator.init(KEY_SIZE_BITS);
+ Key key = keyGenerator.generateKey();
+ sKeysByAlias.put(alias, key);
+ sKeyStatusesByAlias.put(alias, RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
+ return key;
+ }
+
+ @Implementation
+ public Key getKey(String alias)
+ throws InternalRecoveryServiceException, UnrecoverableKeyException {
+ return sKeysByAlias.get(alias);
+ }
+
+ @Implementation
+ public void removeKey(String alias) throws InternalRecoveryServiceException {
+ sKeyStatusesByAlias.remove(alias);
+ sKeysByAlias.remove(alias);
+ }
+
+ @Implementation
+ public int getRecoveryStatus(String alias) throws InternalRecoveryServiceException {
+ maybeThrowError();
+ return sKeyStatusesByAlias.getOrDefault(
+ alias, RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
+ }
+
+ @Implementation
+ public List<String> getAliases() throws InternalRecoveryServiceException {
+ return ImmutableList.copyOf(sKeyStatusesByAlias.keySet());
+ }
+
+ private static void maybeThrowError() throws InternalRecoveryServiceException {
+ if (sThrowsInternalError) {
+ throw new InternalRecoveryServiceException("test error");
+ }
+ }
+
+ /** Sets the recovery status of the key with {@code alias} to {@code status}. */
+ public static void setRecoveryStatus(String alias, int status) {
+ sKeyStatusesByAlias.put(alias, status);
+ }
+
+ /** Sets all existing keys to being synced. */
+ public static void syncAllKeys() {
+ for (String alias : sKeysByAlias.keySet()) {
+ sKeyStatusesByAlias.put(alias, RecoveryController.RECOVERY_STATUS_SYNCED);
+ }
+ }
+
+ public static void setThrowsInternalError(boolean throwsInternalError) {
+ ShadowRecoveryController.sThrowsInternalError = throwsInternalError;
+ }
+
+ public static void setIsSupported(boolean isSupported) {
+ ShadowRecoveryController.sIsSupported = isSupported;
+ }
+
+ @Resetter
+ public static void reset() {
+ sIsSupported = true;
+ sThrowsInternalError = false;
+ sKeysByAlias.clear();
+ sKeyStatusesByAlias.clear();
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
new file mode 100644
index 000000000000..b2ec83583eba
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -0,0 +1,842 @@
+/*
+ * Copyright (C) 2018 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.job.controllers;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
+import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX;
+import static com.android.server.job.JobSchedulerService.RARE_INDEX;
+import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.AlarmManager;
+import android.app.job.JobInfo;
+import android.app.usage.UsageStatsManager;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManagerInternal;
+import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobSchedulerService.Constants;
+import com.android.server.job.controllers.QuotaController.TimingSession;
+
+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.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class QuotaControllerTest {
+ private static final long SECOND_IN_MILLIS = 1000L;
+ private static final long MINUTE_IN_MILLIS = 60 * SECOND_IN_MILLIS;
+ private static final long HOUR_IN_MILLIS = 60 * MINUTE_IN_MILLIS;
+ private static final String TAG_CLEANUP = "*job.cleanup*";
+ private static final String TAG_QUOTA_CHECK = "*job.quota_check*";
+ private static final long IN_QUOTA_BUFFER_MILLIS = 30 * SECOND_IN_MILLIS;
+ private static final int CALLING_UID = 1000;
+ private static final String SOURCE_PACKAGE = "com.android.frameworks.mockingservicestests";
+ private static final int SOURCE_USER_ID = 0;
+
+ private BroadcastReceiver mChargingReceiver;
+ private Constants mConstants;
+ private QuotaController mQuotaController;
+
+ private MockitoSession mMockingSession;
+ @Mock
+ private AlarmManager mAlarmManager;
+ @Mock
+ private Context mContext;
+ @Mock
+ private JobSchedulerService mJobSchedulerService;
+ @Mock
+ private UsageStatsManagerInternal mUsageStatsManager;
+
+ @Before
+ public void setUp() {
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .mockStatic(LocalServices.class)
+ .startMocking();
+ // Make sure constants turn on QuotaController.
+ mConstants = new Constants();
+ mConstants.USE_HEARTBEATS = false;
+
+ // Called in StateController constructor.
+ when(mJobSchedulerService.getTestableContext()).thenReturn(mContext);
+ when(mJobSchedulerService.getLock()).thenReturn(mJobSchedulerService);
+ when(mJobSchedulerService.getConstants()).thenReturn(mConstants);
+ // Called in QuotaController constructor.
+ when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+ when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
+ doReturn(mock(BatteryManagerInternal.class))
+ .when(() -> LocalServices.getService(BatteryManagerInternal.class));
+ doReturn(mUsageStatsManager)
+ .when(() -> LocalServices.getService(UsageStatsManagerInternal.class));
+ // Used in JobStatus.
+ doReturn(mock(PackageManagerInternal.class))
+ .when(() -> LocalServices.getService(PackageManagerInternal.class));
+
+ // Freeze the clocks at this moment in time
+ JobSchedulerService.sSystemClock =
+ Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
+ JobSchedulerService.sUptimeMillisClock =
+ Clock.fixed(SystemClock.uptimeMillisClock().instant(), ZoneOffset.UTC);
+ JobSchedulerService.sElapsedRealtimeClock =
+ Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
+
+ // Initialize real objects.
+ // Capture the listeners.
+ ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ mQuotaController = new QuotaController(mJobSchedulerService);
+
+ verify(mContext).registerReceiver(receiverCaptor.capture(), any());
+ mChargingReceiver = receiverCaptor.getValue();
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ private Clock getAdvancedClock(Clock clock, long incrementMs) {
+ return Clock.offset(clock, Duration.ofMillis(incrementMs));
+ }
+
+ private void advanceElapsedClock(long incrementMs) {
+ JobSchedulerService.sElapsedRealtimeClock = getAdvancedClock(
+ JobSchedulerService.sElapsedRealtimeClock, incrementMs);
+ }
+
+ private void setCharging() {
+ Intent intent = new Intent(BatteryManager.ACTION_CHARGING);
+ mChargingReceiver.onReceive(mContext, intent);
+ }
+
+ private void setDischarging() {
+ Intent intent = new Intent(BatteryManager.ACTION_DISCHARGING);
+ mChargingReceiver.onReceive(mContext, intent);
+ }
+
+ private void setStandbyBucket(int bucketIndex) {
+ int bucket;
+ switch (bucketIndex) {
+ case ACTIVE_INDEX:
+ bucket = UsageStatsManager.STANDBY_BUCKET_ACTIVE;
+ break;
+ case WORKING_INDEX:
+ bucket = UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
+ break;
+ case FREQUENT_INDEX:
+ bucket = UsageStatsManager.STANDBY_BUCKET_FREQUENT;
+ break;
+ case RARE_INDEX:
+ bucket = UsageStatsManager.STANDBY_BUCKET_RARE;
+ break;
+ default:
+ bucket = UsageStatsManager.STANDBY_BUCKET_NEVER;
+ }
+ when(mUsageStatsManager.getAppStandbyBucket(eq(SOURCE_PACKAGE), eq(SOURCE_USER_ID),
+ anyLong())).thenReturn(bucket);
+ }
+
+ private void setStandbyBucket(int bucketIndex, JobStatus job) {
+ setStandbyBucket(bucketIndex);
+ job.setStandbyBucket(bucketIndex);
+ }
+
+ private JobStatus createJobStatus(String testTag, int jobId) {
+ JobInfo jobInfo = new JobInfo.Builder(jobId,
+ new ComponentName(mContext, "TestQuotaJobService"))
+ .setMinimumLatency(Math.abs(jobId) + 1)
+ .build();
+ return JobStatus.createFromJobInfo(
+ jobInfo, CALLING_UID, SOURCE_PACKAGE, SOURCE_USER_ID, testTag);
+ }
+
+ private TimingSession createTimingSession(long start, long duration, int count) {
+ return new TimingSession(start, start + duration, count);
+ }
+
+ @Test
+ public void testSaveTimingSession() {
+ assertNull(mQuotaController.getTimingSessions(0, "com.android.test"));
+
+ List<TimingSession> expected = new ArrayList<>();
+ TimingSession one = new TimingSession(1, 10, 1);
+ TimingSession two = new TimingSession(11, 20, 2);
+ TimingSession thr = new TimingSession(21, 30, 3);
+
+ mQuotaController.saveTimingSession(0, "com.android.test", one);
+ expected.add(one);
+ assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test"));
+
+ mQuotaController.saveTimingSession(0, "com.android.test", two);
+ expected.add(two);
+ assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test"));
+
+ mQuotaController.saveTimingSession(0, "com.android.test", thr);
+ expected.add(thr);
+ assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test"));
+ }
+
+ @Test
+ public void testDeleteObsoleteSessionsLocked() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ TimingSession one = createTimingSession(
+ now - 10 * MINUTE_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3);
+ TimingSession two = createTimingSession(
+ now - (70 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1);
+ TimingSession thr = createTimingSession(
+ now - (3 * HOUR_IN_MILLIS + 10 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1);
+ // Overlaps 24 hour boundary.
+ TimingSession fou = createTimingSession(
+ now - (24 * HOUR_IN_MILLIS + 2 * MINUTE_IN_MILLIS), 7 * MINUTE_IN_MILLIS, 1);
+ // Way past the 24 hour boundary.
+ TimingSession fiv = createTimingSession(
+ now - (25 * HOUR_IN_MILLIS), 5 * MINUTE_IN_MILLIS, 4);
+ List<TimingSession> expected = new ArrayList<>();
+ // Added in correct (chronological) order.
+ expected.add(fou);
+ expected.add(thr);
+ expected.add(two);
+ expected.add(one);
+ mQuotaController.saveTimingSession(0, "com.android.test", fiv);
+ mQuotaController.saveTimingSession(0, "com.android.test", fou);
+ mQuotaController.saveTimingSession(0, "com.android.test", thr);
+ mQuotaController.saveTimingSession(0, "com.android.test", two);
+ mQuotaController.saveTimingSession(0, "com.android.test", one);
+
+ mQuotaController.deleteObsoleteSessionsLocked();
+
+ assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test"));
+ }
+
+ @Test
+ public void testGetTrailingExecutionTimeLocked_NoTimer() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ // Added in chronological order.
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(
+ now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5));
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1));
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(
+ now - (HOUR_IN_MILLIS - 10 * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS, 1));
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 5 * MINUTE_IN_MILLIS, 4 * MINUTE_IN_MILLIS, 3));
+
+ assertEquals(0, mQuotaController.getTrailingExecutionTimeLocked(0, "com.android.test",
+ MINUTE_IN_MILLIS));
+ assertEquals(2 * MINUTE_IN_MILLIS,
+ mQuotaController.getTrailingExecutionTimeLocked(0, "com.android.test",
+ 3 * MINUTE_IN_MILLIS));
+ assertEquals(4 * MINUTE_IN_MILLIS,
+ mQuotaController.getTrailingExecutionTimeLocked(0, "com.android.test",
+ 5 * MINUTE_IN_MILLIS));
+ assertEquals(4 * MINUTE_IN_MILLIS,
+ mQuotaController.getTrailingExecutionTimeLocked(0, "com.android.test",
+ 49 * MINUTE_IN_MILLIS));
+ assertEquals(5 * MINUTE_IN_MILLIS,
+ mQuotaController.getTrailingExecutionTimeLocked(0, "com.android.test",
+ 50 * MINUTE_IN_MILLIS));
+ assertEquals(6 * MINUTE_IN_MILLIS,
+ mQuotaController.getTrailingExecutionTimeLocked(0, "com.android.test",
+ HOUR_IN_MILLIS));
+ assertEquals(11 * MINUTE_IN_MILLIS,
+ mQuotaController.getTrailingExecutionTimeLocked(0, "com.android.test",
+ 2 * HOUR_IN_MILLIS));
+ assertEquals(12 * MINUTE_IN_MILLIS,
+ mQuotaController.getTrailingExecutionTimeLocked(0, "com.android.test",
+ 3 * HOUR_IN_MILLIS));
+ assertEquals(22 * MINUTE_IN_MILLIS,
+ mQuotaController.getTrailingExecutionTimeLocked(0, "com.android.test",
+ 6 * HOUR_IN_MILLIS));
+ }
+
+ @Test
+ public void testMaybeScheduleCleanupAlarmLocked() {
+ // No sessions saved yet.
+ mQuotaController.maybeScheduleCleanupAlarmLocked();
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_CLEANUP), any(), any());
+
+ // Test with only one timing session saved.
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final long end = now - (6 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS);
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ new TimingSession(now - 6 * HOUR_IN_MILLIS, end, 1));
+ mQuotaController.maybeScheduleCleanupAlarmLocked();
+ verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(end + 24 * HOUR_IN_MILLIS), eq(TAG_CLEANUP), any(), any());
+
+ // Test with new (more recent) timing sessions saved. AlarmManger shouldn't be called again.
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1));
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleCleanupAlarmLocked();
+ verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(end + 24 * HOUR_IN_MILLIS), eq(TAG_CLEANUP), any(), any());
+ }
+
+ @Test
+ public void testMaybeScheduleStartAlarmLocked_WorkingSet() {
+ // saveTimingSession calls maybeScheduleCleanupAlarmLocked which interferes with these tests
+ // because it schedules an alarm too. Prevent it from doing so.
+ spyOn(mQuotaController);
+ doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked();
+
+ // Working set window size is 2 hours.
+ final int standbyBucket = WORKING_INDEX;
+
+ // No sessions saved yet.
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Test with timing sessions out of window.
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 10 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Test with timing sessions in window but still in quota.
+ final long end = now - (2 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS);
+ // Counting backwards, the quota will come back one minute before the end.
+ final long expectedAlarmTime =
+ end - MINUTE_IN_MILLIS + 2 * HOUR_IN_MILLIS + IN_QUOTA_BUFFER_MILLIS;
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ new TimingSession(now - 2 * HOUR_IN_MILLIS, end, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Add some more sessions, but still in quota.
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1));
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - (50 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Test when out of quota.
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 30 * MINUTE_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Alarm already scheduled, so make sure it's not scheduled again.
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+ }
+
+ @Test
+ public void testMaybeScheduleStartAlarmLocked_Frequent() {
+ // saveTimingSession calls maybeScheduleCleanupAlarmLocked which interferes with these tests
+ // because it schedules an alarm too. Prevent it from doing so.
+ spyOn(mQuotaController);
+ doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked();
+
+ // Frequent window size is 8 hours.
+ final int standbyBucket = FREQUENT_INDEX;
+
+ // No sessions saved yet.
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Test with timing sessions out of window.
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 10 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Test with timing sessions in window but still in quota.
+ final long start = now - (6 * HOUR_IN_MILLIS);
+ final long expectedAlarmTime = start + 8 * HOUR_IN_MILLIS + IN_QUOTA_BUFFER_MILLIS;
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Add some more sessions, but still in quota.
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1));
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Test when out of quota.
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Alarm already scheduled, so make sure it's not scheduled again.
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+ }
+
+ @Test
+ public void testMaybeScheduleStartAlarmLocked_Rare() {
+ // saveTimingSession calls maybeScheduleCleanupAlarmLocked which interferes with these tests
+ // because it schedules an alarm too. Prevent it from doing so.
+ spyOn(mQuotaController);
+ doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked();
+
+ // Rare window size is 24 hours.
+ final int standbyBucket = RARE_INDEX;
+
+ // No sessions saved yet.
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Test with timing sessions out of window.
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 25 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Test with timing sessions in window but still in quota.
+ final long start = now - (6 * HOUR_IN_MILLIS);
+ // Counting backwards, the first minute in the session is over the allowed time, so it
+ // needs to be excluded.
+ final long expectedAlarmTime =
+ start + MINUTE_IN_MILLIS + 24 * HOUR_IN_MILLIS + IN_QUOTA_BUFFER_MILLIS;
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Add some more sessions, but still in quota.
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1));
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Test when out of quota.
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - HOUR_IN_MILLIS, 2 * MINUTE_IN_MILLIS, 1));
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // Alarm already scheduled, so make sure it's not scheduled again.
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
+ verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+ }
+
+ /** Tests that the start alarm is properly rescheduled if the app's bucket is changed. */
+ @Test
+ public void testMaybeScheduleStartAlarmLocked_BucketChange() {
+ // saveTimingSession calls maybeScheduleCleanupAlarmLocked which interferes with these tests
+ // because it schedules an alarm too. Prevent it from doing so.
+ spyOn(mQuotaController);
+ doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked();
+
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+
+ // Affects rare bucket
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 12 * HOUR_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3));
+ // Affects frequent and rare buckets
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 4 * HOUR_IN_MILLIS, 4 * MINUTE_IN_MILLIS, 3));
+ // Affects working, frequent, and rare buckets
+ final long outOfQuotaTime = now - HOUR_IN_MILLIS;
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(outOfQuotaTime, 7 * MINUTE_IN_MILLIS, 10));
+ // Affects all buckets
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - 5 * MINUTE_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 3));
+
+ InOrder inOrder = inOrder(mAlarmManager);
+
+ // Start in ACTIVE bucket.
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", ACTIVE_INDEX);
+ inOrder.verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any());
+ inOrder.verify(mAlarmManager, never()).cancel(any(AlarmManager.OnAlarmListener.class));
+
+ // And down from there.
+ final long expectedWorkingAlarmTime =
+ outOfQuotaTime + (2 * HOUR_IN_MILLIS) + IN_QUOTA_BUFFER_MILLIS;
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", WORKING_INDEX);
+ inOrder.verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+ final long expectedFrequentAlarmTime =
+ outOfQuotaTime + (8 * HOUR_IN_MILLIS) + IN_QUOTA_BUFFER_MILLIS;
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", FREQUENT_INDEX);
+ inOrder.verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedFrequentAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+ final long expectedRareAlarmTime =
+ outOfQuotaTime + (24 * HOUR_IN_MILLIS) + IN_QUOTA_BUFFER_MILLIS;
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", RARE_INDEX);
+ inOrder.verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedRareAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+ // And back up again.
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", FREQUENT_INDEX);
+ inOrder.verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedFrequentAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", WORKING_INDEX);
+ inOrder.verify(mAlarmManager, times(1))
+ .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+ mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", ACTIVE_INDEX);
+ inOrder.verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any());
+ inOrder.verify(mAlarmManager, times(1)).cancel(any(AlarmManager.OnAlarmListener.class));
+ }
+
+ /** Tests that QuotaController doesn't throttle if throttling is turned off. */
+ @Test
+ public void testThrottleToggling() throws Exception {
+ setDischarging();
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
+ 10 * MINUTE_IN_MILLIS, 4));
+ JobStatus jobStatus = createJobStatus("testThrottleToggling", 1);
+ setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+ assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+ mConstants.USE_HEARTBEATS = true;
+ mQuotaController.onConstantsUpdatedLocked();
+ Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background.
+ assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+
+ mConstants.USE_HEARTBEATS = false;
+ mQuotaController.onConstantsUpdatedLocked();
+ Thread.sleep(SECOND_IN_MILLIS); // Job updates are done in the background.
+ assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ }
+
+ @Test
+ public void testConstantsUpdating_ValidValues() {
+ mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = 5 * MINUTE_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = 2 * MINUTE_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = 15 * MINUTE_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = 30 * MINUTE_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 45 * MINUTE_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = 60 * MINUTE_IN_MILLIS;
+
+ mQuotaController.onConstantsUpdatedLocked();
+
+ assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
+ assertEquals(2 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
+ assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[ACTIVE_INDEX]);
+ assertEquals(30 * MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[WORKING_INDEX]);
+ assertEquals(45 * MINUTE_IN_MILLIS,
+ mQuotaController.getBucketWindowSizes()[FREQUENT_INDEX]);
+ assertEquals(60 * MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[RARE_INDEX]);
+ }
+
+ @Test
+ public void testConstantsUpdating_InvalidValues() {
+ // Test negatives
+ mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = -MINUTE_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = -MINUTE_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = -MINUTE_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = -MINUTE_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = -MINUTE_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = -MINUTE_IN_MILLIS;
+
+ mQuotaController.onConstantsUpdatedLocked();
+
+ assertEquals(MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
+ assertEquals(0, mQuotaController.getInQuotaBufferMs());
+ assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[ACTIVE_INDEX]);
+ assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[WORKING_INDEX]);
+ assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[FREQUENT_INDEX]);
+ assertEquals(MINUTE_IN_MILLIS, mQuotaController.getBucketWindowSizes()[RARE_INDEX]);
+
+ // Test larger than a day. Controller should cap at one day.
+ mConstants.QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS = 25 * HOUR_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS = 25 * HOUR_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS = 25 * HOUR_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS = 25 * HOUR_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS = 25 * HOUR_IN_MILLIS;
+ mConstants.QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS = 25 * HOUR_IN_MILLIS;
+
+ mQuotaController.onConstantsUpdatedLocked();
+
+ assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
+ assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
+ assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getBucketWindowSizes()[ACTIVE_INDEX]);
+ assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getBucketWindowSizes()[WORKING_INDEX]);
+ assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getBucketWindowSizes()[FREQUENT_INDEX]);
+ assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getBucketWindowSizes()[RARE_INDEX]);
+ }
+
+ /** Tests that TimingSessions aren't saved when the device is charging. */
+ @Test
+ public void testTimerTracking_Charging() {
+ setCharging();
+
+ JobStatus jobStatus = createJobStatus("testTimerTracking_Charging", 1);
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+
+ assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ mQuotaController.prepareForExecutionLocked(jobStatus);
+ advanceElapsedClock(5 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
+
+ /** Tests that TimingSessions are saved properly when the device is discharging. */
+ @Test
+ public void testTimerTracking_Discharging() {
+ setDischarging();
+
+ JobStatus jobStatus = createJobStatus("testTimerTracking_Discharging", 1);
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+
+ assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ List<TimingSession> expected = new ArrayList<>();
+
+ long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.prepareForExecutionLocked(jobStatus);
+ advanceElapsedClock(5 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ expected.add(createTimingSession(start, 5 * SECOND_IN_MILLIS, 1));
+ assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // Test overlapping jobs.
+ JobStatus jobStatus2 = createJobStatus("testTimerTracking_Discharging", 2);
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null);
+
+ JobStatus jobStatus3 = createJobStatus("testTimerTracking_Discharging", 3);
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null);
+
+ advanceElapsedClock(SECOND_IN_MILLIS);
+
+ start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+ mQuotaController.prepareForExecutionLocked(jobStatus);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.prepareForExecutionLocked(jobStatus2);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.prepareForExecutionLocked(jobStatus3);
+ advanceElapsedClock(20 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ expected.add(createTimingSession(start, MINUTE_IN_MILLIS, 3));
+ assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
+
+ /**
+ * Tests that TimingSessions are saved properly when the device alternates between
+ * charging and discharging.
+ */
+ @Test
+ public void testTimerTracking_ChargingAndDischarging() {
+ JobStatus jobStatus = createJobStatus("testTimerTracking_ChargingAndDischarging", 1);
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+ JobStatus jobStatus2 = createJobStatus("testTimerTracking_ChargingAndDischarging", 2);
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null);
+ JobStatus jobStatus3 = createJobStatus("testTimerTracking_ChargingAndDischarging", 3);
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null);
+ assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+ List<TimingSession> expected = new ArrayList<>();
+
+ // A job starting while charging. Only the portion that runs during the discharging period
+ // should be counted.
+ setCharging();
+
+ mQuotaController.prepareForExecutionLocked(jobStatus);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ setDischarging();
+ long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, jobStatus, true);
+ expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+ assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ advanceElapsedClock(SECOND_IN_MILLIS);
+
+ // One job starts while discharging, spans a charging session, and ends after the charging
+ // session. Only the portions during the discharging periods should be counted. This should
+ // result in two TimingSessions. A second job starts while discharging and ends within the
+ // charging session. Only the portion during the first discharging portion should be
+ // counted. A third job starts and ends within the charging session. The third job
+ // shouldn't be included in either job count.
+ setDischarging();
+ start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+ mQuotaController.prepareForExecutionLocked(jobStatus);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.prepareForExecutionLocked(jobStatus2);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ setCharging();
+ expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
+ mQuotaController.prepareForExecutionLocked(jobStatus3);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ setDischarging();
+ start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ advanceElapsedClock(20 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1));
+ assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+ // A job starting while discharging and ending while charging. Only the portion that runs
+ // during the discharging period should be counted.
+ setDischarging();
+ start = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null);
+ mQuotaController.prepareForExecutionLocked(jobStatus2);
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+ setCharging();
+ advanceElapsedClock(10 * SECOND_IN_MILLIS);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
+
+ /**
+ * Tests that a job is properly updated and JobSchedulerService is notified when a job reaches
+ * its quota.
+ */
+ @Test
+ public void testTracking_OutOfQuota() {
+ JobStatus jobStatus = createJobStatus("testTracking_OutOfQuota", 1);
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+ setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window
+ // Now the package only has two seconds to run.
+ final long remainingTimeMs = 2 * SECOND_IN_MILLIS;
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(
+ JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
+ 10 * MINUTE_IN_MILLIS - remainingTimeMs, 1));
+
+ // Start the job.
+ mQuotaController.prepareForExecutionLocked(jobStatus);
+ advanceElapsedClock(remainingTimeMs);
+
+ // Wait for some extra time to allow for job processing.
+ verify(mJobSchedulerService,
+ timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(1))
+ .onControllerStateChanged();
+ assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ }
+
+ /**
+ * Tests that a job is properly handled when it's at the edge of its quota and the old quota is
+ * being phased out.
+ */
+ @Test
+ public void testTracking_RollingQuota() {
+ JobStatus jobStatus = createJobStatus("testTracking_OutOfQuota", 1);
+ mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+ setStandbyBucket(WORKING_INDEX, jobStatus); // 2 hour window
+ Handler handler = mQuotaController.getHandler();
+ spyOn(handler);
+
+ long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final long remainingTimeMs = SECOND_IN_MILLIS;
+ // The package only has one second to run, but this session is at the edge of the rolling
+ // window, so as the package "reaches its quota" it will have more to keep running.
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - 2 * HOUR_IN_MILLIS,
+ 10 * MINUTE_IN_MILLIS - remainingTimeMs, 1));
+
+ assertEquals(remainingTimeMs, mQuotaController.getRemainingExecutionTimeLocked(jobStatus));
+ // Start the job.
+ mQuotaController.prepareForExecutionLocked(jobStatus);
+ advanceElapsedClock(remainingTimeMs);
+
+ // Wait for some extra time to allow for job processing.
+ verify(mJobSchedulerService,
+ timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(0))
+ .onControllerStateChanged();
+ assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+ // The job used up the remaining quota, but in that time, the same amount of time in the
+ // old TimingSession also fell out of the quota window, so it should still have the same
+ // amount of remaining time left its quota.
+ assertEquals(remainingTimeMs,
+ mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+ verify(handler, atLeast(1)).sendMessageDelayed(any(), eq(remainingTimeMs));
+ }
+}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 746c4530a5e1..cf4d3a8070f9 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -66,6 +66,7 @@
<uses-permission android:name="android.permission.SUSPEND_APPS"/>
<uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
<uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
+ <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/BinderCallsStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/BinderCallsStatsServiceTest.java
new file mode 100644
index 000000000000..f70efdfadfd7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/BinderCallsStatsServiceTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Binder;
+import android.os.Process;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.BinderInternal;
+import com.android.internal.os.BinderInternal.CallSession;
+import com.android.server.BinderCallsStatsService.WorkSourceProvider;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+public class BinderCallsStatsServiceTest {
+ @Test
+ public void weTrustOurselves() {
+ WorkSourceProvider workSourceProvider = new WorkSourceProvider() {
+ protected int getCallingUid() {
+ return Process.myUid();
+ }
+
+ protected int getCallingWorkSourceUid() {
+ return 1;
+ }
+ };
+ workSourceProvider.systemReady(InstrumentationRegistry.getContext());
+
+ assertEquals(1, workSourceProvider.resolveWorkSourceUid());
+ }
+
+ @Test
+ public void workSourceSetIfCallerHasPermission() {
+ WorkSourceProvider workSourceProvider = new WorkSourceProvider() {
+ protected int getCallingUid() {
+ // System process uid which as UPDATE_DEVICE_STATS.
+ return 1001;
+ }
+
+ protected int getCallingWorkSourceUid() {
+ return 1;
+ }
+ };
+ workSourceProvider.systemReady(InstrumentationRegistry.getContext());
+
+ assertEquals(1, workSourceProvider.resolveWorkSourceUid());
+ }
+
+ @Test
+ public void workSourceResolvedToCallingUid() {
+ WorkSourceProvider workSourceProvider = new WorkSourceProvider() {
+ protected int getCallingUid() {
+ // UID without permissions.
+ return Integer.MAX_VALUE;
+ }
+
+ protected int getCallingWorkSourceUid() {
+ return 1;
+ }
+ };
+ workSourceProvider.systemReady(InstrumentationRegistry.getContext());
+
+ assertEquals(Integer.MAX_VALUE, workSourceProvider.resolveWorkSourceUid());
+ }
+
+ @Test
+ public void workSourceSet() {
+ TestObserver observer = new TestObserver();
+ observer.callStarted(new Binder(), 0);
+ assertEquals(true, observer.workSourceSet);
+ }
+
+ static class TestObserver extends BinderCallsStatsService.BinderCallsObserver {
+ public boolean workSourceSet = false;
+
+ TestObserver() {
+ super(new NoopObserver(), new WorkSourceProvider());
+ }
+
+ @Override
+ protected void setThreadLocalWorkSourceUid(int uid) {
+ workSourceSet = true;
+ }
+ }
+
+
+ static class NoopObserver implements BinderInternal.Observer {
+ @Override
+ public CallSession callStarted(Binder binder, int code) {
+ return null;
+ }
+
+ @Override
+ public void callEnded(CallSession s, int parcelRequestSize, int parcelReplySize) {
+ }
+
+ @Override
+ public void callThrewException(CallSession s, Exception exception) {
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/CachedDeviceStateServiceTest.java b/services/tests/servicestests/src/com/android/server/CachedDeviceStateServiceTest.java
index 81107cf2ef4f..2a78b6f6ca24 100644
--- a/services/tests/servicestests/src/com/android/server/CachedDeviceStateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/CachedDeviceStateServiceTest.java
@@ -17,9 +17,10 @@
package com.android.server;
-import static org.mockito.Mockito.when;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
import android.content.Context;
import android.content.Intent;
import android.os.BatteryManager;
@@ -134,4 +135,44 @@ public class CachedDeviceStateServiceTest {
mContext.sendBroadcast(intentUnplugged);
assertThat(deviceState.isCharging()).isFalse();
}
+
+ @Test
+ public void correctlyTracksTimeOnBattery() throws Exception {
+ CachedDeviceStateService service = new CachedDeviceStateService(mContext);
+ when(mBatteryManager.getPlugType()).thenReturn(OsProtoEnums.BATTERY_PLUGGED_NONE);
+
+ service.onStart();
+ CachedDeviceState.Readonly deviceState =
+ LocalServices.getService(CachedDeviceState.Readonly.class);
+
+ CachedDeviceState.TimeInStateStopwatch stopwatch =
+ deviceState.createTimeOnBatteryStopwatch();
+
+ // State can be initialized correctly only after PHASE_SYSTEM_SERVICES_READY.
+ assertThat(stopwatch.isRunning()).isFalse();
+ service.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ assertThat(stopwatch.isRunning()).isTrue();
+ stopwatch.reset();
+
+ Thread.sleep(100);
+ assertThat(stopwatch.isRunning()).isTrue();
+ assertThat(stopwatch.getMillis()).isAtLeast(100L);
+
+ long timeOnBatteryBeforePluggedIn = stopwatch.getMillis();
+ Intent intentPluggedIn = new Intent(Intent.ACTION_BATTERY_CHANGED);
+ intentPluggedIn.putExtra(BatteryManager.EXTRA_PLUGGED, OsProtoEnums.BATTERY_PLUGGED_AC);
+ mContext.sendBroadcast(intentPluggedIn);
+
+ assertThat(stopwatch.getMillis()).isAtLeast(timeOnBatteryBeforePluggedIn);
+ assertThat(stopwatch.isRunning()).isFalse();
+
+ long timeOnBatteryAfterPluggedIn = stopwatch.getMillis();
+ Thread.sleep(20);
+ assertThat(stopwatch.getMillis()).isEqualTo(timeOnBatteryAfterPluggedIn);
+
+ stopwatch.reset();
+ assertThat(stopwatch.getMillis()).isEqualTo(0L);
+ assertThat(stopwatch.isRunning()).isFalse();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
index 53711a623704..e0ecd3ee24f0 100644
--- a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
@@ -35,6 +35,7 @@ import android.test.mock.MockContentResolver;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.internal.app.ColorDisplayController;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
@@ -911,7 +912,11 @@ public class ColorDisplayServiceTest {
startService();
assertAccessibilityTransformActivated(true /* activated */ );
assertUserColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
- assertActiveColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
+ if (isColorModeValid(ColorDisplayController.COLOR_MODE_SATURATED)) {
+ assertActiveColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
+ } else if (isColorModeValid(ColorDisplayController.COLOR_MODE_AUTOMATIC)) {
+ assertActiveColorMode(ColorDisplayController.COLOR_MODE_AUTOMATIC);
+ }
}
@Test
@@ -926,7 +931,11 @@ public class ColorDisplayServiceTest {
startService();
assertAccessibilityTransformActivated(true /* activated */ );
assertUserColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
- assertActiveColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
+ if (isColorModeValid(ColorDisplayController.COLOR_MODE_SATURATED)) {
+ assertActiveColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
+ } else if (isColorModeValid(ColorDisplayController.COLOR_MODE_AUTOMATIC)) {
+ assertActiveColorMode(ColorDisplayController.COLOR_MODE_AUTOMATIC);
+ }
}
@Test
@@ -942,7 +951,11 @@ public class ColorDisplayServiceTest {
startService();
assertAccessibilityTransformActivated(true /* activated */ );
assertUserColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
- assertActiveColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
+ if (isColorModeValid(ColorDisplayController.COLOR_MODE_SATURATED)) {
+ assertActiveColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
+ } else if (isColorModeValid(ColorDisplayController.COLOR_MODE_AUTOMATIC)) {
+ assertActiveColorMode(ColorDisplayController.COLOR_MODE_AUTOMATIC);
+ }
}
@Test
@@ -1030,6 +1043,24 @@ public class ColorDisplayServiceTest {
}
/**
+ * Returns whether the color mode is valid on the device the tests are running on.
+ *
+ * @param mode the mode to check
+ */
+ private boolean isColorModeValid(int mode) {
+ final int[] availableColorModes = mContext.getResources().getIntArray(
+ R.array.config_availableColorModes);
+ if (availableColorModes != null) {
+ for (int availableMode : availableColorModes) {
+ if (mode == availableMode) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* Convenience method to start {@link #mColorDisplayService}.
*/
private void startService() {
@@ -1038,7 +1069,6 @@ public class ColorDisplayServiceTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
- mColorDisplayService.onStart();
mColorDisplayService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
mColorDisplayService.onStartUser(mUserId);
}
diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
index 5077f9289477..c1963da3b3af 100644
--- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
@@ -268,7 +268,7 @@ public class ThermalManagerServiceTest {
@Test
public void testGetCurrentStatus() throws RemoteException {
- int status = Temperature.THROTTLING_WARNING;
+ int status = Temperature.THROTTLING_EMERGENCY;
Temperature newSkin = new Temperature(100, Temperature.TYPE_SKIN, "skin1", status);
mFakeHal.mCallback.onValues(newSkin);
assertEquals(status, mService.mService.getCurrentThermalStatus());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 9da204fe3c02..41d5a1c2fac4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -456,6 +456,31 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
}
@Test
+ public void testNoBeepForImportanceDefaultInAutomotive() throws Exception {
+ mService.setIsAutomotive(true);
+
+ NotificationRecord r = getBeepyNotification();
+ r.setSystemImportance(NotificationManager.IMPORTANCE_DEFAULT);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyNeverBeep();
+ assertFalse(r.isInterruptive());
+ }
+
+ @Test
+ public void testBeepForImportanceHighInAutomotive() throws Exception {
+ mService.setIsAutomotive(true);
+
+ NotificationRecord r = getBeepyNotification();
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verifyBeepLooped();
+ assertTrue(r.isInterruptive());
+ }
+
+ @Test
public void testNoInterruptionForMin() throws Exception {
NotificationRecord r = getBeepyNotification();
r.setSystemImportance(NotificationManager.IMPORTANCE_MIN);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
index b30bb4b37c12..068129569d14 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationComparatorTest.java
@@ -15,8 +15,9 @@
*/
package com.android.server.notification;
-import static org.junit.Assert.assertEquals;
+import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
@@ -34,8 +35,8 @@ import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
-import android.telecom.TelecomManager;
import android.support.test.runner.AndroidJUnit4;
+import android.telecom.TelecomManager;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.server.UiServiceTestCase;
@@ -211,7 +212,7 @@ public class NotificationComparatorTest extends UiServiceTestCase {
mRecordColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "colorized", uid2, uid2, n13,
new UserHandle(userId), "", 1999), getDefaultChannel());
- mRecordHighCall.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
+ mRecordColorized.setSystemImportance(NotificationManager.IMPORTANCE_HIGH);
Notification n14 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_CALL)
@@ -225,11 +226,11 @@ public class NotificationComparatorTest extends UiServiceTestCase {
}
@Test
- public void testOrdering() throws Exception {
+ public void testOrdering() {
final List<NotificationRecord> expected = new ArrayList<>();
expected.add(mRecordColorizedCall);
- expected.add(mRecordDefaultMedia);
expected.add(mRecordColorized);
+ expected.add(mRecordDefaultMedia);
expected.add(mRecordHighCall);
expected.add(mRecordInlineReply);
if (mRecordSms != null) {
@@ -250,11 +251,11 @@ public class NotificationComparatorTest extends UiServiceTestCase {
Collections.sort(actual, new NotificationComparator(mContext));
- assertEquals(expected, actual);
+ assertThat(actual, contains(expected.toArray()));
}
@Test
- public void testMessaging() throws Exception {
+ public void testMessaging() {
NotificationComparator comp = new NotificationComparator(mContext);
assertTrue(comp.isImportantMessaging(mRecordInlineReply));
if (mRecordSms != null) {
@@ -265,7 +266,7 @@ public class NotificationComparatorTest extends UiServiceTestCase {
}
@Test
- public void testPeople() throws Exception {
+ public void testPeople() {
NotificationComparator comp = new NotificationComparator(mContext);
assertTrue(comp.isImportantPeople(mRecordStarredContact));
assertTrue(comp.isImportantPeople(mRecordContact));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 1d63c57e6cfe..7be331cc8a06 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -79,6 +79,7 @@ public class DisplayPolicyTestsBase extends WindowTestsBase {
resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
when(mDisplayPolicy.getSystemUiContext()).thenReturn(context);
when(mDisplayPolicy.hasNavigationBar()).thenReturn(true);
+ when(mDisplayPolicy.hasStatusBar()).thenReturn(true);
final int shortSizeDp =
Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 9569c0d5affa..105f8260022f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -22,7 +22,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -750,6 +753,64 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
}
@Test
+ public void testUsesDisplayOrientationForNoSensorOrientation() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ mActivity.info.screenOrientation = SCREEN_ORIENTATION_NOSENSOR;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ final int orientationForDisplay = orientationFromBounds(freeformDisplay.getBounds());
+ final int orientationForTask = orientationFromBounds(mResult.mBounds);
+ assertEquals("Launch bounds orientation should be the same as the display, but"
+ + " display orientation is "
+ + ActivityInfo.screenOrientationToString(orientationForDisplay)
+ + " launch bounds orientation is "
+ + ActivityInfo.screenOrientationToString(orientationForTask),
+ orientationForDisplay, orientationForTask);
+ }
+
+ @Test
+ public void testRespectsAppRequestedOrientation_Landscape() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ mActivity.info.screenOrientation = SCREEN_ORIENTATION_LANDSCAPE;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, orientationFromBounds(mResult.mBounds));
+ }
+
+ @Test
+ public void testRespectsAppRequestedOrientation_Portrait() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, orientationFromBounds(mResult.mBounds));
+ }
+
+ @Test
public void testDefaultSizeSmallerThanBigScreen() {
final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
WINDOWING_MODE_FREEFORM);
@@ -1090,6 +1151,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
display.setWindowingMode(windowingMode);
display.setBounds(/* left */ 0, /* top */ 0, /* right */ 1920, /* bottom */ 1080);
display.getConfiguration().densityDpi = DENSITY_DEFAULT;
+ display.getConfiguration().orientation = ORIENTATION_LANDSCAPE;
return display;
}
@@ -1115,6 +1177,11 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
}
}
+ private int orientationFromBounds(Rect bounds) {
+ return bounds.width() > bounds.height() ? SCREEN_ORIENTATION_LANDSCAPE
+ : SCREEN_ORIENTATION_PORTRAIT;
+ }
+
private static class WindowLayoutBuilder {
private int mWidth = -1;
private int mHeight = -1;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
index 4a99172160f5..50fd188cc00b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -30,6 +30,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
import android.app.ActivityManagerInternal;
import android.content.Context;
@@ -125,11 +126,12 @@ public class WindowManagerServiceRule implements TestRule {
if (input != null && input.length > 1) {
doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
}
+ ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class);
+ when(atms.getGlobalLock()).thenReturn(new WindowManagerGlobalLock());
mService = WindowManagerService.main(context, ims, false, false,
mPolicy = new TestWindowManagerPolicy(
- WindowManagerServiceRule.this::getWindowManagerService),
- new WindowManagerGlobalLock());
+ WindowManagerServiceRule.this::getWindowManagerService), atms);
mService.mTransactionFactory = () -> {
final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
mSurfaceTransactions.add(new WeakReference<>(transaction));
@@ -173,21 +175,21 @@ public class WindowManagerServiceRule implements TestRule {
};
}
- public WindowManagerService getWindowManagerService() {
+ WindowManagerService getWindowManagerService() {
return mService;
}
- public TestWindowManagerPolicy getWindowManagerPolicy() {
- return mPolicy;
- }
-
- public void waitUntilWindowManagerHandlersIdle() {
+ void waitUntilWindowManagerHandlersIdle() {
final WindowManagerService wm = getWindowManagerService();
- if (wm != null) {
- wm.mH.runWithScissors(() -> { }, 0);
- wm.mAnimationHandler.runWithScissors(() -> { }, 0);
- SurfaceAnimationThread.getHandler().runWithScissors(() -> { }, 0);
+ if (wm == null) {
+ return;
}
+ wm.mH.removeCallbacksAndMessages(null);
+ wm.mAnimationHandler.removeCallbacksAndMessages(null);
+ SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null);
+ wm.mH.runWithScissors(() -> { }, 0);
+ wm.mAnimationHandler.runWithScissors(() -> { }, 0);
+ SurfaceAnimationThread.getHandler().runWithScissors(() -> { }, 0);
}
private void destroyAllSurfaceTransactions() {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index cef998651cfe..d617de0af6a1 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -29,7 +29,6 @@ import android.os.ParcelFileDescriptor;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
-import java.lang.String;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
@@ -908,10 +907,16 @@ public final class Call {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("[pa: ");
+ sb.append("[id: ");
+ sb.append(mTelecomCallId);
+ sb.append(", pa: ");
sb.append(mAccountHandle);
sb.append(", hdl: ");
- sb.append(Log.pii(mHandle));
+ sb.append(Log.piiHandle(mHandle));
+ sb.append(", hdlPres: ");
+ sb.append(mHandlePresentation);
+ sb.append(", videoState: ");
+ sb.append(VideoProfile.videoStateToString(mVideoState));
sb.append(", caps: ");
sb.append(capabilitiesToString(mCallCapabilities));
sb.append(", props: ");
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 7db69407ad3d..662874316a7f 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -27,8 +27,8 @@ import android.os.Message;
import android.os.RemoteException;
import com.android.internal.os.SomeArgs;
-import com.android.internal.telecom.ICallScreeningService;
import com.android.internal.telecom.ICallScreeningAdapter;
+import com.android.internal.telecom.ICallScreeningService;
/**
* This service can be implemented by the default dialer (see
@@ -147,7 +147,7 @@ public abstract class CallScreeningService extends Service {
private boolean mShouldSkipCallLog;
private boolean mShouldSkipNotification;
- /*
+ /**
* Sets whether the incoming call should be blocked.
*/
public Builder setDisallowCall(boolean shouldDisallowCall) {
@@ -155,7 +155,7 @@ public abstract class CallScreeningService extends Service {
return this;
}
- /*
+ /**
* Sets whether the incoming call should be disconnected as if the user had manually
* rejected it. This property should only be set to true if the call is disallowed.
*/
@@ -164,16 +164,20 @@ public abstract class CallScreeningService extends Service {
return this;
}
- /*
+ /**
* Sets whether the incoming call should not be displayed in the call log. This property
* should only be set to true if the call is disallowed.
+ * <p>
+ * Note: Calls will still be logged with type
+ * {@link android.provider.CallLog.Calls#BLOCKED_TYPE}, regardless of how this property
+ * is set.
*/
public Builder setSkipCallLog(boolean shouldSkipCallLog) {
mShouldSkipCallLog = shouldSkipCallLog;
return this;
}
- /*
+ /**
* Sets whether a missed call notification should not be shown for the incoming call.
* This property should only be set to true if the call is disallowed.
*/
@@ -211,6 +215,17 @@ public abstract class CallScreeningService extends Service {
* Called when a new incoming call is added.
* {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}
* should be called to allow or disallow the call.
+ * <p>
+ * Note: The {@link Call.Details} instance provided to a call screening service will only have
+ * the following properties set. The rest of the {@link Call.Details} properties will be set to
+ * their default value or {@code null}.
+ * <ul>
+ * <li>{@link Call.Details#getState()}</li>
+ * <li>{@link Call.Details#getConnectTimeMillis()}</li>
+ * <li>{@link Call.Details#getCreationTimeMillis()}</li>
+ * <li>{@link Call.Details#getHandle()}</li>
+ * <li>{@link Call.Details#getHandlePresentation()}</li>
+ * </ul>
*
* @param callDetails Information about a new incoming call, see {@link Call.Details}.
*/
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 13fbeaaa02b7..ca0c854a1a75 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -118,6 +118,13 @@ public class ServiceState implements Parcelable {
*/
public static final int FREQUENCY_RANGE_MMWAVE = 4;
+ private static final List<Integer> FREQUENCY_RANGE_ORDER = Arrays.asList(
+ FREQUENCY_RANGE_UNKNOWN,
+ FREQUENCY_RANGE_LOW,
+ FREQUENCY_RANGE_MID,
+ FREQUENCY_RANGE_HIGH,
+ FREQUENCY_RANGE_MMWAVE);
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "DUPLEX_MODE_",
@@ -1835,4 +1842,13 @@ public class ServiceState implements Parcelable {
mNetworkRegistrationStates.add(regState);
}
}
+
+ /**
+ * @hide
+ */
+ public static final int getBetterNRFrequencyRange(int range1, int range2) {
+ return FREQUENCY_RANGE_ORDER.indexOf(range1) > FREQUENCY_RANGE_ORDER.indexOf(range2)
+ ? range1
+ : range2;
+ }
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2a01ac4b8df2..2c06c4720650 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1590,14 +1590,23 @@ public class SubscriptionManager {
return subId;
}
- /** @hide */
- @UnsupportedAppUsage
- public void setDefaultSmsSubId(int subId) {
- if (VDBG) logd("setDefaultSmsSubId sub id = " + subId);
+ /**
+ * Set the subscription which will be used by default for SMS, with the subscription which
+ * the supplied subscription ID corresponds to; or throw a RuntimeException if the supplied
+ * subscription ID is not usable (check with {@link #isUsableSubscriptionId(int)}).
+ *
+ * @param subscriptionId the supplied subscription ID
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setDefaultSmsSubId(int subscriptionId) {
+ if (VDBG) logd("setDefaultSmsSubId sub id = " + subscriptionId);
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- iSub.setDefaultSmsSubId(subId);
+ iSub.setDefaultSmsSubId(subscriptionId);
}
} catch (RemoteException ex) {
// ignore it
@@ -1645,14 +1654,23 @@ public class SubscriptionManager {
return subId;
}
- /** @hide */
- @UnsupportedAppUsage
- public void setDefaultDataSubId(int subId) {
- if (VDBG) logd("setDataSubscription sub id = " + subId);
+ /**
+ * Set the subscription which will be used by default for data, with the subscription which
+ * the supplied subscription ID corresponds to; or throw a RuntimeException if the supplied
+ * subscription ID is not usable (check with {@link #isUsableSubscriptionId(int)}).
+ *
+ * @param subscriptionId the supplied subscription ID
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setDefaultDataSubId(int subscriptionId) {
+ if (VDBG) logd("setDataSubscription sub id = " + subscriptionId);
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- iSub.setDefaultDataSubId(subId);
+ iSub.setDefaultDataSubId(subscriptionId);
}
} catch (RemoteException ex) {
// ignore it
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 45d914e0dfdd..fa9b76de2e6b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5541,19 +5541,40 @@ public class TelephonyManager {
public void requestNumberVerification(@NonNull PhoneNumberRange range, long timeoutMillis,
@NonNull @CallbackExecutor Executor executor,
@NonNull NumberVerificationCallback callback) {
+ if (executor == null) {
+ throw new NullPointerException("Executor must be non-null");
+ }
+ if (callback == null) {
+ throw new NullPointerException("Callback must be non-null");
+ }
+
INumberVerificationCallback internalCallback = new INumberVerificationCallback.Stub() {
@Override
- public void onCallReceived(String phoneNumber) throws RemoteException {
- Binder.withCleanCallingIdentity(() -> callback.onCallReceived(phoneNumber));
+ public void onCallReceived(String phoneNumber) {
+ Binder.withCleanCallingIdentity(() ->
+ executor.execute(() ->
+ callback.onCallReceived(phoneNumber)));
}
@Override
- public void onVerificationFailed(int reason) throws RemoteException {
- Binder.withCleanCallingIdentity(() -> callback.onVerificationFailed(reason));
+ public void onVerificationFailed(int reason) {
+ Binder.withCleanCallingIdentity(() ->
+ executor.execute(() ->
+ callback.onVerificationFailed(reason)));
}
};
- // TODO -- call the aidl method
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.requestNumberVerification(range, timeoutMillis, internalCallback,
+ getOpPackageName());
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "requestNumberVerification RemoteException", ex);
+ executor.execute(() ->
+ callback.onVerificationFailed(NumberVerificationCallback.REASON_UNSPECIFIED));
+ }
}
/**
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 3b1ef3f45993..994c49cd2315 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -155,7 +155,7 @@ public class EuiccCardManager {
* Requests all the profiles on eUicc.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code and all the profiles.
*/
public void requestAllProfiles(String cardId, @CallbackExecutor Executor executor,
@@ -179,7 +179,7 @@ public class EuiccCardManager {
*
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code and profile.
*/
public void requestProfile(String cardId, String iccid, @CallbackExecutor Executor executor,
@@ -204,7 +204,7 @@ public class EuiccCardManager {
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
* @param refresh Whether sending the REFRESH command to modem.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code.
*/
public void disableProfile(String cardId, String iccid, boolean refresh,
@@ -230,7 +230,7 @@ public class EuiccCardManager {
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile to switch to.
* @param refresh Whether sending the REFRESH command to modem.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code and the EuiccProfileInfo enabled.
*/
public void switchToProfile(String cardId, String iccid, boolean refresh,
@@ -255,7 +255,7 @@ public class EuiccCardManager {
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
* @param nickname The nickname of the profile.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code.
*/
public void setNickname(String cardId, String iccid, String nickname,
@@ -279,7 +279,7 @@ public class EuiccCardManager {
*
* @param cardId The Id of the eUICC.
* @param iccid The iccid of the profile.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code.
*/
public void deleteProfile(String cardId, String iccid, @CallbackExecutor Executor executor,
@@ -304,7 +304,7 @@ public class EuiccCardManager {
* @param cardId The Id of the eUICC.
* @param options Bits of the options of resetting which parts of the eUICC memory. See
* EuiccCard for details.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code.
*/
public void resetMemory(String cardId, @ResetOption int options,
@@ -327,7 +327,7 @@ public class EuiccCardManager {
* Requests the default SM-DP+ address from eUICC.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code and the default SM-DP+ address.
*/
public void requestDefaultSmdpAddress(String cardId, @CallbackExecutor Executor executor,
@@ -350,7 +350,7 @@ public class EuiccCardManager {
* Requests the SM-DS address from eUICC.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code and the SM-DS address.
*/
public void requestSmdsAddress(String cardId, @CallbackExecutor Executor executor,
@@ -374,7 +374,7 @@ public class EuiccCardManager {
*
* @param cardId The Id of the eUICC.
* @param defaultSmdpAddress The default SM-DP+ address to set.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback The callback to get the result code.
*/
public void setDefaultSmdpAddress(String cardId, String defaultSmdpAddress,
@@ -398,7 +398,7 @@ public class EuiccCardManager {
* Requests Rules Authorisation Table.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and the rule authorisation table.
*/
public void requestRulesAuthTable(String cardId, @CallbackExecutor Executor executor,
@@ -421,7 +421,7 @@ public class EuiccCardManager {
* Requests the eUICC challenge for new profile downloading.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and the challenge.
*/
public void requestEuiccChallenge(String cardId, @CallbackExecutor Executor executor,
@@ -444,7 +444,7 @@ public class EuiccCardManager {
* Requests the eUICC info1 defined in GSMA RSP v2.0+ for new profile downloading.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and the info1.
*/
public void requestEuiccInfo1(String cardId, @CallbackExecutor Executor executor,
@@ -467,7 +467,7 @@ public class EuiccCardManager {
* Gets the eUICC info2 defined in GSMA RSP v2.0+ for new profile downloading.
*
* @param cardId The Id of the eUICC.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and the info2.
*/
public void requestEuiccInfo2(String cardId, @CallbackExecutor Executor executor,
@@ -500,7 +500,7 @@ public class EuiccCardManager {
* GSMA RSP v2.0+.
* @param serverCertificate ASN.1 data in byte array indicating SM-DP+ Certificate returned by
* SM-DP+ server.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and a byte array which represents a
* {@code AuthenticateServerResponse} defined in GSMA RSP v2.0+.
*/
@@ -540,7 +540,7 @@ public class EuiccCardManager {
* SM-DP+ server.
* @param smdpCertificate ASN.1 data in byte array indicating the SM-DP+ Certificate returned
* by SM-DP+ server.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and a byte array which represents a
* {@code PrepareDownloadResponse} defined in GSMA RSP v2.0+
*/
@@ -572,7 +572,7 @@ public class EuiccCardManager {
*
* @param cardId The Id of the eUICC.
* @param boundProfilePackage the Bound Profile Package data returned by SM-DP+ server.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and a byte array which represents a
* {@code LoadBoundProfilePackageResponse} defined in GSMA RSP v2.0+.
*/
@@ -601,7 +601,7 @@ public class EuiccCardManager {
* @param cardId The Id of the eUICC.
* @param transactionId the transaction ID returned by SM-DP+ server.
* @param reason the cancel reason.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and an byte[] which represents a
* {@code CancelSessionResponse} defined in GSMA RSP v2.0+.
*/
@@ -630,7 +630,7 @@ public class EuiccCardManager {
*
* @param cardId The Id of the eUICC.
* @param events bits of the event types ({@link EuiccNotification.Event}) to list.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and the list of notifications.
*/
public void listNotifications(String cardId, @EuiccNotification.Event int events,
@@ -654,7 +654,7 @@ public class EuiccCardManager {
*
* @param cardId The Id of the eUICC.
* @param events bits of the event types ({@link EuiccNotification.Event}) to list.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and the list of notifications.
*/
public void retrieveNotificationList(String cardId, @EuiccNotification.Event int events,
@@ -678,7 +678,7 @@ public class EuiccCardManager {
*
* @param cardId The Id of the eUICC.
* @param seqNumber the sequence number of the notification.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code and the notification.
*/
public void retrieveNotification(String cardId, int seqNumber,
@@ -702,7 +702,7 @@ public class EuiccCardManager {
*
* @param cardId The Id of the eUICC.
* @param seqNumber the sequence number of the notification.
- * @param executor The executor through which the callback should be invoke.
+ * @param executor The executor through which the callback should be invoked.
* @param callback the callback to get the result code.
*/
public void removeNotificationFromList(String cardId, int seqNumber,
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 32e939a0c925..399dc5255176 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -35,6 +35,7 @@ import android.telephony.ICellInfoCallback;
import android.telephony.ModemActivityInfo;
import android.telephony.NeighboringCellInfo;
import android.telephony.NetworkScanRequest;
+import android.telephony.PhoneNumberRange;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -49,6 +50,7 @@ import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.aidl.IImsRegistrationCallback;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.telephony.CellNetworkScanResult;
+import com.android.internal.telephony.INumberVerificationCallback;
import com.android.internal.telephony.OperatorInfo;
import java.util.List;
@@ -871,6 +873,17 @@ interface ITelephony {
String getCdmaMin(int subId);
/**
+ * Request that the next incoming call from a number matching {@code range} be intercepted.
+ * @param range The range of phone numbers the caller expects a phone call from.
+ * @param timeoutMillis The amount of time to wait for such a call, or
+ * {@link #MAX_NUMBER_VERIFICATION_TIMEOUT_MILLIS}, whichever is lesser.
+ * @param callback the callback aidl
+ * @param callingPackage the calling package name.
+ */
+ void requestNumberVerification(in PhoneNumberRange range, long timeoutMillis,
+ in INumberVerificationCallback callback, String callingPackage);
+
+ /**
* Has the calling application been granted special privileges by the carrier.
*
* If any of the packages in the calling UID has carrier privileges, the
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 4dc0341c8e2b..d8f961850906 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -542,7 +542,7 @@ public class IpSecServiceParameterizedTest {
verify(mMockNetd)
.ipSecApplyTransportModeTransform(
- eq(pfd.getFileDescriptor()),
+ eq(pfd),
eq(mUid),
eq(IpSecManager.DIRECTION_OUT),
anyString(),
@@ -555,7 +555,7 @@ public class IpSecServiceParameterizedTest {
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
mIpSecService.removeTransportModeTransforms(pfd);
- verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
+ verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
}
private IpSecTunnelInterfaceResponse createAndValidateTunnel(
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 2c94a601fbf6..724446e11c83 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -425,7 +425,7 @@ public class IpSecServiceTest {
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
mIpSecService.removeTransportModeTransforms(pfd);
- verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
+ verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
}
@Test
@@ -620,10 +620,10 @@ public class IpSecServiceTest {
mIpSecService.openUdpEncapsulationSocket(0, new Binder());
FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
- ArgumentMatcher<FileDescriptor> fdMatcher = (arg) -> {
+ ArgumentMatcher<ParcelFileDescriptor> fdMatcher = (arg) -> {
try {
StructStat sockStat = Os.fstat(sockFd);
- StructStat argStat = Os.fstat(arg);
+ StructStat argStat = Os.fstat(arg.getFileDescriptor());
return sockStat.st_ino == argStat.st_ino
&& sockStat.st_dev == argStat.st_dev;
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index ed70fb3c57d6..df0daebe8453 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -240,6 +240,12 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
}
break;
+ case android::RES_TABLE_OVERLAYABLE_TYPE:
+ if (!ParseOverlayable(parser.chunk())) {
+ return false;
+ }
+ break;
+
default:
diag_->Warn(DiagMessage(source_)
<< "unexpected chunk type "
@@ -383,24 +389,12 @@ bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
return false;
}
- const uint32_t type_spec_flags = entry_type_spec_flags_[res_id];
- if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0 ||
- (type_spec_flags & ResTable_typeSpec::SPEC_OVERLAYABLE) != 0) {
- if (entry->flags & ResTable_entry::FLAG_PUBLIC) {
- Visibility visibility;
- visibility.level = Visibility::Level::kPublic;
- visibility.source = source_.WithLine(0);
- if (!table_->SetVisibilityWithIdMangled(name, visibility, res_id, diag_)) {
- return false;
- }
- }
-
- if (type_spec_flags & ResTable_typeSpec::SPEC_OVERLAYABLE) {
- Overlayable overlayable;
- overlayable.source = source_.WithLine(0);
- if (!table_->AddOverlayableMangled(name, overlayable, diag_)) {
- return false;
- }
+ if (entry->flags & ResTable_entry::FLAG_PUBLIC) {
+ Visibility visibility;
+ visibility.level = Visibility::Level::kPublic;
+ visibility.source = source_.WithLine(0);
+ if (!table_->SetVisibilityWithIdMangled(name, visibility, res_id, diag_)) {
+ return false;
}
// Erase the ID from the map once processed, so that we don't mark the same symbol more than
@@ -433,6 +427,72 @@ bool BinaryResourceParser::ParseLibrary(const ResChunk_header* chunk) {
return true;
}
+bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
+ const ResTable_overlayable_header* header = ConvertTo<ResTable_overlayable_header>(chunk);
+ if (!header) {
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_category_header chunk");
+ return false;
+ }
+
+ ResChunkPullParser parser(GetChunkData(chunk),
+ GetChunkDataLen(chunk));
+ while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
+ if (util::DeviceToHost16(parser.chunk()->type) == android::RES_TABLE_OVERLAYABLE_POLICY_TYPE) {
+ const ResTable_overlayable_policy_header* policy_header =
+ ConvertTo<ResTable_overlayable_policy_header>(parser.chunk());
+
+ std::vector<Overlayable::Policy> policies;
+ if (policy_header->policy_flags & ResTable_overlayable_policy_header::POLICY_PUBLIC) {
+ policies.push_back(Overlayable::Policy::kPublic);
+ }
+ if (policy_header->policy_flags
+ & ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION) {
+ policies.push_back(Overlayable::Policy::kSystem);
+ }
+ if (policy_header->policy_flags
+ & ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION) {
+ policies.push_back(Overlayable::Policy::kVendor);
+ }
+ if (policy_header->policy_flags
+ & ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) {
+ policies.push_back(Overlayable::Policy::kProduct);
+ }
+ if (policy_header->policy_flags
+ & ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION) {
+ policies.push_back(Overlayable::Policy::kProductServices);
+ }
+
+ const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
+ ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
+ const ResTable_ref* const ref_end = ref_begin
+ + util::DeviceToHost32(policy_header->entry_count);
+ for (auto ref_iter = ref_begin; ref_iter != ref_end; ++ref_iter) {
+ ResourceId res_id(util::DeviceToHost32(ref_iter->ident));
+ const auto iter = id_index_.find(res_id);
+
+ // If the overlayable chunk comes before the type chunks, the resource ids and resource name
+ // pairing will not exist at this point.
+ if (iter == id_index_.cend()) {
+ diag_->Error(DiagMessage(source_) << "failed to find resource name for overlayable"
+ << " resource " << res_id);
+ return false;
+ }
+
+ for (Overlayable::Policy policy : policies) {
+ Overlayable overlayable;
+ overlayable.source = source_.WithLine(0);
+ overlayable.policy = policy;
+ if (!table_->AddOverlayable(iter->second, overlayable, diag_)) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
std::unique_ptr<Item> BinaryResourceParser::ParseValue(const ResourceNameRef& name,
const ConfigDescription& config,
const android::Res_value& value) {
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.h b/tools/aapt2/format/binary/BinaryResourceParser.h
index 2bdc051f4e29..a2eee5006964 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.h
+++ b/tools/aapt2/format/binary/BinaryResourceParser.h
@@ -54,6 +54,7 @@ class BinaryResourceParser {
bool ParseTypeSpec(const ResourceTablePackage* package, const android::ResChunk_header* chunk);
bool ParseType(const ResourceTablePackage* package, const android::ResChunk_header* chunk);
bool ParseLibrary(const android::ResChunk_header* chunk);
+ bool ParseOverlayable(const android::ResChunk_header* chunk);
std::unique_ptr<Item> ParseValue(const ResourceNameRef& name,
const android::ConfigDescription& config,
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 6c1a9ba2cbad..976c3288bfca 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -24,6 +24,7 @@
#include "android-base/logging.h"
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
+#include "androidfw/ResourceUtils.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
@@ -216,6 +217,11 @@ class MapFlattenVisitor : public ValueVisitor {
size_t entry_count_ = 0;
};
+struct PolicyChunk {
+ uint32_t policy_flags;
+ std::set<ResourceId> ids;
+};
+
class PackageFlattener {
public:
PackageFlattener(IAaptContext* context, ResourceTablePackage* package,
@@ -267,6 +273,8 @@ class PackageFlattener {
FlattenLibrarySpec(buffer);
}
+ FlattenOverlayable(buffer);
+
pkg_writer.Finish();
return true;
}
@@ -413,6 +421,97 @@ class PackageFlattener {
return sorted_entries;
}
+ void FlattenOverlayable(BigBuffer* buffer) {
+ std::vector<PolicyChunk> policies;
+
+ CHECK(bool(package_->id)) << "package must have an ID set when flattening <overlayable>";
+ for (auto& type : package_->types) {
+ CHECK(bool(type->id)) << "type must have an ID set when flattening <overlayable>";
+ for (auto& entry : type->entries) {
+ CHECK(bool(type->id)) << "entry must have an ID set when flattening <overlayable>";
+
+ // TODO(b/120298168): Convert the policies vector to a policy set or bitmask
+ if (!entry->overlayable_declarations.empty()) {
+ uint16_t policy_flags = 0;
+ for (Overlayable overlayable : entry->overlayable_declarations) {
+ if (overlayable.policy) {
+ switch (overlayable.policy.value()) {
+ case Overlayable::Policy::kPublic:
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
+ break;
+ case Overlayable::Policy::kSystem:
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
+ break;
+ case Overlayable::Policy::kVendor:
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
+ break;
+ case Overlayable::Policy::kProduct:
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
+ break;
+ case Overlayable::Policy::kProductServices:
+ policy_flags |=
+ ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
+ break;
+ }
+ } else {
+ // Encode overlayable entries defined without a policy as publicly overlayable
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
+ }
+ }
+
+ // Find the overlayable policy chunk with the same policies as the entry
+ PolicyChunk* policy_chunk = nullptr;
+ for (PolicyChunk& policy : policies) {
+ if (policy.policy_flags == policy_flags) {
+ policy_chunk = &policy;
+ break;
+ }
+ }
+
+ // Create a new policy chunk if an existing one with the same policy cannot be found
+ if (policy_chunk == nullptr) {
+ PolicyChunk p;
+ p.policy_flags = policy_flags;
+ policies.push_back(p);
+ policy_chunk = &policies.back();
+ }
+
+ policy_chunk->ids.insert(android::make_resid(package_->id.value(), type->id.value(),
+ entry->id.value()));
+ }
+ }
+ }
+
+ if (policies.empty()) {
+ // Only write the overlayable chunk if the APK has overlayable entries
+ return;
+ }
+
+ ChunkWriter writer(buffer);
+ writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
+
+ // Write each policy block for the overlayable
+ for (PolicyChunk& policy : policies) {
+ ChunkWriter policy_writer(buffer);
+ ResTable_overlayable_policy_header* policy_type =
+ policy_writer.StartChunk<ResTable_overlayable_policy_header>(
+ RES_TABLE_OVERLAYABLE_POLICY_TYPE);
+ policy_type->policy_flags = util::HostToDevice32(policy.policy_flags);
+ policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(policy.ids.size()));
+
+ // Write the ids after the policy header
+ ResTable_ref* id_block = policy_writer.NextBlock<ResTable_ref>(policy.ids.size());
+ for (const ResourceId& id : policy.ids) {
+ id_block->ident = util::HostToDevice32(id.id);
+ id_block++;
+ }
+
+ policy_writer.Finish();
+ }
+
+ writer.Finish();
+ }
+
bool FlattenTypeSpec(ResourceTableType* type, std::vector<ResourceEntry*>* sorted_entries,
BigBuffer* buffer) {
ChunkWriter type_spec_writer(buffer);
@@ -446,11 +545,6 @@ class PackageFlattener {
config_masks[entry->id.value()] |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
}
- if (!entry->overlayable_declarations.empty()) {
- config_masks[entry->id.value()] |=
- util::HostToDevice32(ResTable_typeSpec::SPEC_OVERLAYABLE);
- }
-
const size_t config_count = entry->values.size();
for (size_t i = 0; i < config_count; i++) {
const ConfigDescription& config = entry->values[i]->config;
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index cd1414c7e628..410efbe83b1b 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -628,24 +628,108 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithWhitelistSucceeds) {
}
TEST_F(TableFlattenerTest, FlattenOverlayable) {
+ std::string name = "com.app.test:integer/overlayable";
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.SetPackageId("com.app.test", 0x7f)
- .AddSimple("com.app.test:integer/overlayable", ResourceId(0x7f020000))
+ .AddSimple(name, ResourceId(0x7f020000))
+ .AddOverlayable(name, Overlayable::Policy::kProduct)
+ .AddOverlayable(name, Overlayable::Policy::kSystem)
+ .AddOverlayable(name, Overlayable::Policy::kVendor)
.Build();
- ASSERT_TRUE(table->AddOverlayable(test::ParseNameOrDie("com.app.test:integer/overlayable"),
- Overlayable{}, test::GetDiagnostics()));
+ ResourceTable output_table;
+ ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &output_table));
- ResTable res_table;
- ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &res_table));
+ auto search_result = output_table.FindResource(test::ParseNameOrDie(name));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations.size(), 3);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[0].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[0].policy,
+ Overlayable::Policy::kSystem);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[1].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[1].policy,
+ Overlayable::Policy::kVendor);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[2].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[2].policy,
+ Overlayable::Policy::kProduct);
+}
+
+TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
+ std::string name_zero = "com.app.test:integer/overlayable_zero";
+ std::string name_one = "com.app.test:integer/overlayable_one";
+ std::string name_two = "com.app.test:integer/overlayable_two";
+ std::string name_three = "com.app.test:integer/overlayable_three";
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.test", 0x7f)
+ .AddSimple(name_zero, ResourceId(0x7f020000))
+ .AddOverlayable(name_zero, Overlayable::Policy::kProduct)
+ .AddOverlayable(name_zero, Overlayable::Policy::kSystem)
+ .AddOverlayable(name_zero, Overlayable::Policy::kProductServices)
+ .AddSimple(name_one, ResourceId(0x7f020001))
+ .AddOverlayable(name_one, Overlayable::Policy::kPublic)
+ .AddOverlayable(name_one, Overlayable::Policy::kSystem)
+ .AddSimple(name_two, ResourceId(0x7f020002))
+ .AddOverlayable(name_two, Overlayable::Policy::kProduct)
+ .AddOverlayable(name_two, Overlayable::Policy::kSystem)
+ .AddOverlayable(name_two, Overlayable::Policy::kProductServices)
+ .AddSimple(name_three, ResourceId(0x7f020003))
+ .AddOverlayable(name_three, {})
+ .Build();
+
+ ResourceTable output_table;
+ ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &output_table));
+
+ auto search_result = output_table.FindResource(test::ParseNameOrDie(name_zero));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations.size(), 3);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[0].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[0].policy,
+ Overlayable::Policy::kSystem);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[1].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[1].policy,
+ Overlayable::Policy::kProduct);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[2].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[2].policy,
+ Overlayable::Policy::kProductServices);
+
+ search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations.size(), 2);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[0].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[0].policy,
+ Overlayable::Policy::kPublic);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[1].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[1].policy,
+ Overlayable::Policy::kSystem);
+
+ search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations.size(), 3);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[0].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[0].policy,
+ Overlayable::Policy::kSystem);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[1].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[1].policy,
+ Overlayable::Policy::kProduct);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[2].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[2].policy,
+ Overlayable::Policy::kProductServices);
+
+ search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations.size(), 1);
+ EXPECT_TRUE(search_result.value().entry->overlayable_declarations[0].policy);
+ EXPECT_EQ(search_result.value().entry->overlayable_declarations[0].policy,
+ Overlayable::Policy::kPublic);
- const StringPiece16 overlayable_name(u"com.app.test:integer/overlayable");
- uint32_t spec_flags = 0u;
- ASSERT_THAT(res_table.identifierForName(overlayable_name.data(), overlayable_name.size(), nullptr,
- 0u, nullptr, 0u, &spec_flags),
- Gt(0u));
- EXPECT_TRUE(spec_flags & android::ResTable_typeSpec::SPEC_OVERLAYABLE);
}
+
} // namespace aapt
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 3a5d5858254d..1b6626a8dfe9 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -368,7 +368,16 @@ bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) {
// Symbol state information may be lost if there is no value for the resource.
if (entry->visibility.level != Visibility::Level::kUndefined && entry->values.empty()) {
context->GetDiagnostics()->Error(DiagMessage(entry->visibility.source)
- << "no definition for declared symbol '" << name << "'");
+ << "no definition for declared symbol '" << name
+ << "'");
+ error = true;
+ }
+
+ // Ensure that definitions for values declared as overlayable exist
+ if (!entry->overlayable_declarations.empty() && entry->values.empty()) {
+ context->GetDiagnostics()->Error(DiagMessage(entry->overlayable_declarations[0].source)
+ << "no definition for overlayable symbol '"
+ << name << "'");
error = true;
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 8e0d4acf089d..cad6d2997bfb 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -156,33 +156,39 @@ public class WifiManager {
public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1;
/**
+ * Reason code if the user has disallowed "android:change_wifi_state" app-ops from the app.
+ * @see android.app.AppOpsManager#unsafeCheckOp(String, int, String).
+ */
+ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED = 2;
+
+ /**
* Reason code if one or more of the network suggestions added already exists in platform's
* database.
* @see WifiNetworkSuggestion#equals(Object)
*/
- public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 2;
+ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3;
/**
* Reason code if the number of network suggestions provided by the app crosses the max
* threshold set per app.
* @see #getMaxNumberOfNetworkSuggestionsPerApp()
*/
- public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 3;
+ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4;
/**
* Reason code if one or more of the network suggestions removed does not exist in platform's
* database.
*/
- public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 4;
+ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
@IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
STATUS_NETWORK_SUGGESTIONS_SUCCESS,
STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
+ STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED,
STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE,
STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP,
STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID,
})
-
@Retention(RetentionPolicy.SOURCE)
public @interface NetworkSuggestionsStatusCode {}
@@ -1982,6 +1988,8 @@ public class WifiManager {
public static final int WIFI_FEATURE_WPA3_SUITE_B = 0x10000000; // WPA3-Enterprise Suite-B
/** @hide */
public static final int WIFI_FEATURE_OWE = 0x20000000; // Enhanced Open
+ /** @hide */
+ public static final int WIFI_FEATURE_LOW_LATENCY = 0x40000000; // Low Latency modes
private int getSupportedFeatures() {
try {
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index fc5caf0a47d7..acc0518dbca4 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -357,11 +357,12 @@ public class WifiScanner {
*/
private int mBucketsScanned;
/**
- * Indicates that the scan results received are as a result of a scan of all available
- * channels. This should only be expected to function for single scans.
+ * Bands scanned. One of the WIFI_BAND values.
+ * Will be {@link #WIFI_BAND_UNSPECIFIED} if the list of channels do not fully cover
+ * any of the bands.
* {@hide}
*/
- private boolean mAllChannelsScanned;
+ private int mBandScanned;
/** all scan results discovered in this scan, sorted by timestamp in ascending order */
private ScanResult mResults[];
@@ -374,12 +375,12 @@ public class WifiScanner {
}
/** {@hide} */
- public ScanData(int id, int flags, int bucketsScanned, boolean allChannelsScanned,
- ScanResult[] results) {
+ public ScanData(int id, int flags, int bucketsScanned, int bandScanned,
+ ScanResult[] results) {
mId = id;
mFlags = flags;
mBucketsScanned = bucketsScanned;
- mAllChannelsScanned = allChannelsScanned;
+ mBandScanned = bandScanned;
mResults = results;
}
@@ -387,7 +388,7 @@ public class WifiScanner {
mId = s.mId;
mFlags = s.mFlags;
mBucketsScanned = s.mBucketsScanned;
- mAllChannelsScanned = s.mAllChannelsScanned;
+ mBandScanned = s.mBandScanned;
mResults = new ScanResult[s.mResults.length];
for (int i = 0; i < s.mResults.length; i++) {
ScanResult result = s.mResults[i];
@@ -410,8 +411,8 @@ public class WifiScanner {
}
/** {@hide} */
- public boolean isAllChannelsScanned() {
- return mAllChannelsScanned;
+ public int getBandScanned() {
+ return mBandScanned;
}
public ScanResult[] getResults() {
@@ -429,7 +430,7 @@ public class WifiScanner {
dest.writeInt(mId);
dest.writeInt(mFlags);
dest.writeInt(mBucketsScanned);
- dest.writeInt(mAllChannelsScanned ? 1 : 0);
+ dest.writeInt(mBandScanned);
dest.writeInt(mResults.length);
for (int i = 0; i < mResults.length; i++) {
ScanResult result = mResults[i];
@@ -447,13 +448,13 @@ public class WifiScanner {
int id = in.readInt();
int flags = in.readInt();
int bucketsScanned = in.readInt();
- boolean allChannelsScanned = in.readInt() != 0;
+ int bandScanned = in.readInt();
int n = in.readInt();
ScanResult results[] = new ScanResult[n];
for (int i = 0; i < n; i++) {
results[i] = ScanResult.CREATOR.createFromParcel(in);
}
- return new ScanData(id, flags, bucketsScanned, allChannelsScanned, results);
+ return new ScanData(id, flags, bucketsScanned, bandScanned, results);
}
public ScanData[] newArray(int size) {
@@ -759,6 +760,7 @@ public class WifiScanner {
* Multiple requests should also not share this object.
* {@hide}
*/
+ @RequiresPermission(Manifest.permission.NETWORK_STACK)
public void registerScanListener(ScanListener listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
int key = addListener(listener);
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index b0ed11034810..e0442f2fd5ae 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -1695,7 +1694,6 @@ public class WifiP2pManager {
* @param listener for callback on success or failure. Can be null.
* @hide
*/
- @SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void factoryReset(@NonNull Channel c, @Nullable ActionListener listener) {
checkChannel(c);
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index da42dcf623c2..cf1ed8fa84c0 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -16,6 +16,7 @@
package android.net.wifi;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -26,6 +27,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.wifi.WifiScanner.PnoSettings;
import android.net.wifi.WifiScanner.PnoSettings.PnoNetwork;
+import android.net.wifi.WifiScanner.ScanData;
import android.net.wifi.WifiScanner.ScanSettings;
import android.os.Handler;
import android.os.Parcel;
@@ -203,4 +205,29 @@ public class WifiScannerTest {
assertNotNull(pnoNetwork.frequencies);
}
+ /**
+ * Verify parcel read/write for ScanData.
+ */
+ @Test
+ public void verifyScanDataParcel() throws Exception {
+ ScanData writeScanData = new ScanData(2, 0, 3,
+ WifiScanner.WIFI_BAND_BOTH_WITH_DFS, new ScanResult[0]);
+
+ ScanData readScanData = parcelWriteRead(writeScanData);
+ assertEquals(writeScanData.getId(), readScanData.getId());
+ assertEquals(writeScanData.getFlags(), readScanData.getFlags());
+ assertEquals(writeScanData.getBucketsScanned(), readScanData.getBucketsScanned());
+ assertEquals(writeScanData.getBandScanned(), readScanData.getBandScanned());
+ assertArrayEquals(writeScanData.getResults(), readScanData.getResults());
+ }
+
+ /**
+ * Write the provided {@link ScanData} to a parcel and deserialize it.
+ */
+ private static ScanData parcelWriteRead(ScanData writeScanData) throws Exception {
+ Parcel parcel = Parcel.obtain();
+ writeScanData.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ return ScanData.CREATOR.createFromParcel(parcel);
+ }
}