summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt219
-rw-r--r--core/api/module-lib-current.txt20
-rw-r--r--core/api/removed.txt16
-rw-r--r--core/api/system-current.txt75
-rw-r--r--core/api/system-removed.txt11
-rw-r--r--core/api/test-current.txt23
-rw-r--r--core/java/android/app/ActivityManager.java117
-rw-r--r--core/java/android/app/ActivityThread.java7
-rw-r--r--core/java/android/app/AppOpsManager.java24
-rw-r--r--core/java/android/app/ApplicationExitInfo.java17
-rw-r--r--core/java/android/app/ApplicationStartInfo.aidl19
-rw-r--r--core/java/android/app/ApplicationStartInfo.java598
-rw-r--r--core/java/android/app/IActivityManager.aidl41
-rw-r--r--core/java/android/app/IApplicationStartInfoCompleteListener.aidl30
-rw-r--r--core/java/android/app/INotificationManager.aidl2
-rw-r--r--core/java/android/app/Notification.java9
-rw-r--r--core/java/android/app/NotificationManager.java26
-rw-r--r--core/java/android/app/OWNERS2
-rw-r--r--core/java/android/app/SystemServiceRegistry.java2
-rw-r--r--core/java/android/app/TEST_MAPPING17
-rw-r--r--core/java/android/app/UiAutomation.java44
-rw-r--r--core/java/android/app/admin/AccountTypePolicyKey.java154
-rw-r--r--core/java/android/app/admin/DeviceAdminAuthority.java17
-rw-r--r--core/java/android/app/admin/DevicePolicyIdentifiers.java174
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java105
-rw-r--r--core/java/android/app/admin/DevicePolicyState.java5
-rw-r--r--core/java/android/app/admin/DpcAuthority.java17
-rw-r--r--core/java/android/app/admin/EnforcingAdmin.java2
-rw-r--r--core/java/android/app/admin/FlagUnion.java10
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--core/java/android/app/admin/IntentFilterPolicyKey.java4
-rw-r--r--core/java/android/app/admin/LockTaskPolicy.java18
-rw-r--r--core/java/android/app/admin/LongPolicyValue.java79
-rw-r--r--core/java/android/app/admin/MostRecent.java28
-rw-r--r--core/java/android/app/admin/MostRestrictive.java13
-rw-r--r--core/java/android/app/admin/PolicyKey.java3
-rw-r--r--core/java/android/app/admin/PolicyState.java4
-rw-r--r--core/java/android/app/admin/PolicyUpdateResult.java23
-rw-r--r--core/java/android/app/admin/PolicyUpdatesReceiver.java16
-rw-r--r--core/java/android/app/admin/RoleAuthority.java15
-rw-r--r--core/java/android/app/admin/StringSetUnion.java18
-rw-r--r--core/java/android/app/admin/TopPriority.java48
-rw-r--r--core/java/android/app/admin/UnknownAuthority.java18
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java4
-rw-r--r--core/java/android/companion/virtual/IVirtualDevice.aidl12
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceManager.java51
-rw-r--r--core/java/android/companion/virtual/VirtualDeviceParams.java90
-rw-r--r--core/java/android/companion/virtual/sensor/IVirtualSensorCallback.aidl (renamed from core/java/android/companion/virtual/sensor/IVirtualSensorStateChangeCallback.aidl)12
-rw-r--r--core/java/android/companion/virtual/sensor/VirtualSensor.aidl (renamed from telephony/java/com/android/internal/telephony/IIntArrayConsumer.aidl)8
-rw-r--r--core/java/android/companion/virtual/sensor/VirtualSensor.java83
-rw-r--r--core/java/android/companion/virtual/sensor/VirtualSensorCallback.java53
-rw-r--r--core/java/android/companion/virtual/sensor/VirtualSensorConfig.java70
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java5
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageInstaller.java58
-rw-r--r--core/java/android/content/pm/ServiceInfo.java13
-rw-r--r--core/java/android/hardware/display/DisplayManager.java23
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java13
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java3
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl1
-rw-r--r--core/java/android/hardware/usb/DisplayPortAltModeInfo.java12
-rw-r--r--core/java/android/hardware/usb/UsbManager.java14
-rw-r--r--core/java/android/hardware/usb/UsbPort.java6
-rw-r--r--core/java/android/hardware/usb/UsbPortStatus.java9
-rw-r--r--core/java/android/nfc/BeamShareData.java67
-rw-r--r--core/java/android/nfc/IAppCallback.aidl3
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl7
-rw-r--r--core/java/android/nfc/NfcActivityManager.java195
-rw-r--r--core/java/android/nfc/NfcAdapter.java265
-rwxr-xr-xcore/java/android/os/Build.java9
-rw-r--r--core/java/android/os/PowerManager.java12
-rw-r--r--core/java/android/os/UserManager.java48
-rw-r--r--core/java/android/provider/DeviceConfigInitializer.java67
-rw-r--r--core/java/android/provider/DeviceConfigServiceManager.java141
-rw-r--r--core/java/android/provider/Settings.java1
-rw-r--r--core/java/android/service/autofill/InlineSuggestionRenderService.java2
-rw-r--r--core/java/android/service/games/GameSessionService.java2
-rw-r--r--core/java/android/service/notification/Adjustment.java15
-rw-r--r--core/java/android/service/notification/INotificationListener.aidl1
-rw-r--r--core/java/android/service/notification/NotificationAssistantService.java3
-rw-r--r--core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java2
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java6
-rw-r--r--core/java/android/speech/RecognitionPart.aidl (renamed from core/java/android/nfc/BeamShareData.aidl)6
-rw-r--r--core/java/android/speech/RecognitionPart.java488
-rw-r--r--core/java/android/speech/RecognitionService.java10
-rw-r--r--core/java/android/speech/RecognizerIntent.java14
-rw-r--r--core/java/android/speech/SpeechRecognizer.java11
-rw-r--r--core/java/android/util/FeatureFlagUtils.java8
-rw-r--r--core/java/android/util/NtpTrustedTime.java3
-rw-r--r--core/java/android/util/PackageUtils.java41
-rw-r--r--core/java/android/view/Choreographer.java8
-rw-r--r--core/java/android/view/DragEvent.java3
-rw-r--r--core/java/android/view/RemoteAnimationTarget.java6
-rw-r--r--core/java/android/view/SurfaceControl.java78
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java34
-rw-r--r--core/java/android/view/View.java38
-rw-r--r--core/java/android/view/ViewRootImpl.java4
-rw-r--r--core/java/android/view/WindowManager.java47
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java65
-rw-r--r--core/java/android/widget/Editor.java59
-rw-r--r--core/java/android/window/SplashScreenView.java3
-rw-r--r--core/java/android/window/TransitionInfo.java1
-rw-r--r--core/java/com/android/internal/app/LocaleStore.java3
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java15
-rw-r--r--core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java17
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/android_view_SurfaceControl.cpp2
-rw-r--r--core/proto/android/app/OWNERS1
-rw-r--r--core/proto/android/nfc/nfc_service.proto34
-rw-r--r--core/proto/android/server/OWNERS1
-rw-r--r--core/res/AndroidManifest.xml21
-rw-r--r--core/res/res/values/attrs_manifest.xml25
-rw-r--r--core/res/res/values/config.xml6
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java46
-rw-r--r--core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java3
-rw-r--r--core/tests/coretests/src/android/view/KeyEventTest.java208
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java2
-rw-r--r--core/tests/hdmitests/Android.bp2
-rw-r--r--core/tests/hdmitests/AndroidTest.xml4
-rw-r--r--core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java3
-rw-r--r--core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java2
-rwxr-xr-xcore/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java3
-rwxr-xr-xcore/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java3
-rw-r--r--core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java3
-rw-r--r--libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java7
-rw-r--r--libs/hwui/jni/Bitmap.cpp37
-rw-r--r--libs/hwui/jni/YuvToJpegEncoder.cpp6
-rw-r--r--libs/hwui/jni/YuvToJpegEncoder.h8
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.cpp11
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.h9
-rw-r--r--libs/hwui/tests/unit/ShaderCacheTests.cpp192
-rw-r--r--media/java/android/media/AudioManager.java43
-rw-r--r--media/java/android/media/AudioSystem.java7
-rw-r--r--media/java/android/media/projection/MediaProjectionManager.java85
-rw-r--r--media/java/android/media/tv/TvInputManager.java10
-rw-r--r--media/java/android/media/tv/TvInputService.java10
-rw-r--r--media/java/android/media/tv/TvRecordingClient.java20
-rw-r--r--media/java/android/media/tv/TvView.java12
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl10
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl3
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl2
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl10
-rw-r--r--media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java10
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppManager.java60
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppService.java124
-rw-r--r--media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java30
-rwxr-xr-xmedia/java/android/media/tv/interactive/TvInteractiveAppView.java145
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java2
-rw-r--r--packages/CompanionDeviceManager/res/drawable-night/ic_glasses.xml27
-rw-r--r--packages/CompanionDeviceManager/res/drawable-night/ic_permission_nearby_device_streaming.xml27
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_glasses.xml27
-rw-r--r--packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml5
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt4
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/common/StartBalIntentSenderForResultContract.kt53
-rw-r--r--packages/LocalTransport/src/com/android/localtransport/LocalTransport.java42
-rw-r--r--packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java7
-rw-r--r--packages/SettingsLib/Spa/build.gradle2
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt2
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt2
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt2
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.pngbin81694 -> 81553 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.pngbin95616 -> 95486 bytes
-rw-r--r--packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.pngbin63231 -> 62979 bytes
-rw-r--r--packages/SettingsLib/Spa/spa/build.gradle13
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt8
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt4
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt4
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt8
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt28
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt4
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt329
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt316
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt26
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt12
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt8
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt2
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt10
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt8
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt4
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt20
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt59
-rw-r--r--packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt2
-rw-r--r--packages/SettingsLib/res/values/arrays.xml30
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java35
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java9
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt40
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableImageView.kt (renamed from packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt)3
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableLinearLayout.kt (renamed from packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt)2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableTextView.kt49
-rw-r--r--packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml4
-rw-r--r--packages/SystemUI/res/drawable/ic_progress_activity.xml26
-rw-r--r--packages/SystemUI/res/drawable/ic_shortcutlist_search.xml25
-rw-r--r--packages/SystemUI/res/drawable/ic_shortcutlist_search_button_cancel.xml25
-rw-r--r--packages/SystemUI/res/drawable/shortcut_button_colored.xml29
-rw-r--r--packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml29
-rw-r--r--packages/SystemUI/res/drawable/shortcut_dialog_bg.xml24
-rw-r--r--packages/SystemUI/res/drawable/shortcut_search_background.xml26
-rw-r--r--packages/SystemUI/res/layout/chipbar.xml7
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml2
-rw-r--r--packages/SystemUI/res/layout/font_scaling_dialog.xml27
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml20
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml24
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml25
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml28
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml28
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml139
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml4
-rw-r--r--packages/SystemUI/res/layout/media_session_view.xml4
-rw-r--r--packages/SystemUI/res/layout/ongoing_call_chip.xml4
-rw-r--r--packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml99
-rw-r--r--packages/SystemUI/res/values/colors.xml1
-rw-r--r--packages/SystemUI/res/values/config.xml3
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/res/values/strings.xml111
-rw-r--r--packages/SystemUI/res/values/styles.xml19
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java33
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt107
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java1382
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationDismissibilityProviderImpl.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt63
-rw-r--r--packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/UserModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserMode.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeModule.kt (renamed from telephony/java/android/telephony/satellite/ISatelliteCapabilitiesConsumer.aidl)15
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt56
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt107
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt68
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt81
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java80
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsReceiverTest.java135
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java79
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java98
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt100
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java63
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java6
-rw-r--r--services/api/current.txt58
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java4
-rw-r--r--services/companion/java/com/android/server/companion/virtual/SensorController.java90
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java60
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java12
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/BatteryService.java14
-rw-r--r--services/core/java/com/android/server/BinaryTransparencyService.java38
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java22
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java44
-rw-r--r--services/core/java/com/android/server/am/BroadcastProcessQueue.java49
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueModernImpl.java26
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java1
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java70
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java14
-rw-r--r--services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java10
-rw-r--r--services/core/java/com/android/server/display/DisplayControl.java8
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java63
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java10
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController2.java10
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java17
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java112
-rw-r--r--services/core/java/com/android/server/pm/DexOptHelper.java19
-rw-r--r--services/core/java/com/android/server/pm/IPackageManagerBase.java6
-rw-r--r--services/core/java/com/android/server/pm/InstallingSession.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelperImpl.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java11
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java4
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/Settings.java10
-rw-r--r--services/core/java/com/android/server/pm/UserManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java104
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java18
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java34
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java6
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java118
-rw-r--r--services/core/java/com/android/server/pm/pkg/AndroidPackage.java60
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageState.java8
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java4
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java73
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java73
-rw-r--r--services/core/java/com/android/server/power/LowPowerStandbyController.java40
-rw-r--r--services/core/java/com/android/server/sensors/SensorManagerInternal.java7
-rw-r--r--services/core/java/com/android/server/sensors/SensorService.java5
-rw-r--r--services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java23
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java37
-rw-r--r--services/core/java/com/android/server/wm/Transition.java41
-rw-r--r--services/core/jni/com_android_server_display_DisplayControl.cpp11
-rw-r--r--services/core/jni/com_android_server_sensor_SensorService.cpp25
-rw-r--r--services/credentials/java/com/android/server/credentials/ClearRequestSession.java9
-rw-r--r--services/credentials/java/com/android/server/credentials/CreateRequestSession.java8
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java2
-rw-r--r--services/credentials/java/com/android/server/credentials/GetRequestSession.java8
-rw-r--r--services/credentials/java/com/android/server/credentials/MetricUtilities.java95
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderClearSession.java3
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderCreateSession.java190
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderGetSession.java473
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java1
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderSession.java28
-rw-r--r--services/credentials/java/com/android/server/credentials/RemoteCredentialService.java185
-rw-r--r--services/credentials/java/com/android/server/credentials/RequestSession.java73
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java80
-rw-r--r--services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java90
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java27
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java28
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java317
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java30
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java53
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java62
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java12
-rw-r--r--services/java/com/android/server/HsumBootUserInitializer.java6
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/PermissionService.kt69
-rw-r--r--services/proguard.flags2
-rw-r--r--services/tests/PackageManagerServiceTests/appenumeration/Android.bp1
-rw-r--r--services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml1
-rw-r--r--services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java30
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt7
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java10
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt58
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java47
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java42
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java64
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt4
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java59
-rw-r--r--services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java85
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java27
-rw-r--r--services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java44
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java24
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java200
-rw-r--r--telecomm/java/android/telecom/CallControl.java4
-rw-r--r--telecomm/java/android/telecom/CallStreamingService.java27
-rw-r--r--telecomm/java/android/telecom/StreamingCall.java17
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java57
-rw-r--r--telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl6
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteCallback.java70
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteDatagram.aidl19
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteDatagram.java75
-rw-r--r--telephony/java/android/telephony/satellite/SatelliteManager.java779
-rw-r--r--telephony/java/com/android/internal/telephony/ISub.aidl16
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl184
-rw-r--r--tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java7
-rw-r--r--tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java12
-rw-r--r--tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java36
-rw-r--r--tools/aapt2/Android.bp1
-rw-r--r--tools/lint/fix/Android.bp6
-rw-r--r--tools/lint/fix/lint_fix.py106
-rw-r--r--tools/lint/fix/soong_lint_fix.py169
-rw-r--r--wifi/java/src/android/net/wifi/nl80211/PnoSettings.java54
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java57
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java8
-rw-r--r--wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java34
409 files changed, 12144 insertions, 4363 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 7c92793c6281..95d84c824dfc 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4614,6 +4614,7 @@ package android.app {
method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
method @NonNull public java.util.List<android.app.ApplicationExitInfo> getHistoricalProcessExitReasons(@Nullable String, @IntRange(from=0) int, @IntRange(from=0) int);
+ method @NonNull public java.util.List<android.app.ApplicationStartInfo> getHistoricalProcessStartReasons(@IntRange(from=0) int);
method public int getLargeMemoryClass();
method public int getLauncherLargeIconDensity();
method public int getLauncherLargeIconSize();
@@ -4639,7 +4640,9 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES) public void killBackgroundProcesses(String);
method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int);
method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int, android.os.Bundle);
+ method public void removeApplicationStartInfoCompleteListener();
method @Deprecated public void restartPackage(String);
+ method public void setApplicationStartInfoCompleteListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.ActivityManager.ApplicationStartInfoCompleteListener);
method public void setProcessStateSummary(@Nullable byte[]);
method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
@@ -4662,6 +4665,10 @@ package android.app {
method public void startActivity(android.content.Context, android.content.Intent, android.os.Bundle);
}
+ public static interface ActivityManager.ApplicationStartInfoCompleteListener {
+ method public void onApplicationStartInfoComplete(@NonNull android.app.ApplicationStartInfo);
+ }
+
public static class ActivityManager.MemoryInfo implements android.os.Parcelable {
ctor public ActivityManager.MemoryInfo();
method public int describeContents();
@@ -5221,6 +5228,52 @@ package android.app {
field public static final int REASON_USER_STOPPED = 11; // 0xb
}
+ public final class ApplicationStartInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDefiningUid();
+ method @Nullable public android.content.Intent getIntent();
+ method public int getLaunchMode();
+ method public int getPackageUid();
+ method public int getPid();
+ method @NonNull public String getProcessName();
+ method public int getRealUid();
+ method public int getReason();
+ method public int getStartType();
+ method public int getStartupState();
+ method @NonNull public java.util.Map<java.lang.Integer,java.lang.Long> getStartupTimestamps();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.ApplicationStartInfo> CREATOR;
+ field public static final int LAUNCH_MODE_SINGLE_INSTANCE = 2; // 0x2
+ field public static final int LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK = 4; // 0x4
+ field public static final int LAUNCH_MODE_SINGLE_TASK = 3; // 0x3
+ field public static final int LAUNCH_MODE_SINGLE_TOP = 1; // 0x1
+ field public static final int LAUNCH_MODE_STANDARD = 0; // 0x0
+ field public static final int STARTUP_STATE_ERROR = 1; // 0x1
+ field public static final int STARTUP_STATE_FIRST_FRAME_DRAWN = 2; // 0x2
+ field public static final int STARTUP_STATE_STARTED = 0; // 0x0
+ field public static final int START_REASON_ALARM = 0; // 0x0
+ field public static final int START_REASON_BACKUP = 1; // 0x1
+ field public static final int START_REASON_BOOT_COMPLETE = 2; // 0x2
+ field public static final int START_REASON_BROADCAST = 3; // 0x3
+ field public static final int START_REASON_CONTENT_PROVIDER = 4; // 0x4
+ field public static final int START_REASON_JOB = 5; // 0x5
+ field public static final int START_REASON_LAUNCHER = 6; // 0x6
+ field public static final int START_REASON_OTHER = 7; // 0x7
+ field public static final int START_REASON_PUSH = 8; // 0x8
+ field public static final int START_REASON_RESUMED_ACTIVITY = 9; // 0x9
+ field public static final int START_REASON_SERVICE = 10; // 0xa
+ field public static final int START_REASON_START_ACTIVITY = 11; // 0xb
+ field public static final int START_TIMESTAMP_APPLICATION_ONCREATE = 2; // 0x2
+ field public static final int START_TIMESTAMP_BIND_APPLICATION = 3; // 0x3
+ field public static final int START_TIMESTAMP_FIRST_FRAME = 4; // 0x4
+ field public static final int START_TIMESTAMP_FULLY_DRAWN = 5; // 0x5
+ field public static final int START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE = 1; // 0x1
+ field public static final int START_TIMESTAMP_LAUNCH = 0; // 0x0
+ field public static final int START_TYPE_COLD = 0; // 0x0
+ field public static final int START_TYPE_HOT = 2; // 0x2
+ field public static final int START_TYPE_WARM = 1; // 0x1
+ }
+
public final class AsyncNotedAppOp implements android.os.Parcelable {
method public int describeContents();
method @Nullable public String getAttributionTag();
@@ -7335,6 +7388,7 @@ package android.app {
public final class UiAutomation {
method public void adoptShellPermissionIdentity();
method public void adoptShellPermissionIdentity(@Nullable java.lang.String...);
+ method public boolean clearCache();
method @Deprecated public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
method public void dropShellPermissionIdentity();
@@ -7696,6 +7750,26 @@ package android.app.admin {
method public final android.os.IBinder onBind(android.content.Intent);
}
+ public final class DevicePolicyIdentifiers {
+ method @NonNull public static String getIdentifierForUserRestriction(@NonNull String);
+ field public static final String ACCOUNT_MANAGEMENT_DISABLED_POLICY = "accountManagementDisabled";
+ field public static final String APPLICATION_HIDDEN_POLICY = "applicationHidden";
+ field public static final String APPLICATION_RESTRICTIONS_POLICY = "applicationRestrictions";
+ field public static final String AUTO_TIMEZONE_POLICY = "autoTimezone";
+ field public static final String AUTO_TIME_POLICY = "autoTime";
+ field public static final String BACKUP_SERVICE_POLICY = "backupService";
+ field public static final String CAMERA_DISABLED_POLICY = "cameraDisabled";
+ field public static final String KEYGUARD_DISABLED_FEATURES_POLICY = "keyguardDisabledFeatures";
+ field public static final String LOCK_TASK_POLICY = "lockTask";
+ field public static final String PACKAGES_SUSPENDED_POLICY = "packagesSuspended";
+ field public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
+ field public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
+ field public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY = "persistentPreferredActivity";
+ field public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
+ field public static final String STATUS_BAR_DISABLED_POLICY = "statusBarDisabled";
+ field public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY = "userControlDisabledPackages";
+ }
+
public class DevicePolicyManager {
method public void acknowledgeDeviceCompliant();
method public void addCrossProfileIntentFilter(@NonNull android.content.ComponentName, android.content.IntentFilter, int);
@@ -7847,6 +7921,7 @@ package android.app.admin {
method public boolean isResetPasswordTokenActive(android.content.ComponentName);
method public boolean isSafeOperation(int);
method public boolean isSecurityLoggingEnabled(@Nullable android.content.ComponentName);
+ method public boolean isStatusBarDisabled();
method public boolean isUninstallBlocked(@Nullable android.content.ComponentName, String);
method public boolean isUniqueDeviceAttestationSupported();
method public boolean isUsbDataSignalingEnabled();
@@ -7881,7 +7956,7 @@ package android.app.admin {
method @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZoneEnabled(@NonNull android.content.ComponentName, boolean);
method public void setBackupServiceEnabled(@NonNull android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
- method public void setCameraDisabled(@NonNull android.content.ComponentName, boolean);
+ method @RequiresPermission(value=android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA, conditional=true) public void setCameraDisabled(@Nullable android.content.ComponentName, boolean);
method @Deprecated public void setCertInstallerPackage(@NonNull android.content.ComponentName, @Nullable String) throws java.lang.SecurityException;
method public void setCommonCriteriaModeEnabled(@NonNull android.content.ComponentName, boolean);
method public void setConfiguredNetworksLockdownState(@NonNull android.content.ComponentName, boolean);
@@ -8087,6 +8162,7 @@ package android.app.admin {
field @Deprecated public static final int KEYGUARD_DISABLE_REMOTE_INPUT = 64; // 0x40
field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
field public static final int KEYGUARD_DISABLE_SECURE_NOTIFICATIONS = 4; // 0x4
+ field public static final int KEYGUARD_DISABLE_SHORTCUTS_ALL = 512; // 0x200
field public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 16; // 0x10
field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
@@ -8248,6 +8324,8 @@ package android.app.admin {
ctor public PolicyUpdateResult(int);
method public int getResultCode();
field public static final int RESULT_FAILURE_CONFLICTING_ADMIN_POLICY = 1; // 0x1
+ field public static final int RESULT_FAILURE_HARDWARE_LIMITATION = 4; // 0x4
+ field public static final int RESULT_FAILURE_STORAGE_LIMIT_REACHED = 3; // 0x3
field public static final int RESULT_FAILURE_UNKNOWN = -1; // 0xffffffff
field public static final int RESULT_POLICY_CLEARED = 2; // 0x2
field public static final int RESULT_SUCCESS = 0; // 0x0
@@ -8260,6 +8338,7 @@ package android.app.admin {
method public final void onReceive(android.content.Context, android.content.Intent);
field public static final String ACTION_DEVICE_POLICY_CHANGED = "android.app.admin.action.DEVICE_POLICY_CHANGED";
field public static final String ACTION_DEVICE_POLICY_SET_RESULT = "android.app.admin.action.DEVICE_POLICY_SET_RESULT";
+ field public static final String EXTRA_ACCOUNT_TYPE = "android.app.admin.extra.ACCOUNT_TYPE";
field public static final String EXTRA_INTENT_FILTER = "android.app.admin.extra.INTENT_FILTER";
field public static final String EXTRA_PACKAGE_NAME = "android.app.admin.extra.PACKAGE_NAME";
field public static final String EXTRA_PERMISSION_NAME = "android.app.admin.extra.PERMISSION_NAME";
@@ -9460,10 +9539,10 @@ package android.companion {
method @Nullable public android.content.IntentSender buildAssociationCancellationIntent();
method @Nullable public android.content.IntentSender buildPermissionTransferUserConsentIntent(int) throws android.companion.DeviceNotAssociatedException;
method @RequiresPermission(android.Manifest.permission.DELIVER_COMPANION_MESSAGES) public void detachSystemDataTransport(int) throws android.companion.DeviceNotAssociatedException;
- method public void disableSystemDataSync(int, int);
+ method public void disableSystemDataSyncForTypes(int, int);
method @Deprecated public void disassociate(@NonNull String);
method public void disassociate(int);
- method public void enableSystemDataSync(int, int);
+ method public void enableSystemDataSyncForTypes(int, int);
method @Deprecated @NonNull public java.util.List<java.lang.String> getAssociations();
method @NonNull public java.util.List<android.companion.AssociationInfo> getMyAssociations();
method @Deprecated public boolean hasNotificationAccess(android.content.ComponentName);
@@ -27161,6 +27240,10 @@ package android.media.tv {
field public static final int SIGNAL_STRENGTH_STRONG = 3; // 0x3
field public static final int SIGNAL_STRENGTH_WEAK = 2; // 0x2
field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
+ field public static final int TIME_SHIFT_MODE_AUTO = 4; // 0x4
+ field public static final int TIME_SHIFT_MODE_LOCAL = 2; // 0x2
+ field public static final int TIME_SHIFT_MODE_NETWORK = 3; // 0x3
+ field public static final int TIME_SHIFT_MODE_OFF = 1; // 0x1
field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
field public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2; // 0x2
field public static final int TIME_SHIFT_STATUS_UNKNOWN = 0; // 0x0
@@ -27245,11 +27328,14 @@ package android.media.tv {
method public void notifyAitInfoUpdated(@NonNull android.media.tv.AitInfo);
method public void notifyAudioPresentationChanged(@NonNull java.util.List<android.media.AudioPresentation>);
method public void notifyAudioPresentationSelected(int, int);
+ method public void notifyAvailableSpeeds(@NonNull float[]);
method public void notifyBroadcastInfoResponse(@NonNull android.media.tv.BroadcastInfoResponse);
method public void notifyChannelRetuned(android.net.Uri);
method public void notifyContentAllowed();
method public void notifyContentBlocked(@NonNull android.media.tv.TvContentRating);
+ method public void notifyCueingMessageAvailability(boolean);
method public void notifySignalStrength(int);
+ method public void notifyTimeShiftMode(int);
method public void notifyTimeShiftStatusChanged(int);
method public void notifyTrackSelected(int, String);
method public void notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>);
@@ -27284,6 +27370,7 @@ package android.media.tv {
method public void onTimeShiftPlay(android.net.Uri);
method public void onTimeShiftResume();
method public void onTimeShiftSeekTo(long);
+ method public void onTimeShiftSetMode(int);
method public void onTimeShiftSetPlaybackParams(android.media.PlaybackParams);
method public boolean onTouchEvent(android.view.MotionEvent);
method public boolean onTrackballEvent(android.view.MotionEvent);
@@ -27301,6 +27388,7 @@ package android.media.tv {
method public void resumeRecording();
method public void resumeRecording(@NonNull android.os.Bundle);
method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle);
+ method public void setTvInteractiveAppView(@Nullable android.media.tv.interactive.TvInteractiveAppView, @Nullable String);
method public void startRecording(@Nullable android.net.Uri);
method public void startRecording(@Nullable android.net.Uri, @NonNull android.os.Bundle);
method public void stopRecording();
@@ -27423,6 +27511,7 @@ package android.media.tv {
method public void timeShiftPlay(String, android.net.Uri);
method public void timeShiftResume();
method public void timeShiftSeekTo(long);
+ method public void timeShiftSetMode(int);
method public void timeShiftSetPlaybackParams(@NonNull android.media.PlaybackParams);
method public void tune(@NonNull String, android.net.Uri);
method public void tune(String, android.net.Uri, android.os.Bundle);
@@ -27443,12 +27532,15 @@ package android.media.tv {
method public void onAitInfoUpdated(@NonNull String, @NonNull android.media.tv.AitInfo);
method public void onAudioPresentationSelected(@NonNull String, int, int);
method public void onAudioPresentationsChanged(@NonNull String, @NonNull java.util.List<android.media.AudioPresentation>);
+ method public void onAvailableSpeeds(@NonNull String, @NonNull float[]);
method public void onChannelRetuned(String, android.net.Uri);
method public void onConnectionFailed(String);
method public void onContentAllowed(String);
method public void onContentBlocked(String, android.media.tv.TvContentRating);
+ method public void onCueingMessageAvailability(@NonNull String, boolean);
method public void onDisconnected(String);
method public void onSignalStrengthUpdated(@NonNull String, int);
+ method public void onTimeShiftMode(@NonNull String, int);
method public void onTimeShiftStatusChanged(String, int);
method public void onTrackSelected(String, int, String);
method public void onTracksChanged(String, java.util.List<android.media.tv.TvTrackInfo>);
@@ -27473,6 +27565,7 @@ package android.media.tv.interactive {
}
public final class TvInteractiveAppManager {
+ method @NonNull public java.util.List<android.media.tv.interactive.AppLinkInfo> getAppLinkInfoList();
method @NonNull public java.util.List<android.media.tv.interactive.TvInteractiveAppServiceInfo> getTvInteractiveAppServiceList();
method public void registerAppLinkInfo(@NonNull String, @NonNull android.media.tv.interactive.AppLinkInfo);
method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppManager.TvInteractiveAppCallback);
@@ -27530,7 +27623,11 @@ package android.media.tv.interactive {
field public static final String COMMAND_PARAMETER_KEY_CHANGE_CHANNEL_QUIETLY = "command_change_channel_quietly";
field public static final String COMMAND_PARAMETER_KEY_CHANNEL_URI = "command_channel_uri";
field public static final String COMMAND_PARAMETER_KEY_INPUT_ID = "command_input_id";
+ field public static final String COMMAND_PARAMETER_KEY_PLAYBACK_PARAMS = "command_playback_params";
+ field public static final String COMMAND_PARAMETER_KEY_PROGRAM_URI = "command_program_uri";
field public static final String COMMAND_PARAMETER_KEY_STOP_MODE = "command_stop_mode";
+ field public static final String COMMAND_PARAMETER_KEY_TIME_POSITION = "command_time_position";
+ field public static final String COMMAND_PARAMETER_KEY_TIME_SHIFT_MODE = "command_time_shift_mode";
field public static final String COMMAND_PARAMETER_KEY_TRACK_ID = "command_track_id";
field public static final String COMMAND_PARAMETER_KEY_TRACK_TYPE = "command_track_type";
field public static final String COMMAND_PARAMETER_KEY_VOLUME = "command_volume";
@@ -27544,6 +27641,12 @@ package android.media.tv.interactive {
field public static final String PLAYBACK_COMMAND_TYPE_TUNE_PREV = "tune_previous";
field public static final String SERVICE_INTERFACE = "android.media.tv.interactive.TvInteractiveAppService";
field public static final String SERVICE_META_DATA = "android.media.tv.interactive.app";
+ field public static final String TIME_SHIFT_COMMAND_TYPE_PAUSE = "pause";
+ field public static final String TIME_SHIFT_COMMAND_TYPE_PLAY = "play";
+ field public static final String TIME_SHIFT_COMMAND_TYPE_RESUME = "resume";
+ field public static final String TIME_SHIFT_COMMAND_TYPE_SEEK_TO = "seek_to";
+ field public static final String TIME_SHIFT_COMMAND_TYPE_SET_MODE = "set_mode";
+ field public static final String TIME_SHIFT_COMMAND_TYPE_SET_PLAYBACK_PARAMS = "set_playback_params";
}
public abstract static class TvInteractiveAppService.Session implements android.view.KeyEvent.Callback {
@@ -27556,6 +27659,7 @@ package android.media.tv.interactive {
method @CallSuper public final void notifyTeletextAppStateChanged(int);
method public void onAdBufferConsumed(@NonNull android.media.tv.AdBuffer);
method public void onAdResponse(@NonNull android.media.tv.AdResponse);
+ method public void onAvailableSpeeds(@NonNull float[]);
method public void onBroadcastInfoResponse(@NonNull android.media.tv.BroadcastInfoResponse);
method public void onContentAllowed();
method public void onContentBlocked(@NonNull android.media.tv.TvContentRating);
@@ -27573,8 +27677,13 @@ package android.media.tv.interactive {
method public boolean onKeyMultiple(int, int, @NonNull android.view.KeyEvent);
method public boolean onKeyUp(int, @NonNull android.view.KeyEvent);
method public void onMediaViewSizeChanged(@Px int, @Px int);
- method public void onRecordingStarted(@NonNull String);
+ method public void onRecordingConnectionFailed(@NonNull String, @NonNull String);
+ method public void onRecordingDisconnected(@NonNull String, @NonNull String);
+ method public void onRecordingError(@NonNull String, int);
+ method public void onRecordingScheduled(@NonNull String, @Nullable String);
+ method public void onRecordingStarted(@NonNull String, @Nullable String);
method public void onRecordingStopped(@NonNull String);
+ method public void onRecordingTuned(@NonNull String, @NonNull android.net.Uri);
method public abstract void onRelease();
method public void onResetInteractiveApp();
method public abstract boolean onSetSurface(@Nullable android.view.Surface);
@@ -27585,6 +27694,11 @@ package android.media.tv.interactive {
method public void onStopInteractiveApp();
method public void onStreamVolume(float);
method public void onSurfaceChanged(int, int, int);
+ method public void onTimeShiftCurrentPositionChanged(@NonNull String, long);
+ method public void onTimeShiftMode(int);
+ method public void onTimeShiftPlaybackParams(@NonNull android.media.PlaybackParams);
+ method public void onTimeShiftStartPositionChanged(@NonNull String, long);
+ method public void onTimeShiftStatusChanged(@NonNull String, int);
method public boolean onTouchEvent(@NonNull android.view.MotionEvent);
method public void onTrackInfoList(@NonNull java.util.List<android.media.tv.TvTrackInfo>);
method public void onTrackSelected(int, @NonNull String);
@@ -27598,19 +27712,24 @@ package android.media.tv.interactive {
method public void onVideoUnavailable(int);
method @CallSuper public void removeBroadcastInfo(int);
method @CallSuper public void requestAd(@NonNull android.media.tv.AdRequest);
+ method @CallSuper public void requestAvailableSpeeds();
method @CallSuper public void requestBroadcastInfo(@NonNull android.media.tv.BroadcastInfoRequest);
method @CallSuper public void requestCurrentChannelLcn();
method @CallSuper public void requestCurrentChannelUri();
method @CallSuper public void requestCurrentTvInputId();
method @CallSuper public void requestCurrentVideoBounds();
+ method @CallSuper public void requestScheduleRecording(@NonNull String, @NonNull String, @NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.os.Bundle);
+ method @CallSuper public void requestScheduleRecording(@NonNull String, @NonNull String, @NonNull android.net.Uri, long, long, int, @NonNull android.os.Bundle);
method @CallSuper public void requestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
- method @CallSuper public void requestStartRecording(@Nullable android.net.Uri);
+ method @CallSuper public void requestStartRecording(@NonNull String, @Nullable android.net.Uri);
method @CallSuper public void requestStopRecording(@NonNull String);
method @CallSuper public void requestStreamVolume();
+ method @CallSuper public void requestTimeShiftMode();
method @CallSuper public void requestTrackInfoList();
method @CallSuper public void requestTvRecordingInfo(@NonNull String);
method @CallSuper public void requestTvRecordingInfoList(@NonNull int);
method @CallSuper public void sendPlaybackCommandRequest(@NonNull String, @Nullable android.os.Bundle);
+ method @CallSuper public void sendTimeShiftCommandRequest(@NonNull String, @Nullable android.os.Bundle);
method @CallSuper public void setMediaViewEnabled(boolean);
method @CallSuper public void setTvRecordingInfo(@NonNull String, @NonNull android.media.tv.TvRecordingInfo);
method @CallSuper public void setVideoBounds(@NonNull android.graphics.Rect);
@@ -27619,6 +27738,7 @@ package android.media.tv.interactive {
public final class TvInteractiveAppServiceInfo implements android.os.Parcelable {
ctor public TvInteractiveAppServiceInfo(@NonNull android.content.Context, @NonNull android.content.ComponentName);
method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getCustomSupportedTypes();
method @NonNull public String getId();
method @Nullable public android.content.pm.ServiceInfo getServiceInfo();
method @NonNull public int getSupportedTypes();
@@ -27627,6 +27747,8 @@ package android.media.tv.interactive {
field public static final int INTERACTIVE_APP_TYPE_ATSC = 2; // 0x2
field public static final int INTERACTIVE_APP_TYPE_GINGA = 4; // 0x4
field public static final int INTERACTIVE_APP_TYPE_HBBTV = 1; // 0x1
+ field public static final int INTERACTIVE_APP_TYPE_OTHER = -2147483648; // 0x80000000
+ field public static final int INTERACTIVE_APP_TYPE_TARGETED_AD = 8; // 0x8
}
public class TvInteractiveAppView extends android.view.ViewGroup {
@@ -27640,8 +27762,13 @@ package android.media.tv.interactive {
method public boolean dispatchUnhandledInputEvent(@NonNull android.view.InputEvent);
method @Nullable public android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener getOnUnhandledInputEventListener();
method public void notifyError(@NonNull String, @NonNull android.os.Bundle);
- method public void notifyRecordingStarted(@NonNull String);
+ method public void notifyRecordingScheduled(@NonNull String, @Nullable String);
+ method public void notifyRecordingStarted(@NonNull String, @Nullable String);
method public void notifyRecordingStopped(@NonNull String);
+ method public void notifyTimeShiftCurrentPositionChanged(@NonNull String, long);
+ method public void notifyTimeShiftPlaybackParams(@NonNull android.media.PlaybackParams);
+ method public void notifyTimeShiftStartPositionChanged(@NonNull String, long);
+ method public void notifyTimeShiftStatusChanged(@NonNull String, int);
method public void notifyTvMessage(@NonNull String, @NonNull android.os.Bundle);
method public void onAttachedToWindow();
method public void onDetachedFromWindow();
@@ -27652,12 +27779,14 @@ package android.media.tv.interactive {
method public void prepareInteractiveApp(@NonNull String, int);
method public void reset();
method public void resetInteractiveApp();
+ method public void sendAvailableSpeeds(@NonNull float[]);
method public void sendCurrentChannelLcn(int);
method public void sendCurrentChannelUri(@Nullable android.net.Uri);
method public void sendCurrentTvInputId(@Nullable String);
method public void sendCurrentVideoBounds(@NonNull android.graphics.Rect);
method public void sendSigningResult(@NonNull String, @NonNull byte[]);
method public void sendStreamVolume(float);
+ method public void sendTimeShiftMode(int);
method public void sendTrackInfoList(@Nullable java.util.List<android.media.tv.TvTrackInfo>);
method public void sendTvRecordingInfo(@Nullable android.media.tv.TvRecordingInfo);
method public void sendTvRecordingInfoList(@NonNull java.util.List<android.media.tv.TvRecordingInfo>);
@@ -27683,14 +27812,18 @@ package android.media.tv.interactive {
ctor public TvInteractiveAppView.TvInteractiveAppCallback();
method public void onBiInteractiveAppCreated(@NonNull String, @NonNull android.net.Uri, @Nullable String);
method public void onPlaybackCommandRequest(@NonNull String, @NonNull String, @NonNull android.os.Bundle);
+ method public void onRequestAvailableSpeeds(@NonNull String);
method public void onRequestCurrentChannelLcn(@NonNull String);
method public void onRequestCurrentChannelUri(@NonNull String);
method public void onRequestCurrentTvInputId(@NonNull String);
method public void onRequestCurrentVideoBounds(@NonNull String);
+ method public void onRequestScheduleRecording(@NonNull String, @NonNull String, @NonNull String, @NonNull android.net.Uri, @NonNull android.net.Uri, @NonNull android.os.Bundle);
+ method public void onRequestScheduleRecording(@NonNull String, @NonNull String, @NonNull String, @NonNull android.net.Uri, long, long, int, @NonNull android.os.Bundle);
method public void onRequestSigning(@NonNull String, @NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
- method public void onRequestStartRecording(@NonNull String, @Nullable android.net.Uri);
+ method public void onRequestStartRecording(@NonNull String, @NonNull String, @Nullable android.net.Uri);
method public void onRequestStopRecording(@NonNull String, @NonNull String);
method public void onRequestStreamVolume(@NonNull String);
+ method public void onRequestTimeShiftMode(@NonNull String);
method public void onRequestTrackInfoList(@NonNull String);
method public void onRequestTvRecordingInfo(@NonNull String, @NonNull String);
method public void onRequestTvRecordingInfoList(@NonNull String, @NonNull int);
@@ -27698,6 +27831,7 @@ package android.media.tv.interactive {
method public void onSetVideoBounds(@NonNull String, @NonNull android.graphics.Rect);
method public void onStateChanged(@NonNull String, int, int);
method public void onTeletextAppStateChanged(@NonNull String, int);
+ method public void onTimeShiftCommandRequest(@NonNull String, @NonNull String, @NonNull android.os.Bundle);
}
}
@@ -28818,24 +28952,15 @@ package android.nfc {
public final class NfcAdapter {
method public void disableForegroundDispatch(android.app.Activity);
- method @Deprecated public void disableForegroundNdefPush(android.app.Activity);
method public void disableReaderMode(android.app.Activity);
method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]);
- method @Deprecated public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo();
method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
- method @Deprecated public boolean invokeBeam(android.app.Activity);
method public boolean isEnabled();
- method @Deprecated public boolean isNdefPushEnabled();
method public boolean isSecureNfcEnabled();
method public boolean isSecureNfcSupported();
- method @Deprecated public void setBeamPushUris(android.net.Uri[], android.app.Activity);
- method @Deprecated public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
- method @Deprecated public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
- method @Deprecated public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
- method @Deprecated public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
field @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static final String ACTION_PREFERRED_PAYMENT_CHANGED = "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
@@ -33312,6 +33437,7 @@ package android.os {
field public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1; // 0x1
field public static final int LOCATION_MODE_NO_CHANGE = 0; // 0x0
field public static final int LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF = 4; // 0x4
+ field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST = 2; // 0x2
field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION = 1; // 0x1
field public static final String LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN = "com.android.lowpowerstandby.WAKE_ON_LAN";
field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
@@ -41265,6 +41391,31 @@ package android.speech {
method public default void onSegmentResults(@NonNull android.os.Bundle);
}
+ public final class RecognitionPart implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getConfidenceLevel();
+ method @Nullable public String getFormattedText();
+ method @NonNull public String getRawText();
+ method public long getTimestampMillis();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CONFIDENCE_LEVEL_HIGH = 5; // 0x5
+ field public static final int CONFIDENCE_LEVEL_LOW = 1; // 0x1
+ field public static final int CONFIDENCE_LEVEL_LOW_MEDIUM = 2; // 0x2
+ field public static final int CONFIDENCE_LEVEL_MEDIUM = 3; // 0x3
+ field public static final int CONFIDENCE_LEVEL_MEDIUM_HIGH = 4; // 0x4
+ field public static final int CONFIDENCE_LEVEL_UNKNOWN = 0; // 0x0
+ field @NonNull public static final android.os.Parcelable.Creator<android.speech.RecognitionPart> CREATOR;
+ }
+
+ public static final class RecognitionPart.Builder {
+ ctor public RecognitionPart.Builder(@NonNull String);
+ method @NonNull public android.speech.RecognitionPart build();
+ method @NonNull public android.speech.RecognitionPart.Builder setConfidenceLevel(int);
+ method @NonNull public android.speech.RecognitionPart.Builder setFormattedText(@NonNull String);
+ method @NonNull public android.speech.RecognitionPart.Builder setRawText(@NonNull String);
+ method @NonNull public android.speech.RecognitionPart.Builder setTimestampMillis(long);
+ }
+
public abstract class RecognitionService extends android.app.Service {
ctor public RecognitionService();
method public int getMaxConcurrentSessionsCount();
@@ -41354,6 +41505,8 @@ package android.speech {
field public static final String EXTRA_PARTIAL_RESULTS = "android.speech.extra.PARTIAL_RESULTS";
field public static final String EXTRA_PREFER_OFFLINE = "android.speech.extra.PREFER_OFFLINE";
field public static final String EXTRA_PROMPT = "android.speech.extra.PROMPT";
+ field public static final String EXTRA_REQUEST_WORD_CONFIDENCE = "android.speech.extra.REQUEST_WORD_CONFIDENCE";
+ field public static final String EXTRA_REQUEST_WORD_TIMING = "android.speech.extra.REQUEST_WORD_TIMING";
field public static final String EXTRA_RESULTS = "android.speech.extra.RESULTS";
field public static final String EXTRA_RESULTS_PENDINGINTENT = "android.speech.extra.RESULTS_PENDINGINTENT";
field public static final String EXTRA_RESULTS_PENDINGINTENT_BUNDLE = "android.speech.extra.RESULTS_PENDINGINTENT_BUNDLE";
@@ -41413,6 +41566,7 @@ package android.speech {
field public static final int ERROR_SERVER_DISCONNECTED = 11; // 0xb
field public static final int ERROR_SPEECH_TIMEOUT = 6; // 0x6
field public static final int ERROR_TOO_MANY_REQUESTS = 10; // 0xa
+ field public static final String RECOGNITION_PARTS = "recognition_parts";
field public static final String RESULTS_ALTERNATIVES = "results_alternatives";
field public static final String RESULTS_RECOGNITION = "results_recognition";
}
@@ -41940,18 +42094,6 @@ package android.telecom {
method public android.telecom.CallScreeningService.CallResponse.Builder setSkipNotification(boolean);
}
- public abstract class CallStreamingService extends android.app.Service {
- ctor public CallStreamingService();
- method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
- method public void onCallStreamingStarted(@NonNull android.telecom.StreamingCall);
- method public void onCallStreamingStateChanged(int);
- method public void onCallStreamingStopped();
- field public static final String SERVICE_INTERFACE = "android.telecom.CallStreamingService";
- field public static final int STREAMING_FAILED_ALREADY_STREAMING = 1; // 0x1
- field public static final int STREAMING_FAILED_NO_SENDER = 2; // 0x2
- field public static final int STREAMING_FAILED_SENDER_BINDING_ERROR = 3; // 0x3
- }
-
public abstract class Conference extends android.telecom.Conferenceable {
ctor public Conference(android.telecom.PhoneAccountHandle);
method public final boolean addConnection(android.telecom.Connection);
@@ -42624,22 +42766,6 @@ package android.telecom {
field @NonNull public static final android.os.Parcelable.Creator<android.telecom.StatusHints> CREATOR;
}
- public final class StreamingCall implements android.os.Parcelable {
- ctor public StreamingCall(@NonNull android.content.ComponentName, @NonNull String, @NonNull android.net.Uri, @NonNull android.os.Bundle);
- method public int describeContents();
- method @NonNull public android.net.Uri getAddress();
- method @NonNull public android.content.ComponentName getComponentName();
- method @NonNull public String getDisplayName();
- method @NonNull public android.os.Bundle getExtras();
- method public int getState();
- method public void requestStreamingState(int);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telecom.StreamingCall> CREATOR;
- field public static final int STATE_DISCONNECTED = 3; // 0x3
- field public static final int STATE_HOLDING = 2; // 0x2
- field public static final int STATE_STREAMING = 1; // 0x1
- }
-
public class TelecomManager {
method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
@@ -53631,12 +53757,14 @@ package android.view {
method public int getFitInsetsTypes();
method public final CharSequence getTitle();
method public boolean isFitInsetsIgnoringVisibility();
+ method public boolean isHdrConversionEnabled();
method public static boolean mayUseInputMethod(int);
method public void setBlurBehindRadius(@IntRange(from=0) int);
method public void setColorMode(int);
method public void setFitInsetsIgnoringVisibility(boolean);
method public void setFitInsetsSides(int);
method public void setFitInsetsTypes(int);
+ method public void setHdrConversionEnabled(boolean);
method public final void setTitle(CharSequence);
method public void setWallpaperTouchEventsEnabled(boolean);
method public void writeToParcel(android.os.Parcel, int);
@@ -53647,6 +53775,7 @@ package android.view {
field public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
field @NonNull public static final android.os.Parcelable.Creator<android.view.WindowManager.LayoutParams> CREATOR;
field public static final int DIM_AMOUNT_CHANGED = 32; // 0x20
+ field public static final int DISPLAY_FLAG_DISABLE_HDR_CONVERSION = 1; // 0x1
field public static final int FIRST_APPLICATION_WINDOW = 1; // 0x1
field public static final int FIRST_SUB_WINDOW = 1000; // 0x3e8
field public static final int FIRST_SYSTEM_WINDOW = 2000; // 0x7d0
@@ -53956,6 +54085,7 @@ package android.view.accessibility {
method public java.util.List<java.lang.String> getAvailableExtraData();
method @Deprecated public void getBoundsInParent(android.graphics.Rect);
method public void getBoundsInScreen(android.graphics.Rect);
+ method public void getBoundsInWindow(@NonNull android.graphics.Rect);
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
method @Nullable public android.view.accessibility.AccessibilityNodeInfo getChild(int, int);
method public int getChildCount();
@@ -54034,6 +54164,7 @@ package android.view.accessibility {
method public void setAvailableExtraData(java.util.List<java.lang.String>);
method @Deprecated public void setBoundsInParent(android.graphics.Rect);
method public void setBoundsInScreen(android.graphics.Rect);
+ method public void setBoundsInWindow(@NonNull android.graphics.Rect);
method public void setCanOpenPopup(boolean);
method public void setCheckable(boolean);
method public void setChecked(boolean);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 517102741117..1e21c77675c6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -166,6 +166,7 @@ package android.media {
method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp();
method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BluetoothProfileConnectionInfo);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setA2dpSuspended(boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK) public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean);
@@ -462,6 +463,25 @@ package android.provider {
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public static java.util.Map<java.lang.String,java.util.List<android.content.ContentValues>> queryRawContactEntity(@NonNull android.content.ContentResolver, long);
}
+ public class DeviceConfigInitializer {
+ method @Nullable public static android.provider.DeviceConfigServiceManager getDeviceConfigServiceManager();
+ method public static void setDeviceConfigServiceManager(@NonNull android.provider.DeviceConfigServiceManager);
+ }
+
+ public class DeviceConfigServiceManager {
+ method @NonNull public android.provider.DeviceConfigServiceManager.ServiceRegisterer getDeviceConfigUpdatableServiceRegisterer();
+ }
+
+ public static class DeviceConfigServiceManager.ServiceNotFoundException extends java.lang.Exception {
+ }
+
+ public static final class DeviceConfigServiceManager.ServiceRegisterer {
+ method @Nullable public android.os.IBinder get();
+ method @NonNull public android.os.IBinder getOrThrow() throws android.provider.DeviceConfigServiceManager.ServiceNotFoundException;
+ method public void register(@NonNull android.os.IBinder);
+ method @Nullable public android.os.IBinder tryGet();
+ }
+
public final class Settings {
field public static final int RESET_MODE_PACKAGE_DEFAULTS = 1; // 0x1
field public static final int RESET_MODE_TRUSTED_DEFAULTS = 4; // 0x4
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 1fa1e89fb46e..8b3696a1e6d9 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -252,6 +252,22 @@ package android.net {
}
+package android.nfc {
+
+ public final class NfcAdapter {
+ method @Deprecated public void disableForegroundNdefPush(android.app.Activity);
+ method @Deprecated public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
+ method @Deprecated public boolean invokeBeam(android.app.Activity);
+ method @Deprecated public boolean isNdefPushEnabled();
+ method @Deprecated public void setBeamPushUris(android.net.Uri[], android.app.Activity);
+ method @Deprecated public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
+ method @Deprecated public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
+ method @Deprecated public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
+ method @Deprecated public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
+ }
+
+}
+
package android.os {
public class BatteryManager {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index fde95bd3fb1e..07c471d6ce2e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -46,6 +46,7 @@ package android {
field public static final String BIND_ATTENTION_SERVICE = "android.permission.BIND_ATTENTION_SERVICE";
field public static final String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE";
field public static final String BIND_CALL_DIAGNOSTIC_SERVICE = "android.permission.BIND_CALL_DIAGNOSTIC_SERVICE";
+ field public static final String BIND_CALL_STREAMING_SERVICE = "android.permission.BIND_CALL_STREAMING_SERVICE";
field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE";
field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE";
@@ -174,6 +175,7 @@ package android {
field public static final String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
field public static final String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
+ field public static final String MANAGE_DEFAULT_APPLICATIONS = "android.permission.MANAGE_DEFAULT_APPLICATIONS";
field public static final String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
field public static final String MANAGE_DEVICE_POLICY_APP_EXEMPTIONS = "android.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS";
field public static final String MANAGE_ETHERNET_NETWORKS = "android.permission.MANAGE_ETHERNET_NETWORKS";
@@ -275,6 +277,7 @@ package android {
field public static final String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS";
field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
field public static final String READ_PROJECTION_STATE = "android.permission.READ_PROJECTION_STATE";
+ field public static final String READ_RESTRICTED_STATS = "android.permission.READ_RESTRICTED_STATS";
field public static final String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
field public static final String READ_SAFETY_CENTER_STATUS = "android.permission.READ_SAFETY_CENTER_STATUS";
field public static final String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
@@ -523,6 +526,7 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
+ method @NonNull @RequiresPermission(android.Manifest.permission.DUMP) public java.util.List<android.app.ApplicationStartInfo> getExternalHistoricalProcessStartReasons(@NonNull String, @IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
method @NonNull public java.util.Collection<java.util.Locale> getSupportedLocales();
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
@@ -626,6 +630,7 @@ package android.app {
field public static final String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background";
field public static final String OPSTR_RUN_IN_BACKGROUND = "android:run_in_background";
field public static final String OPSTR_START_FOREGROUND = "android:start_foreground";
+ field public static final String OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION = "android:system_exempt_from_hibernation";
field public static final String OPSTR_TAKE_AUDIO_FOCUS = "android:take_audio_focus";
field public static final String OPSTR_TAKE_MEDIA_BUTTONS = "android:take_media_buttons";
field public static final String OPSTR_TOAST_WINDOW = "android:toast_window";
@@ -1201,11 +1206,19 @@ package android.app {
package android.app.admin {
+ public final class AccountTypePolicyKey extends android.app.admin.PolicyKey {
+ method public int describeContents();
+ method @NonNull public String getAccountType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.AccountTypePolicyKey> CREATOR;
+ }
+
public abstract class Authority implements android.os.Parcelable {
method public int describeContents();
}
public final class DeviceAdminAuthority extends android.app.admin.Authority {
+ ctor public DeviceAdminAuthority();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DeviceAdminAuthority> CREATOR;
}
@@ -1286,6 +1299,7 @@ package android.app.admin {
field public static final int EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION = 2; // 0x2
field public static final int EXEMPT_FROM_APP_STANDBY = 0; // 0x0
field public static final int EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS = 1; // 0x1
+ field public static final int EXEMPT_FROM_HIBERNATION = 3; // 0x3
field public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER = "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
field public static final String EXTRA_LOST_MODE_LOCATION = "android.app.extra.LOST_MODE_LOCATION";
field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
@@ -1388,11 +1402,13 @@ package android.app.admin {
}
public final class DpcAuthority extends android.app.admin.Authority {
+ ctor public DpcAuthority();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DpcAuthority> CREATOR;
}
public final class EnforcingAdmin implements android.os.Parcelable {
+ ctor public EnforcingAdmin(@NonNull String, @NonNull android.app.admin.Authority, @NonNull android.os.UserHandle);
method public int describeContents();
method @NonNull public android.app.admin.Authority getAuthority();
method @NonNull public String getPackageName();
@@ -1516,6 +1532,7 @@ package android.app.admin {
}
public final class RoleAuthority extends android.app.admin.Authority {
+ ctor public RoleAuthority(@NonNull java.util.Set<java.lang.String>);
method @NonNull public java.util.Set<java.lang.String> getRoles();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.RoleAuthority> CREATOR;
@@ -1536,6 +1553,7 @@ package android.app.admin {
}
public final class UnknownAuthority extends android.app.admin.Authority {
+ ctor public UnknownAuthority();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.UnknownAuthority> CREATOR;
}
@@ -3185,7 +3203,7 @@ package android.companion.virtual {
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.input.VirtualTouchscreenConfig);
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method public int getDeviceId();
- method @Nullable public android.companion.virtual.sensor.VirtualSensor getVirtualSensor(int, @NonNull String);
+ method @NonNull public java.util.List<android.companion.virtual.sensor.VirtualSensor> getVirtualSensorList();
method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void registerIntentInterceptor(@NonNull android.content.IntentFilter, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
@@ -3240,6 +3258,7 @@ package android.companion.virtual {
method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set<android.os.UserHandle>);
+ method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setVirtualSensorCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.sensor.VirtualSensorCallback);
}
}
@@ -3291,14 +3310,18 @@ package android.companion.virtual.audio {
package android.companion.virtual.sensor {
- public class VirtualSensor {
+ public final class VirtualSensor implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDeviceId();
method @NonNull public String getName();
method public int getType();
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendEvent(@NonNull android.companion.virtual.sensor.VirtualSensorEvent);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.sensor.VirtualSensor> CREATOR;
}
- public static interface VirtualSensor.SensorStateChangeCallback {
- method public void onStateChanged(boolean, @NonNull java.time.Duration, @NonNull java.time.Duration);
+ public interface VirtualSensorCallback {
+ method public void onConfigurationChanged(@NonNull android.companion.virtual.sensor.VirtualSensor, boolean, @NonNull java.time.Duration, @NonNull java.time.Duration);
}
public final class VirtualSensorConfig implements android.os.Parcelable {
@@ -3313,7 +3336,6 @@ package android.companion.virtual.sensor {
public static final class VirtualSensorConfig.Builder {
ctor public VirtualSensorConfig.Builder(int, @NonNull String);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig build();
- method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setStateChangeCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.sensor.VirtualSensor.SensorStateChangeCallback);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setVendor(@Nullable String);
}
@@ -5960,7 +5982,7 @@ package android.hardware.usb {
method public boolean isHotPlugDetectActive();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.usb.DisplayPortAltModeInfo> CREATOR;
- field public static final int DISPLAYPORT_ALT_MODE_STATUS_CAPABLE = 2; // 0x2
+ field public static final int DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED = 2; // 0x2
field public static final int DISPLAYPORT_ALT_MODE_STATUS_ENABLED = 3; // 0x3
field public static final int DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE = 1; // 0x1
field public static final int DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN = 0; // 0x0
@@ -5978,7 +6000,7 @@ package android.hardware.usb {
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USB) public java.util.List<android.hardware.usb.UsbPort> getPorts();
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void grantPermission(android.hardware.usb.UsbDevice, String);
method public static boolean isUvcSupportEnabled();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public boolean registerDisplayPortAltModeInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.usb.UsbManager.DisplayPortAltModeInfoListener);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void registerDisplayPortAltModeInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.usb.UsbManager.DisplayPortAltModeInfoListener);
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void resetUsbGadget();
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long);
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void unregisterDisplayPortAltModeInfoListener(@NonNull android.hardware.usb.UsbManager.DisplayPortAltModeInfoListener);
@@ -9831,11 +9853,15 @@ package android.net.wifi.nl80211 {
method public int getMin5gRssiDbm();
method public int getMin6gRssiDbm();
method @NonNull public java.util.List<android.net.wifi.nl80211.PnoNetwork> getPnoNetworks();
+ method public int getScanIntervalMultiplier();
+ method public int getScanIterations();
method public void setIntervalMillis(long);
method public void setMin2gRssiDbm(int);
method public void setMin5gRssiDbm(int);
method public void setMin6gRssiDbm(int);
method public void setPnoNetworks(@NonNull java.util.List<android.net.wifi.nl80211.PnoNetwork>);
+ method public void setScanIntervalMultiplier(int);
+ method public void setScanIterations(int);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.PnoSettings> CREATOR;
}
@@ -10114,9 +10140,7 @@ package android.nfc {
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disableNdefPush();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
@@ -10125,10 +10149,8 @@ package android.nfc {
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
- method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
- field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff
field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0
field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe
@@ -12448,7 +12470,7 @@ package android.service.notification {
method public final void adjustNotification(@NonNull android.service.notification.Adjustment);
method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
- method public void onAllowedAdjustmentsChanged();
+ method @Deprecated public void onAllowedAdjustmentsChanged();
method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
method public void onNotificationClicked(@NonNull String);
method public void onNotificationDirectReplied(@NonNull String);
@@ -13301,6 +13323,19 @@ package android.telecom {
method @NonNull @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallViaAudioProcessing(boolean);
}
+ public abstract class CallStreamingService extends android.app.Service {
+ ctor public CallStreamingService();
+ method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
+ method public void onCallStreamingStarted(@NonNull android.telecom.StreamingCall);
+ method public void onCallStreamingStateChanged(int);
+ method public void onCallStreamingStopped();
+ field public static final String SERVICE_INTERFACE = "android.telecom.CallStreamingService";
+ field public static final int STREAMING_FAILED_ALREADY_STREAMING = 1; // 0x1
+ field public static final int STREAMING_FAILED_NO_SENDER = 2; // 0x2
+ field public static final int STREAMING_FAILED_SENDER_BINDING_ERROR = 3; // 0x3
+ field public static final int STREAMING_FAILED_UNKNOWN = 0; // 0x0
+ }
+
public abstract class Conference extends android.telecom.Conferenceable {
method @Deprecated public final android.telecom.AudioState getAudioState();
method @Deprecated public final long getConnectTimeMillis();
@@ -13524,6 +13559,22 @@ package android.telecom {
method @Deprecated public android.content.ComponentName getPackageName();
}
+ public final class StreamingCall implements android.os.Parcelable {
+ ctor public StreamingCall(@NonNull android.content.ComponentName, @NonNull CharSequence, @NonNull android.net.Uri, @NonNull android.os.Bundle);
+ method public int describeContents();
+ method @NonNull public android.net.Uri getAddress();
+ method @NonNull public android.content.ComponentName getComponentName();
+ method @NonNull public CharSequence getDisplayName();
+ method @NonNull public android.os.Bundle getExtras();
+ method public int getState();
+ method public void requestStreamingState(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telecom.StreamingCall> CREATOR;
+ field public static final int STATE_DISCONNECTED = 3; // 0x3
+ field public static final int STATE_HOLDING = 2; // 0x2
+ field public static final int STATE_STREAMING = 1; // 0x1
+ }
+
public final class TelecomAnalytics implements android.os.Parcelable {
ctor public TelecomAnalytics(java.util.List<android.telecom.TelecomAnalytics.SessionTiming>, java.util.List<android.telecom.ParcelableCallAnalytics>);
method public int describeContents();
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index 2c5acf182d51..1c10356c6b03 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -140,6 +140,17 @@ package android.media.tv {
}
+package android.nfc {
+
+ public final class NfcAdapter {
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disableNdefPush();
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
+ method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
+ field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
+ }
+
+}
+
package android.os {
public class Build {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1abdbb9376bf..bea2bfc09741 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -349,9 +349,7 @@ package android.app {
}
public class NotificationManager {
- method public void allowAssistantAdjustment(String);
method public void cleanUpCallersAfter(long);
- method public void disallowAssistantAdjustment(String);
method public android.content.ComponentName getEffectsSuppressor();
method public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String);
method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean, boolean);
@@ -448,6 +446,7 @@ package android.app {
method @Deprecated public boolean grantRuntimePermission(String, String, android.os.UserHandle);
method public boolean injectInputEvent(@NonNull android.view.InputEvent, boolean, boolean);
method public void injectInputEventToInputFilter(@NonNull android.view.InputEvent);
+ method public boolean isNodeInCache(@NonNull android.view.accessibility.AccessibilityNodeInfo);
method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
method public void syncInputTransactions();
method public void syncInputTransactions(boolean);
@@ -513,6 +512,10 @@ package android.app {
package android.app.admin {
+ public final class DeviceAdminAuthority extends android.app.admin.Authority {
+ field @NonNull public static final android.app.admin.DeviceAdminAuthority DEVICE_ADMIN_AUTHORITY;
+ }
+
public class DevicePolicyManager {
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void acknowledgeNewUserDisclaimer();
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void clearOrganizationId();
@@ -593,21 +596,28 @@ package android.app.admin {
field @Deprecated public static final int STATUS_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14; // 0xe
}
+ public final class DpcAuthority extends android.app.admin.Authority {
+ field @NonNull public static final android.app.admin.DpcAuthority DPC_AUTHORITY;
+ }
+
public final class FlagUnion extends android.app.admin.ResolutionMechanism<java.lang.Integer> {
method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.FlagUnion> CREATOR;
+ field @NonNull public static final android.app.admin.FlagUnion FLAG_UNION;
}
public final class MostRecent<V> extends android.app.admin.ResolutionMechanism<V> {
ctor public MostRecent();
method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRecent> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRecent<?>> CREATOR;
+ field @NonNull public static final android.app.admin.MostRecent<?> MOST_RECENT;
}
public final class MostRestrictive<V> extends android.app.admin.ResolutionMechanism<V> {
method public int describeContents();
+ method @NonNull public java.util.List<V> getMostToLeastRestrictiveValues();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.MostRestrictive<?>> CREATOR;
}
@@ -628,14 +638,20 @@ package android.app.admin {
method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.StringSetUnion> CREATOR;
+ field @NonNull public static final android.app.admin.StringSetUnion STRING_SET_UNION;
}
public final class TopPriority<V> extends android.app.admin.ResolutionMechanism<V> {
method public int describeContents();
+ method @NonNull public java.util.List<android.app.admin.Authority> getHighestToLowestPriorityAuthorities();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.TopPriority<?>> CREATOR;
}
+ public final class UnknownAuthority extends android.app.admin.Authority {
+ field @NonNull public static final android.app.admin.UnknownAuthority UNKNOWN_AUTHORITY;
+ }
+
public final class UnsafeStateException extends java.lang.IllegalStateException implements android.os.Parcelable {
ctor public UnsafeStateException(int, int);
method public int getOperation();
@@ -1401,6 +1417,7 @@ package android.hardware.display {
method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void clearGlobalUserPreferredDisplayMode();
method @Nullable public android.view.Display.Mode getGlobalUserPreferredDisplayMode();
method @NonNull public android.hardware.display.HdrConversionMode getHdrConversionMode();
+ method @NonNull public android.hardware.display.HdrConversionMode getHdrConversionModeSetting();
method @NonNull public int[] getSupportedHdrOutputTypes();
method @NonNull public int[] getUserDisabledHdrTypes();
method public boolean isMinimalPostProcessingRequested(int);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f4089167f3d2..42d056c78eba 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3676,6 +3676,123 @@ public class ActivityManager {
}
/**
+ * Return a list of {@link ApplicationStartInfo} records containing the information about the
+ * most recent app startups.
+ *
+ * <p class="note"> Note: System stores this historical information in a ring buffer and only
+ * the most recent records will be returned. </p>
+ *
+ * @param maxNum The maximum number of results to be returned; a value of 0
+ * means to ignore this parameter and return all matching records. If fewer
+ * records exist, all existing records will be returned.
+ *
+ * @return a list of {@link ApplicationStartInfo} records matching the criteria, sorted in
+ * the order from most recent to least recent.
+ */
+ @NonNull
+ public List<ApplicationStartInfo> getHistoricalProcessStartReasons(
+ @IntRange(from = 0) int maxNum) {
+ try {
+ ParceledListSlice<ApplicationStartInfo> startInfos = getService()
+ .getHistoricalProcessStartReasons(null, maxNum, mContext.getUserId());
+ return startInfos == null ? Collections.emptyList() : startInfos.getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return a list of {@link ApplicationStartInfo} records containing the information about the
+ * most recent app startups.
+ *
+ * <p class="note"> Note: System stores this historical information in a ring buffer and only
+ * the most recent records will be returned. </p>
+ *
+ * @param packageName Package name for which app startups to receive.
+ * @param maxNum The maximum number of results to be returned; a value of 0
+ * means to ignore this parameter and return all matching records. If fewer
+ * records exist, all existing records will be returned.
+ *
+ * @return a list of {@link ApplicationStartInfo} records matching the criteria, sorted in
+ * the order from most recent to least recent.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ @RequiresPermission(Manifest.permission.DUMP)
+ public List<ApplicationStartInfo> getExternalHistoricalProcessStartReasons(
+ @NonNull String packageName, @IntRange(from = 0) int maxNum) {
+ try {
+ ParceledListSlice<ApplicationStartInfo> startInfos = getService()
+ .getHistoricalProcessStartReasons(packageName, maxNum, mContext.getUserId());
+ return startInfos == null ? Collections.emptyList() : startInfos.getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Callback to receive {@link ApplicationStartInfo} object once recording of startup related
+ * metrics is complete.
+ * Use with {@link #setApplicationStartInfoCompleteListener}.
+ */
+ public interface ApplicationStartInfoCompleteListener {
+ /** {@link ApplicationStartInfo} is complete, no more info will be added. */
+ void onApplicationStartInfoComplete(@NonNull ApplicationStartInfo applicationStartInfo);
+ }
+
+ /**
+ * Sets a callback to be notified when the {@link ApplicationStartInfo} records of this startup
+ * are complete.
+ *
+ * <p class="note"> Note: callback will not wait for {@link Activity#reportFullyDrawn} to occur.
+ * Timestamp for fully drawn may be added after callback occurs. Set callback after invoking
+ * {@link Activity#reportFullyDrawn} if timestamp for fully drawn is required.</p>
+ *
+ * <p class="note"> Note: if start records have already been retrieved, the callback will be
+ * invoked immediately on the specified executor with the previously resolved AppStartInfo.</p>
+ *
+ * <p class="note"> Note: callback is asynchronous and should be made from a background thread.
+ * </p>
+ *
+ * @param executor The executor on which the listener should be called.
+ * @param listener Callback to be called when collection of {@link ApplicationStartInfo} is
+ * complete. Will replace existing listener if one is already attached.
+ *
+ * @throws IllegalArgumentException if executor or listener are null.
+ */
+ public void setApplicationStartInfoCompleteListener(@NonNull final Executor executor,
+ @NonNull final ApplicationStartInfoCompleteListener listener) {
+ Preconditions.checkNotNull(executor, "executor cannot be null");
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+ IApplicationStartInfoCompleteListener callback =
+ new IApplicationStartInfoCompleteListener.Stub() {
+ @Override
+ public void onApplicationStartInfoComplete(ApplicationStartInfo applicationStartInfo) {
+ executor.execute(() ->
+ listener.onApplicationStartInfoComplete(applicationStartInfo));
+ }
+ };
+ try {
+ getService().setApplicationStartInfoCompleteListener(callback, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Removes the callback set by {@link #setApplicationStartInfoCompleteListener} if there is one.
+ */
+ public void removeApplicationStartInfoCompleteListener() {
+ try {
+ getService().removeApplicationStartInfoCompleteListener(mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return a list of {@link ApplicationExitInfo} records containing the reasons for the most
* recent app deaths.
*
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f78f45244ec5..543c5e700e33 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -151,6 +151,8 @@ import android.provider.BlockedNumberContract;
import android.provider.CalendarContract;
import android.provider.CallLog;
import android.provider.ContactsContract;
+import android.provider.DeviceConfigInitializer;
+import android.provider.DeviceConfigServiceManager;
import android.provider.Downloads;
import android.provider.FontsContract;
import android.provider.Settings;
@@ -8139,8 +8141,11 @@ public final class ActivityThread extends ClientTransactionHandler
MediaFrameworkInitializer.setMediaServiceManager(new MediaServiceManager());
BluetoothFrameworkInitializer.setBluetoothServiceManager(new BluetoothServiceManager());
BluetoothFrameworkInitializer.setBinderCallsStatsInitializer(context -> {
- BinderCallsStats.startForBluetooth(context); });
+ BinderCallsStats.startForBluetooth(context);
+ });
NfcFrameworkInitializer.setNfcServiceManager(new NfcServiceManager());
+
+ DeviceConfigInitializer.setDeviceConfigServiceManager(new DeviceConfigServiceManager());
}
private void purgePendingResources() {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 8263a4e3d81f..8a671be0673b 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1462,9 +1462,17 @@ public class AppOpsManager {
*/
public static final int OP_USE_FULL_SCREEN_INTENT = AppProtoEnums.APP_OP_USE_FULL_SCREEN_INTENT;
+ /**
+ * Prevent an app from being placed into hibernation.
+ *
+ * @hide
+ */
+ public static final int OP_SYSTEM_EXEMPT_FROM_HIBERNATION =
+ AppProtoEnums.APP_OP_SYSTEM_EXEMPT_FROM_HIBERNATION;
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 134;
+ public static final int _NUM_OP = 135;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -2058,6 +2066,15 @@ public class AppOpsManager {
*/
public static final String OPSTR_USE_FULL_SCREEN_INTENT = "android:use_full_screen_intent";
+ /**
+ * Prevent an app from being placed into hibernation.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION =
+ "android:system_exempt_from_hibernation";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -2580,7 +2597,10 @@ public class AppOpsManager {
.setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
new AppOpInfo.Builder(OP_USE_FULL_SCREEN_INTENT, OPSTR_USE_FULL_SCREEN_INTENT,
"USE_FULL_SCREEN_INTENT").setPermission(Manifest.permission.USE_FULL_SCREEN_INTENT)
- .build()
+ .build(),
+ new AppOpInfo.Builder(OP_SYSTEM_EXEMPT_FROM_HIBERNATION,
+ OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION,
+ "SYSTEM_EXEMPT_FROM_HIBERNATION").build()
};
// The number of longs needed to form a full bitmask of app ops
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index e93ce6beba1b..c628ec4cc56c 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -734,7 +734,22 @@ public final class ApplicationExitInfo implements Parcelable {
* guarantees that the format is stable across devices or Android releases.</p>
*/
public @Nullable String getDescription() {
- return mDescription;
+ final StringBuilder sb = new StringBuilder();
+
+ if (mSubReason != SUBREASON_UNKNOWN) {
+ sb.append("[");
+ sb.append(subreasonToString(mSubReason));
+ sb.append("]");
+ }
+
+ if (!TextUtils.isEmpty(mDescription)) {
+ if (sb.length() > 0) {
+ sb.append(" ");
+ }
+ sb.append(mDescription);
+ }
+
+ return sb.toString();
}
/**
diff --git a/core/java/android/app/ApplicationStartInfo.aidl b/core/java/android/app/ApplicationStartInfo.aidl
new file mode 100644
index 000000000000..4322c7e69c45
--- /dev/null
+++ b/core/java/android/app/ApplicationStartInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable ApplicationStartInfo;
diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java
new file mode 100644
index 000000000000..794c55e85678
--- /dev/null
+++ b/core/java/android/app/ApplicationStartInfo.java
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Provide information related to a processes startup. */
+public final class ApplicationStartInfo implements Parcelable {
+
+ /**
+ * State indicating process startup has started. Some information is available in
+ * {@link ApplicationStartInfo} and more will be added.
+ */
+ public static final int STARTUP_STATE_STARTED = 0;
+
+ /**
+ * State indicating process startup has failed. Startup information in
+ * {@link ApplicationStartInfo} is incomplete, but no more will be added.
+ */
+ public static final int STARTUP_STATE_ERROR = 1;
+
+ /**
+ * State indicating process startup has made it to first frame draw. Startup
+ * information in {@link ApplicationStartInfo} is complete with potential exception
+ * of fully drawn timestamp which is not guaranteed to be set.
+ */
+ public static final int STARTUP_STATE_FIRST_FRAME_DRAWN = 2;
+
+ /** Process started due to alarm. */
+ public static final int START_REASON_ALARM = 0;
+
+ /** Process started to run backup. */
+ public static final int START_REASON_BACKUP = 1;
+
+ /** Process started due to boot complete. */
+ public static final int START_REASON_BOOT_COMPLETE = 2;
+
+ /** Process started due to broadcast received. */
+ public static final int START_REASON_BROADCAST = 3;
+
+ /** Process started due to access of ContentProvider */
+ public static final int START_REASON_CONTENT_PROVIDER = 4;
+
+ /** * Process started to run scheduled job. */
+ public static final int START_REASON_JOB = 5;
+
+ /** Process started due to click app icon or widget from launcher. */
+ public static final int START_REASON_LAUNCHER = 6;
+
+ /** Process started not for any of the listed reasons. */
+ public static final int START_REASON_OTHER = 7;
+
+ /** Process started due to push message. */
+ public static final int START_REASON_PUSH = 8;
+
+ /** Process started to resume activity. */
+ public static final int START_REASON_RESUMED_ACTIVITY = 9;
+
+ /** Process service started. */
+ public static final int START_REASON_SERVICE = 10;
+
+ /** Process started due to Activity started for any reason not explicitly listed. */
+ public static final int START_REASON_START_ACTIVITY = 11;
+
+ /** Process started from scratch. */
+ public static final int START_TYPE_COLD = 0;
+
+ /** Process retained minimally SavedInstanceState. */
+ public static final int START_TYPE_WARM = 1;
+
+ /** Process brought back to foreground. */
+ public static final int START_TYPE_HOT = 2;
+
+ /**
+ * Default. The system always creates a new instance of the activity in the target task and
+ * routes the intent to it.
+ */
+ public static final int LAUNCH_MODE_STANDARD = 0;
+
+ /**
+ * If an instance of the activity already exists at the top of the target task, the system
+ * routes the intent to that instance through a call to its onNewIntent() method, rather than
+ * creating a new instance of the activity.
+ */
+ public static final int LAUNCH_MODE_SINGLE_TOP = 1;
+
+ /**
+ * The system creates the activity at the root of a new task or locates the activity on an
+ * existing task with the same affinity. If an instance of the activity already exists and is at
+ * the root of the task, the system routes the intent to existing instance through a call to its
+ * onNewIntent() method, rather than creating a new one.
+ */
+ public static final int LAUNCH_MODE_SINGLE_INSTANCE = 2;
+
+ /**
+ * Same as "singleTask", except that the system doesn't launch any other activities into the
+ * task holding the instance. The activity is always the single and only member of its task.
+ */
+ public static final int LAUNCH_MODE_SINGLE_TASK = 3;
+
+ /**
+ * The activity can only be running as the root activity of the task, the first activity that
+ * created the task, and therefore there will only be one instance of this activity in a task;
+ * but activity can be instantiated multiple times in different tasks.
+ */
+ public static final int LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK = 4;
+
+ /** Clock monotonic timestamp of launch started. */
+ public static final int START_TIMESTAMP_LAUNCH = 0;
+
+ /** Clock monotonic timestamp of finish java classloading. */
+ public static final int START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE = 1;
+
+ /** Clock monotonic timestamp of Application onCreate called. */
+ public static final int START_TIMESTAMP_APPLICATION_ONCREATE = 2;
+
+ /** Clock monotonic timestamp of bindApplication called. */
+ public static final int START_TIMESTAMP_BIND_APPLICATION = 3;
+
+ /** Clock monotonic timestamp of first frame drawn. */
+ public static final int START_TIMESTAMP_FIRST_FRAME = 4;
+
+ /** Clock monotonic timestamp of reportFullyDrawn called by application. */
+ public static final int START_TIMESTAMP_FULLY_DRAWN = 5;
+
+ /**
+ * @see #getStartupState
+ */
+ private @StartupState int mStartupState;
+
+ /**
+ * @see #getPid
+ */
+ private int mPid;
+
+ /**
+ * @see #getRealUid
+ */
+ private int mRealUid;
+
+ /**
+ * @see #getPackageUid
+ */
+ private int mPackageUid;
+
+ /**
+ * @see #getDefiningUid
+ */
+ private int mDefiningUid;
+
+ /**
+ * @see #getProcessName
+ */
+ private String mProcessName;
+
+ /**
+ * @see #getReason
+ */
+ private @StartReason int mReason;
+
+ /**
+ * @see #getStartupTimestamps
+ */
+ private Map<@StartupTimestamp Integer, Long> mStartupTimestampsNs;
+
+ /**
+ * @see #getStartType
+ */
+ private @StartType int mStartType;
+
+ /**
+ * @see #getStartIntent
+ */
+ private Intent mStartIntent;
+
+ /**
+ * @see #getLaunchMode
+ */
+ private @LaunchMode int mLaunchMode;
+
+ /**
+ * @hide *
+ */
+ @IntDef(
+ prefix = {"STARTUP_STATE_"},
+ value = {
+ STARTUP_STATE_STARTED,
+ STARTUP_STATE_ERROR,
+ STARTUP_STATE_FIRST_FRAME_DRAWN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StartupState {}
+
+ /**
+ * @hide *
+ */
+ @IntDef(
+ prefix = {"START_REASON_"},
+ value = {
+ START_REASON_ALARM,
+ START_REASON_BACKUP,
+ START_REASON_BOOT_COMPLETE,
+ START_REASON_BROADCAST,
+ START_REASON_CONTENT_PROVIDER,
+ START_REASON_JOB,
+ START_REASON_LAUNCHER,
+ START_REASON_OTHER,
+ START_REASON_PUSH,
+ START_REASON_RESUMED_ACTIVITY,
+ START_REASON_SERVICE,
+ START_REASON_START_ACTIVITY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StartReason {}
+
+ /**
+ * @hide *
+ */
+ @IntDef(
+ prefix = {"START_TYPE_"},
+ value = {
+ START_TYPE_COLD,
+ START_TYPE_WARM,
+ START_TYPE_HOT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StartType {}
+
+ /**
+ * @hide *
+ */
+ @IntDef(
+ prefix = {"LAUNCH_MODE_"},
+ value = {
+ LAUNCH_MODE_STANDARD,
+ LAUNCH_MODE_SINGLE_TOP,
+ LAUNCH_MODE_SINGLE_INSTANCE,
+ LAUNCH_MODE_SINGLE_TASK,
+ LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LaunchMode {}
+
+ /**
+ * @hide *
+ */
+ @IntDef(
+ prefix = {"START_TIMESTAMP_"},
+ value = {
+ START_TIMESTAMP_LAUNCH,
+ START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE,
+ START_TIMESTAMP_APPLICATION_ONCREATE,
+ START_TIMESTAMP_BIND_APPLICATION,
+ START_TIMESTAMP_FULLY_DRAWN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ public @interface StartupTimestamp {}
+
+ /**
+ * @see #getStartupState
+ * @hide
+ */
+ public void setStartupState(final @StartupState int startupState) {
+ mStartupState = startupState;
+ }
+
+ /**
+ * @see #getPid
+ * @hide
+ */
+ public void setPid(final int pid) {
+ mPid = pid;
+ }
+
+ /**
+ * @see #getRealUid
+ * @hide
+ */
+ public void setRealUid(final int uid) {
+ mRealUid = uid;
+ }
+
+ /**
+ * @see #getPackageUid
+ * @hide
+ */
+ public void setPackageUid(final int uid) {
+ mPackageUid = uid;
+ }
+
+ /**
+ * @see #getDefiningUid
+ * @hide
+ */
+ public void setDefiningUid(final int uid) {
+ mDefiningUid = uid;
+ }
+
+ /**
+ * @see #getProcessName
+ * @hide
+ */
+ public void setProcessName(final String processName) {
+ mProcessName = intern(processName);
+ }
+
+ /**
+ * @see #getReason
+ * @hide
+ */
+ public void setReason(@StartReason int reason) {
+ mReason = reason;
+ }
+
+ /**
+ * @see #getStartupTimestamps
+ * @hide
+ */
+ public void addStartupTimestamp(@StartupTimestamp int key, long timestampNs) {
+ if (mStartupTimestampsNs == null) {
+ mStartupTimestampsNs = new HashMap<@StartupTimestamp Integer, Long>();
+ }
+ mStartupTimestampsNs.put(key, timestampNs);
+ }
+
+ /**
+ * @see #getStartType
+ * @hide
+ */
+ public void setStartType(@StartType int startType) {
+ mStartType = startType;
+ }
+
+ /**
+ * @see #getStartIntent
+ * @hide
+ */
+ public void setIntent(Intent startIntent) {
+ mStartIntent = startIntent;
+ }
+
+ /**
+ * @see #getLaunchMode
+ * @hide
+ */
+ public void setLaunchMode(@LaunchMode int launchMode) {
+ mLaunchMode = launchMode;
+ }
+
+ /**
+ * Current state of startup.
+ *
+ * Can be used to determine whether the object will have additional fields added as it may be
+ * queried before all data is collected.
+ *
+ * <p class="note"> Note: field will always be set and available.</p>
+ */
+ public @StartupState int getStartupState() {
+ return mStartupState;
+ }
+
+ /**
+ * The process id.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public int getPid() {
+ return mPid;
+ }
+
+ /**
+ * The kernel user identifier of the process, most of the time the system uses this to do access
+ * control checks. It's typically the uid of the package where the component is running from,
+ * except the case of isolated process, where this field identifies the kernel user identifier
+ * that this process is actually running with, while the {@link #getPackageUid} identifies the
+ * kernel user identifier that is assigned at the package installation time.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public int getRealUid() {
+ return mRealUid;
+ }
+
+ /**
+ * Similar to {@link #getRealUid}, it's the kernel user identifier that is assigned at the
+ * package installation time.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public int getPackageUid() {
+ return mPackageUid;
+ }
+
+ /**
+ * Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
+ * {@link #getPackageUid}, if an external service has the {@link
+ * android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set to <code>
+ * true</code> and was bound with the flag {@link android.content.Context#BIND_EXTERNAL_SERVICE}
+ * - in this case, this field here will be the kernel user identifier of the external service
+ * provider.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public int getDefiningUid() {
+ return mDefiningUid;
+ }
+
+ /**
+ * The actual process name it was running with.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public @NonNull String getProcessName() {
+ return mProcessName;
+ }
+
+ /**
+ * The reason code of what triggered the process's start.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public @StartReason int getReason() {
+ return mReason;
+ }
+
+ /**
+ * Various clock monotonic timestamps in nanoseconds throughout the startup process.
+ *
+ * <p class="note"> Note: different timestamps will be available for different values of
+ * {@link #getStartupState}:
+ *
+ * (Subsequent rows contain all timestamps of proceding states.)
+ *
+ * For {@link #STARTUP_STATE_STARTED}, timestamp {@link #START_TIMESTAMP_LAUNCH} will be
+ * available.
+ * For {@link #STARTUP_STATE_ERROR}, no additional timestamps are guaranteed available.
+ * For {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}, timestamps
+ * {@link #START_TIMESTAMP_JAVA_CLASSLOADING_COMPLETE}, {@link #START_TIMESTAMP_APPLICATION_ONCREATE},
+ * {@link #START_TIMESTAMP_BIND_APPLICATION}, and {@link #START_TIMESTAMP_FIRST_FRAME} will
+ * additionally be available.
+ *
+ * Timestamp {@link #START_TIMESTAMP_FULLY_DRAWN} is never guaranteed to be available as it is
+ * dependant on devloper calling {@link Activity#reportFullyDrawn}.
+ * </p>
+ */
+ public @NonNull Map<@StartupTimestamp Integer, Long> getStartupTimestamps() {
+ if (mStartupTimestampsNs == null) {
+ mStartupTimestampsNs = new HashMap<@StartupTimestamp Integer, Long>();
+ }
+ return mStartupTimestampsNs;
+ }
+
+ /**
+ * The state of the app at startup.
+ *
+ * <p class="note"> Note: field will be set for {@link #getStartupState} value
+ * {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}. Not guaranteed for other states.</p>
+ */
+ public @StartType int getStartType() {
+ return mStartType;
+ }
+
+ /**
+ * The intent used to launch the application.
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ @SuppressLint("IntentBuilderName")
+ @Nullable
+ public Intent getIntent() {
+ return mStartIntent;
+ }
+
+ /**
+ * An instruction on how the activity should be launched. There are five modes that work in
+ * conjunction with activity flags in Intent objects to determine what should happen when the
+ * activity is called upon to handle an intent.
+ *
+ * Modes:
+ * {@link #LAUNCH_MODE_STANDARD}
+ * {@link #LAUNCH_MODE_SINGLE_TOP}
+ * {@link #LAUNCH_MODE_SINGLE_INSTANCE}
+ * {@link #LAUNCH_MODE_SINGLE_TASK}
+ * {@link #LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK}
+ *
+ * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
+ */
+ public @LaunchMode int getLaunchMode() {
+ return mLaunchMode;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mStartupState);
+ dest.writeInt(mPid);
+ dest.writeInt(mRealUid);
+ dest.writeInt(mPackageUid);
+ dest.writeInt(mDefiningUid);
+ dest.writeString(mProcessName);
+ dest.writeInt(mReason);
+ dest.writeInt(mStartupTimestampsNs.size());
+ for (@StartupTimestamp int key : mStartupTimestampsNs.keySet()) {
+ dest.writeInt(key);
+ dest.writeLong(mStartupTimestampsNs.get(key));
+ }
+ dest.writeInt(mStartType);
+ dest.writeParcelable(mStartIntent, flags);
+ dest.writeInt(mLaunchMode);
+ }
+
+ /** @hide */
+ public ApplicationStartInfo() {}
+
+ /** @hide */
+ public ApplicationStartInfo(ApplicationStartInfo other) {
+ mStartupState = other.mStartupState;
+ mPid = other.mPid;
+ mRealUid = other.mRealUid;
+ mPackageUid = other.mPackageUid;
+ mDefiningUid = other.mDefiningUid;
+ mProcessName = other.mProcessName;
+ mReason = other.mReason;
+ mStartupTimestampsNs = other.mStartupTimestampsNs;
+ mStartType = other.mStartType;
+ mStartIntent = other.mStartIntent;
+ mLaunchMode = other.mLaunchMode;
+ }
+
+ private ApplicationStartInfo(@NonNull Parcel in) {
+ mStartupState = in.readInt();
+ mPid = in.readInt();
+ mRealUid = in.readInt();
+ mPackageUid = in.readInt();
+ mDefiningUid = in.readInt();
+ mProcessName = intern(in.readString());
+ mReason = in.readInt();
+ int starupTimestampCount = in.readInt();
+ for (int i = 0; i < starupTimestampCount; i++) {
+ int key = in.readInt();
+ long val = in.readLong();
+ addStartupTimestamp(key, val);
+ }
+ mStartType = in.readInt();
+ mStartIntent =
+ in.readParcelable(Intent.class.getClassLoader(), android.content.Intent.class);
+ mLaunchMode = in.readInt();
+ }
+
+ private static String intern(@Nullable String source) {
+ return source != null ? source.intern() : null;
+ }
+
+ public @NonNull static final Creator<ApplicationStartInfo> CREATOR =
+ new Creator<ApplicationStartInfo>() {
+ @Override
+ public ApplicationStartInfo createFromParcel(Parcel in) {
+ return new ApplicationStartInfo(in);
+ }
+
+ @Override
+ public ApplicationStartInfo[] newArray(int size) {
+ return new ApplicationStartInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index c5c3d3090f12..a2c4820d5fcb 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -19,10 +19,12 @@ package android.app;
import android.app.ActivityManager;
import android.app.ActivityManager.PendingIntentInfo;
import android.app.ActivityTaskManager;
+import android.app.ApplicationStartInfo;
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
import android.app.ContentProviderHolder;
import android.app.GrantedUriPermission;
+import android.app.IApplicationStartInfoCompleteListener;
import android.app.IApplicationThread;
import android.app.IActivityController;
import android.app.IAppTask;
@@ -634,6 +636,45 @@ interface IActivityManager {
void appNotResponding(String reason);
/**
+ * Return a list of {@link ApplicationStartInfo} records.
+ *
+ * <p class="note"> Note: System stores historical information in a ring buffer, older
+ * records would be overwritten by newer records. </p>
+ *
+ * @param packageName Optional, an empty value means match all packages belonging to the
+ * caller's UID. If this package belongs to another UID, you must hold
+ * {@link android.Manifest.permission#DUMP} in order to retrieve it.
+ * @param maxNum Optional, the maximum number of results should be returned; A value of 0
+ * means to ignore this parameter and return all matching records
+ * @param userId The userId in the multi-user environment.
+ *
+ * @return a list of {@link ApplicationStartInfo} records with the matching criteria, sorted in
+ * the order from most recent to least recent.
+ */
+ ParceledListSlice<ApplicationStartInfo> getHistoricalProcessStartReasons(String packageName,
+ int maxNum, int userId);
+
+
+ /**
+ * Sets a callback for {@link ApplicationStartInfo} upon completion of collecting startup data.
+ *
+ * <p class="note"> Note: completion of startup is no guaranteed and as such this callback may not occur.</p>
+ *
+ * @param listener A listener to for the callback upon completion of startup data collection.
+ * @param userId The userId in the multi-user environment.
+ */
+ void setApplicationStartInfoCompleteListener(IApplicationStartInfoCompleteListener listener,
+ int userId);
+
+
+ /**
+ * Removes callback for {@link ApplicationStartInfo} upon completion of collecting startup data.
+ *
+ * @param userId The userId in the multi-user environment.
+ */
+ void removeApplicationStartInfoCompleteListener(int userId);
+
+ /**
* Return a list of {@link ApplicationExitInfo} records.
*
* <p class="note"> Note: System stores these historical information in a ring buffer, older
diff --git a/core/java/android/app/IApplicationStartInfoCompleteListener.aidl b/core/java/android/app/IApplicationStartInfoCompleteListener.aidl
new file mode 100644
index 000000000000..0f0d9198234f
--- /dev/null
+++ b/core/java/android/app/IApplicationStartInfoCompleteListener.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.app.ApplicationStartInfo;
+
+/**
+ * Notify the client when compilation of app start info is complete.
+ * Will not be called in case of an error that disrupts startup.
+ * @param applicationStartInfo the completed ApplicationStartInfo object.
+ *
+ * @hide
+ */
+interface IApplicationStartInfoCompleteListener {
+ void onApplicationStartInfoComplete(in ApplicationStartInfo applicationStartInfo);
+}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 302d1469e1fb..ab32f4d21237 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -80,8 +80,6 @@ interface INotificationManager
boolean isImportanceLocked(String pkg, int uid);
List<String> getAllowedAssistantAdjustments(String pkg);
- void allowAssistantAdjustment(String adjustmentType);
- void disallowAssistantAdjustment(String adjustmentType);
boolean shouldHideSilentStatusIcons(String callingPkg);
void setHideSilentStatusIcons(boolean hide);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9974e292a322..7ab65b186d40 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4624,16 +4624,15 @@ public class Notification implements Parcelable
/**
* Set whether this is an "ongoing" notification.
*
-
- * Ongoing notifications cannot be dismissed by the user, so your application or service
- * must take care of canceling them.
+ * Ongoing notifications cannot be dismissed by the user on locked devices, or by
+ * notification listeners, and some notifications cannnot be dismissed on unlocked
+ * devices (system, device management, media), so your application or service must take
+ * care of canceling them.
*
-
* They are typically used to indicate a background task that the user is actively engaged
* with (e.g., playing music) or is pending in some way and therefore occupying the device
* (e.g., a file download, sync operation, active network connection).
*
-
* @see Notification#FLAG_ONGOING_EVENT
*/
@NonNull
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 4e94a1dcf642..82adaaf70bcb 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1577,32 +1577,6 @@ public class NotificationManager {
}
}
- /**
- * @hide
- */
- @TestApi
- public void allowAssistantAdjustment(String capability) {
- INotificationManager service = getService();
- try {
- service.allowAssistantAdjustment(capability);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- */
- @TestApi
- public void disallowAssistantAdjustment(String capability) {
- INotificationManager service = getService();
- try {
- service.disallowAssistantAdjustment(capability);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
/** @hide */
@TestApi
public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String pkg) {
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 824c7ccd7de1..e72b14115b18 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -4,7 +4,7 @@ per-file ContextImpl.java = *
# ActivityManager
per-file ActivityManager* = file:/services/core/java/com/android/server/am/OWNERS
-per-file ApplicationStartInfo* = file:/services/core/java/com/android/server/am/OWNERS
+per-file *ApplicationStartInfo* = file:/services/core/java/com/android/server/am/OWNERS
per-file ApplicationErrorReport* = file:/services/core/java/com/android/server/am/OWNERS
per-file ApplicationExitInfo* = file:/services/core/java/com/android/server/am/OWNERS
per-file Application.java = file:/services/core/java/com/android/server/am/OWNERS
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 64538ec132de..6d80a44d3d60 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1570,7 +1570,7 @@ public final class SystemServiceRegistry {
new CachedServiceFetcher<SharedConnectivityManager>() {
@Override
public SharedConnectivityManager createService(ContextImpl ctx) {
- return new SharedConnectivityManager(ctx);
+ return SharedConnectivityManager.create(ctx);
}
});
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index f133c8aa5899..0bdc222f323c 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -218,6 +218,23 @@
"file_patterns": [
"(/|^)GameManager[^/]*", "(/|^)GameMode[^/]*"
]
+ },
+ {
+ "name": "HdmiCecTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.hardware.hdmi"
+ }
+ ],
+ "file_patterns": [
+ "(/|^)DeviceFeature[^/]*", "(/|^)Hdmi[^/]*"
+ ]
}
],
"presubmit-large": [
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 249937a72d74..b3b1cf82b85a 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -17,6 +17,7 @@
package android.app;
import android.accessibilityservice.AccessibilityGestureEvent;
+import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityService.Callbacks;
import android.accessibilityservice.AccessibilityService.IAccessibilityServiceClientWrapper;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -58,6 +59,7 @@ import android.view.ViewRootImpl;
import android.view.Window;
import android.view.WindowAnimationFrameStats;
import android.view.WindowContentFrameStats;
+import android.view.accessibility.AccessibilityCache;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -465,6 +467,48 @@ public final class UiAutomation {
}
/**
+ * Clears the accessibility cache.
+ *
+ * @return {@code true} if the cache was cleared
+ * @see AccessibilityService#clearCache()
+ */
+ public boolean clearCache() {
+ final int connectionId;
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ connectionId = mConnectionId;
+ }
+ final AccessibilityCache cache = AccessibilityInteractionClient.getCache(connectionId);
+ if (cache == null) {
+ return false;
+ }
+ cache.clear();
+ return true;
+ }
+
+ /**
+ * Checks if {@code node} is in the accessibility cache.
+ *
+ * @param node the node to check.
+ * @return {@code true} if {@code node} is in the cache.
+ * @hide
+ * @see AccessibilityService#isNodeInCache(AccessibilityNodeInfo)
+ */
+ @TestApi
+ public boolean isNodeInCache(@NonNull AccessibilityNodeInfo node) {
+ final int connectionId;
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ connectionId = mConnectionId;
+ }
+ final AccessibilityCache cache = AccessibilityInteractionClient.getCache(connectionId);
+ if (cache == null) {
+ return false;
+ }
+ return cache.isNodeInCache(node);
+ }
+
+ /**
* Adopt the permission identity of the shell UID for all permissions. This allows
* you to call APIs protected permissions which normal apps cannot hold but are
* granted to the shell UID. If you already adopted all shell permissions by calling
diff --git a/core/java/android/app/admin/AccountTypePolicyKey.java b/core/java/android/app/admin/AccountTypePolicyKey.java
new file mode 100644
index 000000000000..14494d7a9a37
--- /dev/null
+++ b/core/java/android/app/admin/AccountTypePolicyKey.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_ACCOUNT_TYPE;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_BUNDLE_KEY;
+import static android.app.admin.PolicyUpdatesReceiver.EXTRA_POLICY_KEY;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Class used to identify a policy that relates to a certain account type
+ * (e.g. {@link DevicePolicyManager#setAccountManagementDisabled}).
+ *
+ * @hide
+ */
+@SystemApi
+public final class AccountTypePolicyKey extends PolicyKey {
+ private static final String ATTR_ACCOUNT_TYPE = "account-type";
+
+ private final String mAccountType;
+
+ /**
+ * @hide
+ */
+ public AccountTypePolicyKey(@NonNull String key, @NonNull String accountType) {
+ super(key);
+ mAccountType = Objects.requireNonNull((accountType));
+ }
+
+ private AccountTypePolicyKey(Parcel source) {
+ super(source.readString());
+ mAccountType = source.readString();
+ }
+
+ /**
+ * @hide
+ */
+ public AccountTypePolicyKey(String key) {
+ super(key);
+ mAccountType = null;
+ }
+
+ /**
+ * Returns the account type this policy relates to.
+ */
+ @NonNull
+ public String getAccountType() {
+ return mAccountType;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void saveToXml(TypedXmlSerializer serializer) throws IOException {
+ serializer.attribute(/* namespace= */ null, ATTR_POLICY_IDENTIFIER, getIdentifier());
+ serializer.attribute(/* namespace= */ null, ATTR_ACCOUNT_TYPE, mAccountType);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public AccountTypePolicyKey readFromXml(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String policyKey = parser.getAttributeValue(/* namespace= */ null,
+ ATTR_POLICY_IDENTIFIER);
+ String accountType = parser.getAttributeValue(/* namespace= */ null, ATTR_ACCOUNT_TYPE);
+ return new AccountTypePolicyKey(policyKey, accountType);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void writeToBundle(Bundle bundle) {
+ bundle.putString(EXTRA_POLICY_KEY, getIdentifier());
+ Bundle extraPolicyParams = new Bundle();
+ extraPolicyParams.putString(EXTRA_ACCOUNT_TYPE, mAccountType);
+ bundle.putBundle(EXTRA_POLICY_BUNDLE_KEY, extraPolicyParams);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ AccountTypePolicyKey other = (AccountTypePolicyKey) o;
+ return Objects.equals(getIdentifier(), other.getIdentifier())
+ && Objects.equals(mAccountType, other.mAccountType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getIdentifier(), mAccountType);
+ }
+
+ @Override
+ public String toString() {
+ return "AccountTypePolicyKey{mPolicyKey= " + getIdentifier()
+ + "; mAccountType= " + mAccountType + "}";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString(getIdentifier());
+ dest.writeString(mAccountType);
+ }
+
+ @NonNull
+ public static final Creator<AccountTypePolicyKey> CREATOR =
+ new Creator<AccountTypePolicyKey>() {
+ @Override
+ public AccountTypePolicyKey createFromParcel(Parcel source) {
+ return new AccountTypePolicyKey(source);
+ }
+
+ @Override
+ public AccountTypePolicyKey[] newArray(int size) {
+ return new AccountTypePolicyKey[size];
+ }
+ };
+}
diff --git a/core/java/android/app/admin/DeviceAdminAuthority.java b/core/java/android/app/admin/DeviceAdminAuthority.java
index 5d1ff1104b06..d363147b7579 100644
--- a/core/java/android/app/admin/DeviceAdminAuthority.java
+++ b/core/java/android/app/admin/DeviceAdminAuthority.java
@@ -19,6 +19,7 @@ package android.app.admin;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
/**
@@ -31,11 +32,18 @@ import android.os.Parcel;
public final class DeviceAdminAuthority extends Authority {
/**
+ * Object representing a device admin authority.
+ *
* @hide
*/
+ @TestApi
+ @NonNull
public static final DeviceAdminAuthority DEVICE_ADMIN_AUTHORITY = new DeviceAdminAuthority();
- private DeviceAdminAuthority() {}
+ /**
+ * Creates an authority that represents a device admin.
+ */
+ public DeviceAdminAuthority() {}
@Override
public String toString() {
@@ -44,12 +52,13 @@ public final class DeviceAdminAuthority extends Authority {
@Override
public boolean equals(@Nullable Object o) {
- return super.equals(o);
+ if (this == o) return true;
+ return o != null && getClass() == o.getClass();
}
@Override
public int hashCode() {
- return super.hashCode();
+ return 0;
}
@Override
@@ -65,7 +74,7 @@ public final class DeviceAdminAuthority extends Authority {
new Creator<DeviceAdminAuthority>() {
@Override
public DeviceAdminAuthority createFromParcel(Parcel source) {
- return new DeviceAdminAuthority();
+ return DEVICE_ADMIN_AUTHORITY;
}
@Override
diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java
new file mode 100644
index 000000000000..f6b070a4aaa2
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import android.annotation.NonNull;
+import android.os.UserManager;
+
+import java.util.Objects;
+
+/**
+ * Class containing identifiers for policy APIs in {@link DevicePolicyManager}, for example they
+ * will be passed in {@link PolicyUpdatesReceiver#onPolicySetResult} and
+ * {@link PolicyUpdatesReceiver#onPolicyChanged} to communicate updates of a certain policy back
+ * to the admin.
+ */
+public final class DevicePolicyIdentifiers {
+
+ private DevicePolicyIdentifiers() {}
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setAutoTimeZoneEnabled}.
+ */
+ public static final String AUTO_TIMEZONE_POLICY = "autoTimezone";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setPermissionGrantState}.
+ */
+ public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setLockTaskPackages}.
+ */
+ public static final String LOCK_TASK_POLICY = "lockTask";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setUserControlDisabledPackages}.
+ */
+ public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY =
+ "userControlDisabledPackages";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#addPersistentPreferredActivity}.
+ */
+ public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY =
+ "persistentPreferredActivity";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setUninstallBlocked}.
+ */
+ public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setApplicationRestrictions}.
+ */
+ public static final String APPLICATION_RESTRICTIONS_POLICY = "applicationRestrictions";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setResetPasswordToken}.
+ */
+ public static final String RESET_PASSWORD_TOKEN_POLICY = "resetPasswordToken";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setAccountManagementDisabled}.
+ */
+ public static final String ACCOUNT_MANAGEMENT_DISABLED_POLICY = "accountManagementDisabled";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setApplicationHidden}.
+ */
+ public static final String APPLICATION_HIDDEN_POLICY = "applicationHidden";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setCameraDisabled}.
+ */
+ public static final String CAMERA_DISABLED_POLICY = "cameraDisabled";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setStatusBarDisabled}.
+ */
+ public static final String STATUS_BAR_DISABLED_POLICY = "statusBarDisabled";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setPackagesSuspended}.
+ */
+ public static final String PACKAGES_SUSPENDED_POLICY = "packagesSuspended";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setKeyguardDisabledFeatures}.
+ */
+ public static final String KEYGUARD_DISABLED_FEATURES_POLICY = "keyguardDisabledFeatures";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setAutoTimeEnabled}.
+ */
+ public static final String AUTO_TIME_POLICY = "autoTime";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setBackupServiceEnabled}.
+ */
+ public static final String BACKUP_SERVICE_POLICY = "backupService";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setPermittedInputMethods}.
+ *
+ * @hide
+ */
+ public static final String PERMITTED_INPUT_METHODS_POLICY = "permittedInputMethods";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setPersonalAppsSuspended}.
+ *
+ * @hide
+ */
+ public static final String PERSONAL_APPS_SUSPENDED_POLICY = "personalAppsSuspended";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setScreenCaptureDisabled}.
+ *
+ * @hide
+ */
+ public static final String SCREEN_CAPTURE_DISABLED_POLICY = "screenCaptureDisabled";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#setTrustAgentConfiguration}.
+ *
+ * @hide
+ */
+ public static final String TRUST_AGENT_CONFIGURATION_POLICY = "trustAgentConfiguration";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#addCrossProfileIntentFilter}.
+ *
+ * @hide
+ */
+ public static final String CROSS_PROFILE_INTENT_FILTER_POLICY = "crossProfileIntentFilter";
+
+ /**
+ * String identifier for {@link DevicePolicyManager#addCrossProfileWidgetProvider}.
+ *
+ * @hide
+ */
+ public static final String CROSS_PROFILE_WIDGET_PROVIDER_POLICY = "crossProfileWidgetProvider";
+
+ /**
+ * @hide
+ */
+ public static final String USER_RESTRICTION_PREFIX = "userRestriction_";
+
+ /**
+ * Returns a string identifier for the provided user restrictions, see
+ * {@link DevicePolicyManager#addUserRestriction} and {@link UserManager} for the list of
+ * available restrictions.
+ */
+ @NonNull
+ public static String getIdentifierForUserRestriction(
+ @UserManager.UserRestrictionKey @NonNull String restriction) {
+ Objects.requireNonNull(restriction);
+ return USER_RESTRICTION_PREFIX + restriction;
+ }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e7f6990fb495..e84acc7906d5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -18,6 +18,7 @@ package android.app.admin;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY;
import static android.Manifest.permission.QUERY_ADMIN_POLICY;
import static android.Manifest.permission.SET_TIME;
@@ -3896,6 +3897,14 @@ public class DevicePolicyManager {
public static final int EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION = 2;
/**
+ * Prevent an app from entering hibernation.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EXEMPT_FROM_HIBERNATION = 3;
+
+ /**
* Exemptions to platform restrictions, given to an application through
* {@link #setApplicationExemptions(String, Set)}.
*
@@ -3904,7 +3913,8 @@ public class DevicePolicyManager {
@IntDef(prefix = { "EXEMPT_FROM_"}, value = {
EXEMPT_FROM_APP_STANDBY,
EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS,
- EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION
+ EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
+ EXEMPT_FROM_HIBERNATION
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationExemptionConstants {}
@@ -4020,52 +4030,6 @@ public class DevicePolicyManager {
return MTE_NOT_CONTROLLED_BY_POLICY;
}
- // TODO: Expose this as SystemAPI once we add the query API
- /**
- * @hide
- */
- public static final String AUTO_TIMEZONE_POLICY = "autoTimezone";
-
- // TODO: Expose this as SystemAPI once we add the query API
- /**
- * @hide
- */
- public static final String PERMISSION_GRANT_POLICY = "permissionGrant";
-
-
- // TODO: Expose this as SystemAPI once we add the query API
- /**
- * @hide
- */
- public static final String LOCK_TASK_POLICY = "lockTask";
-
- // TODO: Expose this as SystemAPI once we add the query API
- /**
- * @hide
- */
- public static final String USER_CONTROL_DISABLED_PACKAGES_POLICY =
- "userControlDisabledPackages";
-
-
- // TODO: Expose this as SystemAPI once we add the query API
- /**
- * @hide
- */
- public static final String PERSISTENT_PREFERRED_ACTIVITY_POLICY =
- "persistentPreferredActivity";
-
- // TODO: Expose this as SystemAPI once we add the query API
- /**
- * @hide
- */
- public static final String PACKAGE_UNINSTALL_BLOCKED_POLICY = "packageUninstallBlocked";
-
- // TODO: Expose this as SystemAPI once we add the query API
- /**
- * @hide
- */
- public static final String APPLICATION_RESTRICTIONS_POLICY = "applicationRestrictions";
-
/**
* This object is a single place to tack on invalidation and disable calls. All
* binder caches in this class derive from this Config, so all can be invalidated or
@@ -6885,6 +6849,11 @@ public class DevicePolicyManager {
public static final int KEYGUARD_DISABLE_IRIS = 1 << 8;
/**
+ * Disable all keyguard shortcuts.
+ */
+ public static final int KEYGUARD_DISABLE_SHORTCUTS_ALL = 1 << 9;
+
+ /**
* NOTE: Please remember to update the DevicePolicyManagerTest's testKeyguardDisabledFeatures
* CTS test when adding to the list above.
*/
@@ -6927,7 +6896,8 @@ public class DevicePolicyManager {
*/
public static final int ORG_OWNED_PROFILE_KEYGUARD_FEATURES_PARENT_ONLY =
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA
- | DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
+ | DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS
+ | DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL;
/**
* Keyguard features that when set on a normal or organization-owned managed profile, have
@@ -8265,15 +8235,18 @@ public class DevicePolicyManager {
* legacy device admins targeting SDK version {@link android.os.Build.VERSION_CODES#P} or
* below will be silently ignored.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with or null if
+ the caller is not a device admin
* @param disabled Whether or not the camera should be disabled.
* @throws SecurityException if {@code admin} is not an active administrator or does not use
* {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}.
*/
- public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) {
+ @RequiresPermission(value = MANAGE_DEVICE_POLICY_CAMERA, conditional = true)
+ public void setCameraDisabled(@Nullable ComponentName admin, boolean disabled) {
if (mService != null) {
try {
- mService.setCameraDisabled(admin, disabled, mParentInstance);
+ mService.setCameraDisabled(admin, mContext.getPackageName(), disabled,
+ mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8744,7 +8717,8 @@ public class DevicePolicyManager {
* {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS},
* {@link #KEYGUARD_DISABLE_FINGERPRINT},
* {@link #KEYGUARD_DISABLE_FACE},
- * {@link #KEYGUARD_DISABLE_IRIS}.
+ * {@link #KEYGUARD_DISABLE_IRIS},
+ * {@link #KEYGUARD_DISABLE_SHORTCUTS_ALL}.
* @throws SecurityException if {@code admin} is not an active administrator or does not user
* {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES}
*/
@@ -12571,6 +12545,33 @@ public class DevicePolicyManager {
}
/**
+ * Returns whether the status bar is disabled/enabled, see {@link #setStatusBarDisabled}.
+ *
+ * <p>Callable by device owner or profile owner of secondary users that is affiliated with the
+ * device owner.
+ *
+ * <p>This policy has no effect in LockTask mode. The behavior of the
+ * status bar in LockTask mode can be configured with
+ * {@link #setLockTaskFeatures(ComponentName, int)}.
+ *
+ * <p>This policy also does not have any effect while on the lock screen, where the status bar
+ * will not be disabled.
+ *
+ * @throws SecurityException if the caller is not the device owner, or a profile owner of
+ * secondary user that is affiliated with the device.
+ * @see #isAffiliatedUser
+ * @see #getSecondaryUsers
+ */
+ public boolean isStatusBarDisabled() {
+ throwIfParentInstance("isStatusBarDisabled");
+ try {
+ return mService.isStatusBarDisabled(mContext.getPackageName());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Called by the system update service to notify device and profile owners of pending system
* updates.
*
diff --git a/core/java/android/app/admin/DevicePolicyState.java b/core/java/android/app/admin/DevicePolicyState.java
index ee33b00312d5..6de51501d59a 100644
--- a/core/java/android/app/admin/DevicePolicyState.java
+++ b/core/java/android/app/admin/DevicePolicyState.java
@@ -82,6 +82,11 @@ public final class DevicePolicyState implements Parcelable {
}
@Override
+ public String toString() {
+ return "DevicePolicyState { mPolicies= " + mPolicies + " }";
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/app/admin/DpcAuthority.java b/core/java/android/app/admin/DpcAuthority.java
index 72c16bc2c52c..cd9da9a304f2 100644
--- a/core/java/android/app/admin/DpcAuthority.java
+++ b/core/java/android/app/admin/DpcAuthority.java
@@ -19,6 +19,7 @@ package android.app.admin;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
/**
@@ -31,11 +32,18 @@ import android.os.Parcel;
public final class DpcAuthority extends Authority {
/**
+ * Object representing a DPC authority.
+ *
* @hide
*/
+ @NonNull
+ @TestApi
public static final DpcAuthority DPC_AUTHORITY = new DpcAuthority();
- private DpcAuthority() {}
+ /**
+ * Creates an authority that represents a DPC admin.
+ */
+ public DpcAuthority() {}
@Override
public String toString() {
@@ -44,12 +52,13 @@ public final class DpcAuthority extends Authority {
@Override
public boolean equals(@Nullable Object o) {
- return super.equals(o);
+ if (this == o) return true;
+ return o != null && getClass() == o.getClass();
}
@Override
public int hashCode() {
- return super.hashCode();
+ return 0;
}
@Override
@@ -65,7 +74,7 @@ public final class DpcAuthority extends Authority {
new Creator<DpcAuthority>() {
@Override
public DpcAuthority createFromParcel(Parcel source) {
- return new DpcAuthority();
+ return DPC_AUTHORITY;
}
@Override
diff --git a/core/java/android/app/admin/EnforcingAdmin.java b/core/java/android/app/admin/EnforcingAdmin.java
index 178646739c5e..771794dbe0fb 100644
--- a/core/java/android/app/admin/EnforcingAdmin.java
+++ b/core/java/android/app/admin/EnforcingAdmin.java
@@ -38,7 +38,7 @@ public final class EnforcingAdmin implements Parcelable {
private final UserHandle mUserHandle;
/**
- * @hide
+ * Creates an enforcing admin with the given params.
*/
public EnforcingAdmin(
@NonNull String packageName, @NonNull Authority authority,
diff --git a/core/java/android/app/admin/FlagUnion.java b/core/java/android/app/admin/FlagUnion.java
index be924d886d04..599373fda136 100644
--- a/core/java/android/app/admin/FlagUnion.java
+++ b/core/java/android/app/admin/FlagUnion.java
@@ -22,8 +22,6 @@ import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Objects;
-
/**
* Class to identify a union resolution mechanism for flag policies, it's used to resolve the
* enforced policy when being set by multiple admins (see
@@ -35,8 +33,10 @@ import java.util.Objects;
public final class FlagUnion extends ResolutionMechanism<Integer> {
/**
- * @hide
+ * Union resolution for policies represented as int flags which resolves as the union of all
+ * flags.
*/
+ @NonNull
public static final FlagUnion FLAG_UNION = new FlagUnion();
private FlagUnion(){};
@@ -49,7 +49,7 @@ public final class FlagUnion extends ResolutionMechanism<Integer> {
@Override
public int hashCode() {
- return Objects.hash(this);
+ return 0;
}
@Override
@@ -70,7 +70,7 @@ public final class FlagUnion extends ResolutionMechanism<Integer> {
new Parcelable.Creator<FlagUnion>() {
@Override
public FlagUnion createFromParcel(Parcel source) {
- return new FlagUnion();
+ return FLAG_UNION;
}
@Override
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c86852a9c615..3f66b45b99bf 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -141,7 +141,7 @@ interface IDevicePolicyManager {
boolean requestBugreport(in ComponentName who);
- void setCameraDisabled(in ComponentName who, boolean disabled, boolean parent);
+ void setCameraDisabled(in ComponentName who, String callerPackageName, boolean disabled, boolean parent);
boolean getCameraDisabled(in ComponentName who, int userHandle, boolean parent);
void setScreenCaptureDisabled(in ComponentName who, boolean disabled, boolean parent);
@@ -379,6 +379,7 @@ interface IDevicePolicyManager {
boolean setKeyguardDisabled(in ComponentName admin, boolean disabled);
boolean setStatusBarDisabled(in ComponentName who, boolean disabled);
+ boolean isStatusBarDisabled(in String callerPackage);
boolean getDoNotAskCredentialsOnBoot();
void notifyPendingSystemUpdate(in SystemUpdateInfo info);
diff --git a/core/java/android/app/admin/IntentFilterPolicyKey.java b/core/java/android/app/admin/IntentFilterPolicyKey.java
index d7eb10197ced..f2f8aa4296b2 100644
--- a/core/java/android/app/admin/IntentFilterPolicyKey.java
+++ b/core/java/android/app/admin/IntentFilterPolicyKey.java
@@ -117,7 +117,7 @@ public final class IntentFilterPolicyKey extends PolicyKey {
@Override
public int hashCode() {
- return Objects.hash(getIdentifier(), mFilter);
+ return Objects.hash(getIdentifier());
}
@Override
@@ -133,7 +133,7 @@ public final class IntentFilterPolicyKey extends PolicyKey {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(getIdentifier());
- mFilter.writeToParcel(dest, flags);
+ dest.writeTypedObject(mFilter, flags);
}
@NonNull
diff --git a/core/java/android/app/admin/LockTaskPolicy.java b/core/java/android/app/admin/LockTaskPolicy.java
index 28757df41f5e..f5d1cb4bb672 100644
--- a/core/java/android/app/admin/LockTaskPolicy.java
+++ b/core/java/android/app/admin/LockTaskPolicy.java
@@ -22,7 +22,6 @@ import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@@ -67,7 +66,7 @@ public final class LockTaskPolicy extends PolicyValue<LockTaskPolicy> {
@Override
@NonNull
public LockTaskPolicy getValue() {
- return super.getValue();
+ return this;
}
/**
@@ -76,6 +75,7 @@ public final class LockTaskPolicy extends PolicyValue<LockTaskPolicy> {
public LockTaskPolicy(@NonNull Set<String> packages) {
Objects.requireNonNull(packages);
mPackages.addAll(packages);
+ setValue(this);
}
/**
@@ -89,9 +89,13 @@ public final class LockTaskPolicy extends PolicyValue<LockTaskPolicy> {
}
private LockTaskPolicy(Parcel source) {
- String[] packages = Objects.requireNonNull(source.readStringArray());
- mPackages = new HashSet<>(Arrays.stream(packages).toList());
+ int size = source.readInt();
+ mPackages = new HashSet<>();
+ for (int i = 0; i < size; i++) {
+ mPackages.add(source.readString());
+ }
mFlags = source.readInt();
+ setValue(this);
}
/**
@@ -100,6 +104,7 @@ public final class LockTaskPolicy extends PolicyValue<LockTaskPolicy> {
public LockTaskPolicy(LockTaskPolicy policy) {
mPackages = new HashSet<>(policy.mPackages);
mFlags = policy.mFlags;
+ setValue(this);
}
/**
@@ -144,7 +149,10 @@ public final class LockTaskPolicy extends PolicyValue<LockTaskPolicy> {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeArray(mPackages.toArray(new String[0]));
+ dest.writeInt(mPackages.size());
+ for (String p : mPackages) {
+ dest.writeString(p);
+ }
dest.writeInt(mFlags);
}
diff --git a/core/java/android/app/admin/LongPolicyValue.java b/core/java/android/app/admin/LongPolicyValue.java
new file mode 100644
index 000000000000..b149b8aa9f2f
--- /dev/null
+++ b/core/java/android/app/admin/LongPolicyValue.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+public final class LongPolicyValue extends PolicyValue<Long> {
+
+ public LongPolicyValue(long value) {
+ super(value);
+ }
+
+ private LongPolicyValue(Parcel source) {
+ this(source.readLong());
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ LongPolicyValue other = (LongPolicyValue) o;
+ return Objects.equals(getValue(), other.getValue());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getValue());
+ }
+
+ @Override
+ public String toString() {
+ return "LongPolicyValue { mValue= " + getValue() + " }";
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeLong(getValue());
+ }
+
+ @NonNull
+ public static final Creator<LongPolicyValue> CREATOR =
+ new Creator<LongPolicyValue>() {
+ @Override
+ public LongPolicyValue createFromParcel(Parcel source) {
+ return new LongPolicyValue(source);
+ }
+
+ @Override
+ public LongPolicyValue[] newArray(int size) {
+ return new LongPolicyValue[size];
+ }
+ };
+}
diff --git a/core/java/android/app/admin/MostRecent.java b/core/java/android/app/admin/MostRecent.java
index ac165718947f..9df4b5375763 100644
--- a/core/java/android/app/admin/MostRecent.java
+++ b/core/java/android/app/admin/MostRecent.java
@@ -18,6 +18,7 @@ package android.app.admin;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,6 +33,23 @@ import android.os.Parcelable;
@TestApi
public final class MostRecent<V> extends ResolutionMechanism<V> {
+ /**
+ * Indicates that the most recent setter of the policy wins the resolution.
+ */
+ @NonNull
+ public static final MostRecent<?> MOST_RECENT = new MostRecent<>();
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ return o != null && getClass() == o.getClass();
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
@Override
public String toString() {
return "MostRecent {}";
@@ -46,15 +64,15 @@ public final class MostRecent<V> extends ResolutionMechanism<V> {
public void writeToParcel(@NonNull Parcel dest, int flags) {}
@NonNull
- public static final Parcelable.Creator<MostRecent> CREATOR =
- new Parcelable.Creator<MostRecent>() {
+ public static final Parcelable.Creator<MostRecent<?>> CREATOR =
+ new Parcelable.Creator<MostRecent<?>>() {
@Override
- public MostRecent createFromParcel(Parcel source) {
- return new MostRecent();
+ public MostRecent<?> createFromParcel(Parcel source) {
+ return new MostRecent<>();
}
@Override
- public MostRecent[] newArray(int size) {
+ public MostRecent<?>[] newArray(int size) {
return new MostRecent[size];
}
};
diff --git a/core/java/android/app/admin/MostRestrictive.java b/core/java/android/app/admin/MostRestrictive.java
index adb4744d9d64..bbe6eb2414ac 100644
--- a/core/java/android/app/admin/MostRestrictive.java
+++ b/core/java/android/app/admin/MostRestrictive.java
@@ -47,7 +47,8 @@ public final class MostRestrictive<V> extends ResolutionMechanism<V> {
/**
* Returns an ordered list of most to least restrictive values for a certain policy.
*/
- List<V> getMostToLeastRestrictiveValues() {
+ @NonNull
+ public List<V> getMostToLeastRestrictiveValues() {
return mMostToLeastRestrictive.stream().map(PolicyValue::getValue).toList();
}
@@ -55,13 +56,17 @@ public final class MostRestrictive<V> extends ResolutionMechanism<V> {
public boolean equals(@Nullable Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- MostRestrictive other = (MostRestrictive) o;
- return Objects.equals(mMostToLeastRestrictive, other.mMostToLeastRestrictive);
+ try {
+ MostRestrictive<V> other = (MostRestrictive<V>) o;
+ return Objects.equals(mMostToLeastRestrictive, other.mMostToLeastRestrictive);
+ } catch (ClassCastException exception) {
+ return false;
+ }
}
@Override
public int hashCode() {
- return Objects.hash(mMostToLeastRestrictive);
+ return mMostToLeastRestrictive.hashCode();
}
/**
diff --git a/core/java/android/app/admin/PolicyKey.java b/core/java/android/app/admin/PolicyKey.java
index a35f6341d868..84cc66b3060e 100644
--- a/core/java/android/app/admin/PolicyKey.java
+++ b/core/java/android/app/admin/PolicyKey.java
@@ -39,8 +39,7 @@ import java.util.Objects;
*
* @hide
*/
-// This is ok as the constructor is hidden and all subclasses have implemented
-// Parcelable.
+// This is ok as the constructor is hidden and all subclasses have implemented Parcelable.
@SuppressLint({"ParcelNotFinal", "ParcelCreator"})
@SystemApi
public abstract class PolicyKey implements Parcelable {
diff --git a/core/java/android/app/admin/PolicyState.java b/core/java/android/app/admin/PolicyState.java
index da71bb11fb13..fa76bfa61552 100644
--- a/core/java/android/app/admin/PolicyState.java
+++ b/core/java/android/app/admin/PolicyState.java
@@ -66,7 +66,7 @@ public final class PolicyState<V> implements Parcelable {
PolicyValue<V> policyValue = source.readParcelable(PolicyValue.class.getClassLoader());
mPoliciesSetByAdmins.put(admin, policyValue);
}
- mCurrentResolvedPolicy = source.readParcelable((PolicyValue.class.getClassLoader()));
+ mCurrentResolvedPolicy = source.readParcelable(PolicyValue.class.getClassLoader());
mResolutionMechanism = source.readParcelable(ResolutionMechanism.class.getClassLoader());
}
@@ -87,7 +87,7 @@ public final class PolicyState<V> implements Parcelable {
*/
@Nullable
public V getCurrentResolvedPolicy() {
- return mCurrentResolvedPolicy.getValue();
+ return mCurrentResolvedPolicy == null ? null : mCurrentResolvedPolicy.getValue();
}
/**
diff --git a/core/java/android/app/admin/PolicyUpdateResult.java b/core/java/android/app/admin/PolicyUpdateResult.java
index a6d0ebf93035..79a76f222dc9 100644
--- a/core/java/android/app/admin/PolicyUpdateResult.java
+++ b/core/java/android/app/admin/PolicyUpdateResult.java
@@ -44,6 +44,9 @@ public final class PolicyUpdateResult {
/**
* Result code to indicate that the policy has not been enforced or has changed because another
* admin has set a conflicting policy on the device.
+ *
+ * <p>The system will automatically try to enforce the policy when it can without additional
+ * calls from the admin.
*/
public static final int RESULT_FAILURE_CONFLICTING_ADMIN_POLICY = 1;
@@ -56,6 +59,22 @@ public final class PolicyUpdateResult {
public static final int RESULT_POLICY_CLEARED = 2;
/**
+ * Result code to indicate that the policy set by the admin has not been enforced because the
+ * local storage has reached its max limit.
+ *
+ * <p>The system will NOT try to automatically store and enforce this policy again.
+ */
+ public static final int RESULT_FAILURE_STORAGE_LIMIT_REACHED = 3;
+
+ /**
+ * Result code to indicate that the policy set by the admin has not been enforced because of a
+ * permanent hardware limitation/issue.
+ *
+ * <p>The system will NOT try to automatically store and enforce this policy again.
+ */
+ public static final int RESULT_FAILURE_HARDWARE_LIMITATION = 4;
+
+ /**
* Reason codes for {@link #getResultCode()}.
*
* @hide
@@ -65,7 +84,9 @@ public final class PolicyUpdateResult {
RESULT_FAILURE_UNKNOWN,
RESULT_SUCCESS,
RESULT_FAILURE_CONFLICTING_ADMIN_POLICY,
- RESULT_POLICY_CLEARED
+ RESULT_POLICY_CLEARED,
+ RESULT_FAILURE_STORAGE_LIMIT_REACHED,
+ RESULT_FAILURE_HARDWARE_LIMITATION
})
public @interface ResultCode {}
diff --git a/core/java/android/app/admin/PolicyUpdatesReceiver.java b/core/java/android/app/admin/PolicyUpdatesReceiver.java
index 67de04c1fdb5..be32d83e6f37 100644
--- a/core/java/android/app/admin/PolicyUpdatesReceiver.java
+++ b/core/java/android/app/admin/PolicyUpdatesReceiver.java
@@ -104,6 +104,14 @@ public abstract class PolicyUpdatesReceiver extends BroadcastReceiver {
"android.app.admin.extra.INTENT_FILTER";
/**
+ * A string extra holding the account type this policy applies to, (see
+ * {@link PolicyUpdatesReceiver#onPolicyChanged} and
+ * {@link PolicyUpdatesReceiver#onPolicySetResult})
+ */
+ public static final String EXTRA_ACCOUNT_TYPE =
+ "android.app.admin.extra.ACCOUNT_TYPE";
+
+ /**
* @hide
*/
public static final String EXTRA_POLICY_CHANGED_KEY =
@@ -214,7 +222,7 @@ public abstract class PolicyUpdatesReceiver extends BroadcastReceiver {
* send updates.
*
* @param context the running context as per {@link #onReceive}
- * @param policyKey Key to identify which policy this callback relates to.
+ * @param policyIdentifier Key to identify which policy this callback relates to.
* @param additionalPolicyParams Bundle containing additional params that may be required to
* identify some of the policy
* (e.g. {@link PolicyUpdatesReceiver#EXTRA_PACKAGE_NAME}
@@ -230,7 +238,7 @@ public abstract class PolicyUpdatesReceiver extends BroadcastReceiver {
*/
public void onPolicySetResult(
@NonNull Context context,
- @NonNull String policyKey,
+ @NonNull String policyIdentifier,
@NonNull Bundle additionalPolicyParams,
@NonNull TargetUser targetUser,
@NonNull PolicyUpdateResult policyUpdateResult) {}
@@ -247,7 +255,7 @@ public abstract class PolicyUpdatesReceiver extends BroadcastReceiver {
* send updates.
*
* @param context the running context as per {@link #onReceive}
- * @param policyKey Key to identify which policy this callback relates to.
+ * @param policyIdentifier Key to identify which policy this callback relates to.
* @param additionalPolicyParams Bundle containing additional params that may be required to
* identify some of the policy
* (e.g. {@link PolicyUpdatesReceiver#EXTRA_PACKAGE_NAME}
@@ -264,7 +272,7 @@ public abstract class PolicyUpdatesReceiver extends BroadcastReceiver {
*/
public void onPolicyChanged(
@NonNull Context context,
- @NonNull String policyKey,
+ @NonNull String policyIdentifier,
@NonNull Bundle additionalPolicyParams,
@NonNull TargetUser targetUser,
@NonNull PolicyUpdateResult policyUpdateResult) {}
diff --git a/core/java/android/app/admin/RoleAuthority.java b/core/java/android/app/admin/RoleAuthority.java
index 7fdd1188f65f..ccb41c398b04 100644
--- a/core/java/android/app/admin/RoleAuthority.java
+++ b/core/java/android/app/admin/RoleAuthority.java
@@ -22,7 +22,6 @@ import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@@ -38,15 +37,18 @@ public final class RoleAuthority extends Authority {
private final Set<String> mRoles;
/**
- * @hide
+ * Constructor for a role authority that accepts the list of roles held by the admin.
*/
public RoleAuthority(@NonNull Set<String> roles) {
mRoles = new HashSet<>(Objects.requireNonNull(roles));
}
private RoleAuthority(Parcel source) {
- String[] roles = source.readStringArray();
- mRoles = roles == null ? new HashSet<>() : new HashSet<>(Arrays.stream(roles).toList());
+ mRoles = new HashSet<>();
+ int size = source.readInt();
+ for (int i = 0; i < size; i++) {
+ mRoles.add(source.readString());
+ }
}
/**
@@ -64,7 +66,10 @@ public final class RoleAuthority extends Authority {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeArray(mRoles.toArray());
+ dest.writeInt(mRoles.size());
+ for (String role : mRoles) {
+ dest.writeString(role);
+ }
}
@Override
diff --git a/core/java/android/app/admin/StringSetUnion.java b/core/java/android/app/admin/StringSetUnion.java
index 730e6a23e382..a95b51e16c8c 100644
--- a/core/java/android/app/admin/StringSetUnion.java
+++ b/core/java/android/app/admin/StringSetUnion.java
@@ -17,6 +17,7 @@
package android.app.admin;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -33,6 +34,23 @@ import java.util.Set;
@TestApi
public final class StringSetUnion extends ResolutionMechanism<Set<String>> {
+ /**
+ * Union resolution for policies represented {@code Set<String>} which resolves as the union of
+ * all sets.
+ */
+ @NonNull
+ public static final StringSetUnion STRING_SET_UNION = new StringSetUnion();
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ return o != null && getClass() == o.getClass();
+ }
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
@Override
public String toString() {
return "StringSetUnion {}";
diff --git a/core/java/android/app/admin/TopPriority.java b/core/java/android/app/admin/TopPriority.java
index e712274820d2..edb93b266221 100644
--- a/core/java/android/app/admin/TopPriority.java
+++ b/core/java/android/app/admin/TopPriority.java
@@ -17,11 +17,12 @@
package android.app.admin;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -36,26 +37,56 @@ import java.util.Objects;
@TestApi
public final class TopPriority<V> extends ResolutionMechanism<V> {
- private final List<String> mHighestToLowestPriorityAuthorities;
+ private final List<Authority> mHighestToLowestPriorityAuthorities;
/**
* @hide
*/
- public TopPriority(@NonNull List<String> highestToLowestPriorityAuthorities) {
+ public TopPriority(@NonNull List<Authority> highestToLowestPriorityAuthorities) {
mHighestToLowestPriorityAuthorities = Objects.requireNonNull(
highestToLowestPriorityAuthorities);
}
/**
+ * Returns an object with the specified order of highest to lowest authorities.
+ */
+ private TopPriority(@NonNull Parcel source) {
+ mHighestToLowestPriorityAuthorities = new ArrayList<>();
+ int size = source.readInt();
+ for (int i = 0; i < size; i++) {
+ mHighestToLowestPriorityAuthorities.add(
+ source.readParcelable(Authority.class.getClassLoader()));
+ }
+ }
+
+ /**
* Returns an ordered list of authorities from highest priority to lowest priority for a
* certain policy.
*/
@NonNull
- List<String> getHighestToLowestPriorityAuthorities() {
+ public List<Authority> getHighestToLowestPriorityAuthorities() {
return mHighestToLowestPriorityAuthorities;
}
@Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ try {
+ TopPriority<V> other = (TopPriority<V>) o;
+ return Objects.equals(
+ mHighestToLowestPriorityAuthorities, other.mHighestToLowestPriorityAuthorities);
+ } catch (ClassCastException exception) {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return mHighestToLowestPriorityAuthorities.hashCode();
+ }
+
+ @Override
public String toString() {
return "TopPriority { mHighestToLowestPriorityAuthorities= "
+ mHighestToLowestPriorityAuthorities + " }";
@@ -67,7 +98,10 @@ public final class TopPriority<V> extends ResolutionMechanism<V> {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeStringArray(mHighestToLowestPriorityAuthorities.toArray(new String[0]));
+ dest.writeInt(mHighestToLowestPriorityAuthorities.size());
+ for (Authority authority : mHighestToLowestPriorityAuthorities) {
+ dest.writeParcelable(authority, flags);
+ }
}
@NonNull
@@ -75,9 +109,7 @@ public final class TopPriority<V> extends ResolutionMechanism<V> {
new Parcelable.Creator<TopPriority<?>>() {
@Override
public TopPriority<?> createFromParcel(Parcel source) {
- String[] highestToLowestPriorityAuthorities = source.readStringArray();
- return new TopPriority<>(
- Arrays.stream(highestToLowestPriorityAuthorities).toList());
+ return new TopPriority<>(source);
}
@Override
diff --git a/core/java/android/app/admin/UnknownAuthority.java b/core/java/android/app/admin/UnknownAuthority.java
index 4492b96895da..fdad898b7bd9 100644
--- a/core/java/android/app/admin/UnknownAuthority.java
+++ b/core/java/android/app/admin/UnknownAuthority.java
@@ -19,6 +19,7 @@ package android.app.admin;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
/**
@@ -32,11 +33,19 @@ import android.os.Parcel;
public final class UnknownAuthority extends Authority {
/**
+ * Object representing an unknown authority.
+ *
* @hide
*/
+ @TestApi
+ @NonNull
public static final UnknownAuthority UNKNOWN_AUTHORITY = new UnknownAuthority();
- private UnknownAuthority() {}
+ /**
+ * Creates an authority that represents an admin that can set a policy but
+ * doesn't have a known authority (e.g. a system components).
+ */
+ public UnknownAuthority() {}
@Override
public String toString() {
@@ -45,12 +54,13 @@ public final class UnknownAuthority extends Authority {
@Override
public boolean equals(@Nullable Object o) {
- return super.equals(o);
+ if (this == o) return true;
+ return o != null && getClass() == o.getClass();
}
@Override
public int hashCode() {
- return super.hashCode();
+ return 0;
}
@Override
@@ -66,7 +76,7 @@ public final class UnknownAuthority extends Authority {
new Creator<UnknownAuthority>() {
@Override
public UnknownAuthority createFromParcel(Parcel source) {
- return new UnknownAuthority();
+ return UNKNOWN_AUTHORITY;
}
@Override
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 8842955af961..5df2d5e1de35 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -491,7 +491,7 @@ public final class CompanionDeviceManager {
* @param associationId id of the device association.
* @param flags system data types to be enabled.
*/
- public void enableSystemDataSync(int associationId, @DataSyncTypes int flags) {
+ public void enableSystemDataSyncForTypes(int associationId, @DataSyncTypes int flags) {
if (!checkFeaturePresent()) {
return;
}
@@ -513,7 +513,7 @@ public final class CompanionDeviceManager {
* @param associationId id of the device association.
* @param flags system data types to be disabled.
*/
- public void disableSystemDataSync(int associationId, @DataSyncTypes int flags) {
+ public void disableSystemDataSyncForTypes(int associationId, @DataSyncTypes int flags) {
if (!checkFeaturePresent()) {
return;
}
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index 9ab7cf9a8fc6..12882a2f47c9 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -20,7 +20,7 @@ import android.app.PendingIntent;
import android.companion.virtual.IVirtualDeviceIntentInterceptor;
import android.companion.virtual.audio.IAudioConfigChangedCallback;
import android.companion.virtual.audio.IAudioRoutingCallback;
-import android.companion.virtual.sensor.IVirtualSensorStateChangeCallback;
+import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.content.IntentFilter;
@@ -112,16 +112,10 @@ interface IVirtualDevice {
boolean sendTouchEvent(IBinder token, in VirtualTouchEvent event);
/**
- * Creates a virtual sensor, capable of injecting sensor events into the system.
+ * Returns all virtual sensors for this device.
*/
@EnforcePermission("CREATE_VIRTUAL_DEVICE")
- void createVirtualSensor(IBinder tokenm, in VirtualSensorConfig config);
-
- /**
- * Removes the sensor corresponding to the given token from the system.
- */
- @EnforcePermission("CREATE_VIRTUAL_DEVICE")
- void unregisterSensor(IBinder token);
+ List<VirtualSensor> getVirtualSensorList();
/**
* Sends an event to the virtual sensor corresponding to the given token.
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 3e6b380be1f4..ae43c6eb8b85 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -35,7 +35,6 @@ import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChan
import android.companion.virtual.camera.VirtualCameraDevice;
import android.companion.virtual.camera.VirtualCameraInput;
import android.companion.virtual.sensor.VirtualSensor;
-import android.companion.virtual.sensor.VirtualSensorConfig;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -428,8 +427,6 @@ public final class VirtualDeviceManager {
};
@Nullable
private VirtualCameraDevice mVirtualCameraDevice;
- @NonNull
- private final List<VirtualSensor> mVirtualSensors = new ArrayList<>();
@Nullable
private VirtualAudioDevice mVirtualAudioDevice;
@@ -448,10 +445,6 @@ public final class VirtualDeviceManager {
params,
mActivityListenerBinder,
mSoundEffectListener);
- final List<VirtualSensorConfig> virtualSensorConfigs = params.getVirtualSensorConfigs();
- for (int i = 0; i < virtualSensorConfigs.size(); ++i) {
- mVirtualSensors.add(createVirtualSensor(virtualSensorConfigs.get(i)));
- }
}
/**
@@ -478,20 +471,19 @@ public final class VirtualDeviceManager {
}
/**
- * Returns this device's sensor with the given type and name, if any.
+ * Returns this device's sensors.
*
* @see VirtualDeviceParams.Builder#addVirtualSensorConfig
*
- * @param type The type of the sensor.
- * @param name The name of the sensor.
- * @return The matching sensor if found, {@code null} otherwise.
+ * @return A list of all sensors for this device, or an empty list if no sensors exist.
*/
- @Nullable
- public VirtualSensor getVirtualSensor(int type, @NonNull String name) {
- return mVirtualSensors.stream()
- .filter(sensor -> sensor.getType() == type && sensor.getName().equals(name))
- .findAny()
- .orElse(null);
+ @NonNull
+ public List<VirtualSensor> getVirtualSensorList() {
+ try {
+ return mVirtualDevice.getVirtualSensorList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -630,9 +622,6 @@ public final class VirtualDeviceManager {
@NonNull VirtualDisplayConfig config,
@Nullable @CallbackExecutor Executor executor,
@Nullable VirtualDisplay.Callback callback) {
- // TODO(b/205343547): Handle display groups properly instead of creating a new display
- // group for every new virtual display created using this API.
- // belongs to the same display group.
IVirtualDisplayCallback callbackWrapper =
new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor);
final int displayId;
@@ -941,28 +930,6 @@ public final class VirtualDeviceManager {
}
/**
- * Creates a virtual sensor, capable of injecting sensor events into the system. Only for
- * internal use, since device sensors must remain valid for the entire lifetime of the
- * device.
- *
- * @param config The configuration of the sensor.
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
- @NonNull
- public VirtualSensor createVirtualSensor(@NonNull VirtualSensorConfig config) {
- Objects.requireNonNull(config);
- try {
- final IBinder token = new Binder(
- "android.hardware.sensor.VirtualSensor:" + config.getName());
- mVirtualDevice.createVirtualSensor(token, config);
- return new VirtualSensor(config.getType(), config.getName(), mVirtualDevice, token);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Adds an activity listener to listen for events such as top activity change or virtual
* display task stack became empty.
*
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index d4a0a0871713..d8076b5c0fd7 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -19,11 +19,18 @@ package android.companion.virtual;
import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.companion.virtual.sensor.IVirtualSensorCallback;
+import android.companion.virtual.sensor.VirtualSensor;
+import android.companion.virtual.sensor.VirtualSensorCallback;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.content.ComponentName;
import android.os.Parcel;
@@ -37,11 +44,13 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
/**
* Params that can be configured when creating virtual devices.
@@ -190,6 +199,7 @@ public final class VirtualDeviceParams implements Parcelable {
// Mapping of @PolicyType to @DevicePolicy
@NonNull private final SparseIntArray mDevicePolicies;
@NonNull private final List<VirtualSensorConfig> mVirtualSensorConfigs;
+ @Nullable private final IVirtualSensorCallback mVirtualSensorCallback;
@RecentsPolicy
private final int mDefaultRecentsPolicy;
private final int mAudioPlaybackSessionId;
@@ -207,6 +217,7 @@ public final class VirtualDeviceParams implements Parcelable {
@Nullable String name,
@NonNull SparseIntArray devicePolicies,
@NonNull List<VirtualSensorConfig> virtualSensorConfigs,
+ @Nullable IVirtualSensorCallback virtualSensorCallback,
@RecentsPolicy int defaultRecentsPolicy,
int audioPlaybackSessionId,
int audioRecordingSessionId) {
@@ -224,6 +235,7 @@ public final class VirtualDeviceParams implements Parcelable {
mName = name;
mDevicePolicies = Objects.requireNonNull(devicePolicies);
mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
+ mVirtualSensorCallback = virtualSensorCallback;
mDefaultRecentsPolicy = defaultRecentsPolicy;
mAudioPlaybackSessionId = audioPlaybackSessionId;
mAudioRecordingSessionId = audioRecordingSessionId;
@@ -244,6 +256,8 @@ public final class VirtualDeviceParams implements Parcelable {
mDevicePolicies = parcel.readSparseIntArray();
mVirtualSensorConfigs = new ArrayList<>();
parcel.readTypedList(mVirtualSensorConfigs, VirtualSensorConfig.CREATOR);
+ mVirtualSensorCallback =
+ IVirtualSensorCallback.Stub.asInterface(parcel.readStrongBinder());
mDefaultRecentsPolicy = parcel.readInt();
mAudioPlaybackSessionId = parcel.readInt();
mAudioRecordingSessionId = parcel.readInt();
@@ -372,6 +386,15 @@ public final class VirtualDeviceParams implements Parcelable {
}
/**
+ * Returns the callback to get notified about changes in the sensor listeners.
+ * @hide
+ */
+ @Nullable
+ public IVirtualSensorCallback getVirtualSensorCallback() {
+ return mVirtualSensorCallback;
+ }
+
+ /**
* Returns the policy of how to handle activities in recents.
*
* @see RecentsPolicy
@@ -417,6 +440,8 @@ public final class VirtualDeviceParams implements Parcelable {
dest.writeString8(mName);
dest.writeSparseIntArray(mDevicePolicies);
dest.writeTypedList(mVirtualSensorConfigs);
+ dest.writeStrongBinder(
+ mVirtualSensorCallback != null ? mVirtualSensorCallback.asBinder() : null);
dest.writeInt(mDefaultRecentsPolicy);
dest.writeInt(mAudioPlaybackSessionId);
dest.writeInt(mAudioRecordingSessionId);
@@ -522,11 +547,38 @@ public final class VirtualDeviceParams implements Parcelable {
private boolean mDefaultActivityPolicyConfigured = false;
@Nullable private String mName;
@NonNull private SparseIntArray mDevicePolicies = new SparseIntArray();
- @NonNull private List<VirtualSensorConfig> mVirtualSensorConfigs = new ArrayList<>();
private int mDefaultRecentsPolicy;
private int mAudioPlaybackSessionId = AUDIO_SESSION_ID_GENERATE;
private int mAudioRecordingSessionId = AUDIO_SESSION_ID_GENERATE;
+ @NonNull private List<VirtualSensorConfig> mVirtualSensorConfigs = new ArrayList<>();
+ @Nullable
+ private IVirtualSensorCallback mVirtualSensorCallback;
+
+ private static class VirtualSensorCallbackDelegate extends IVirtualSensorCallback.Stub {
+ @NonNull
+ private final Executor mExecutor;
+ @NonNull
+ private final VirtualSensorCallback mCallback;
+
+ VirtualSensorCallbackDelegate(@NonNull @CallbackExecutor Executor executor,
+ @NonNull VirtualSensorCallback callback) {
+ mCallback = callback;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void onConfigurationChanged(@NonNull VirtualSensor sensor, boolean enabled,
+ int samplingPeriodMicros, int batchReportLatencyMicros) {
+ final Duration samplingPeriod =
+ Duration.ofNanos(MICROSECONDS.toNanos(samplingPeriodMicros));
+ final Duration batchReportingLatency =
+ Duration.ofNanos(MICROSECONDS.toNanos(batchReportLatencyMicros));
+ mExecutor.execute(() -> mCallback.onConfigurationChanged(
+ sensor, enabled, samplingPeriod, batchReportingLatency));
+ }
+ }
+
/**
* Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY}
* is required if this is set to {@link #LOCK_STATE_ALWAYS_UNLOCKED}.
@@ -731,6 +783,24 @@ public final class VirtualDeviceParams implements Parcelable {
}
/**
+ * Sets the callback to get notified about changes in the sensor listeners.
+ *
+ * @param executor The executor where the callback is executed on.
+ * @param callback The callback to get notified when the state of the sensor
+ * listeners has changed, see {@link VirtualSensorCallback}
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setVirtualSensorCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull VirtualSensorCallback callback) {
+ mVirtualSensorCallback = new VirtualSensorCallbackDelegate(
+ Objects.requireNonNull(executor),
+ Objects.requireNonNull(callback));
+ return this;
+ }
+
+ /**
* Sets the policy to indicate how activities are handled in recents.
*
* @param defaultRecentsPolicy A policy specifying how to handle activities in recents.
@@ -798,12 +868,17 @@ public final class VirtualDeviceParams implements Parcelable {
*/
@NonNull
public VirtualDeviceParams build() {
- if (!mVirtualSensorConfigs.isEmpty()
- && (mDevicePolicies.get(POLICY_TYPE_SENSORS, DEVICE_POLICY_DEFAULT)
- != DEVICE_POLICY_CUSTOM)) {
- throw new IllegalArgumentException(
- "DEVICE_POLICY_CUSTOM for POLICY_TYPE_SENSORS is required for creating "
- + "virtual sensors.");
+ if (!mVirtualSensorConfigs.isEmpty()) {
+ if (mDevicePolicies.get(POLICY_TYPE_SENSORS, DEVICE_POLICY_DEFAULT)
+ != DEVICE_POLICY_CUSTOM) {
+ throw new IllegalArgumentException(
+ "DEVICE_POLICY_CUSTOM for POLICY_TYPE_SENSORS is required for creating "
+ + "virtual sensors.");
+ }
+ if (mVirtualSensorCallback == null) {
+ throw new IllegalArgumentException(
+ "VirtualSensorCallback is required for creating virtual sensors.");
+ }
}
if ((mAudioPlaybackSessionId != AUDIO_SESSION_ID_GENERATE
@@ -837,6 +912,7 @@ public final class VirtualDeviceParams implements Parcelable {
mName,
mDevicePolicies,
mVirtualSensorConfigs,
+ mVirtualSensorCallback,
mDefaultRecentsPolicy,
mAudioPlaybackSessionId,
mAudioRecordingSessionId);
diff --git a/core/java/android/companion/virtual/sensor/IVirtualSensorStateChangeCallback.aidl b/core/java/android/companion/virtual/sensor/IVirtualSensorCallback.aidl
index b99cc7eb67a5..7da9c3224400 100644
--- a/core/java/android/companion/virtual/sensor/IVirtualSensorStateChangeCallback.aidl
+++ b/core/java/android/companion/virtual/sensor/IVirtualSensorCallback.aidl
@@ -16,20 +16,24 @@
package android.companion.virtual.sensor;
+import android.companion.virtual.sensor.VirtualSensor;
+
/**
- * Interface for notification of listener registration changes for a virtual sensor.
+ * Interface for notifying the sensor owner about whether and how sensor events should be injected.
*
* @hide
*/
-oneway interface IVirtualSensorStateChangeCallback {
+oneway interface IVirtualSensorCallback {
/**
- * Called when the registered listeners to a virtual sensor have changed.
+ * Called when the requested sensor event injection parameters have changed.
*
+ * @param sensor The sensor whose requested injection parameters have changed.
* @param enabled Whether the sensor is enabled.
* @param samplingPeriodMicros The requested sensor's sampling period in microseconds.
* @param batchReportingLatencyMicros The requested maximum time interval in microseconds
* between the delivery of two batches of sensor events.
*/
- void onStateChanged(boolean enabled, int samplingPeriodMicros, int batchReportLatencyMicros);
+ void onConfigurationChanged(in VirtualSensor sensor, boolean enabled, int samplingPeriodMicros,
+ int batchReportLatencyMicros);
}
diff --git a/telephony/java/com/android/internal/telephony/IIntArrayConsumer.aidl b/core/java/android/companion/virtual/sensor/VirtualSensor.aidl
index c208755a666a..ccb597aca0ac 100644
--- a/telephony/java/com/android/internal/telephony/IIntArrayConsumer.aidl
+++ b/core/java/android/companion/virtual/sensor/VirtualSensor.aidl
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-package com.android.internal.telephony;
+package android.companion.virtual.sensor;
-// Copies consumer pattern for an operation that requires an int array result from another
-// process to finish.
-oneway interface IIntArrayConsumer {
- void accept(in int[] result);
-} \ No newline at end of file
+parcelable VirtualSensor;
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensor.java b/core/java/android/companion/virtual/sensor/VirtualSensor.java
index 58a5387c5651..bda44d402823 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensor.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensor.java
@@ -22,10 +22,10 @@ import android.annotation.SystemApi;
import android.companion.virtual.IVirtualDevice;
import android.hardware.Sensor;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
-import java.time.Duration;
-
/**
* Representation of a sensor on a remote device, capable of sending events, such as an
* accelerometer or a gyroscope.
@@ -35,24 +35,8 @@ import java.time.Duration;
* @hide
*/
@SystemApi
-public class VirtualSensor {
-
- /**
- * Interface for notification of listener registration changes for a virtual sensor.
- */
- public interface SensorStateChangeCallback {
- /**
- * Called when the registered listeners to a virtual sensor have changed.
- *
- * @param enabled Whether the sensor is enabled.
- * @param samplingPeriod The requested sampling period of the sensor.
- * @param batchReportLatency The requested maximum time interval between the delivery of two
- * batches of sensor events.
- */
- void onStateChanged(boolean enabled, @NonNull Duration samplingPeriod,
- @NonNull Duration batchReportLatency);
- }
-
+public final class VirtualSensor implements Parcelable {
+ private final int mHandle;
private final int mType;
private final String mName;
private final IVirtualDevice mVirtualDevice;
@@ -61,13 +45,32 @@ public class VirtualSensor {
/**
* @hide
*/
- public VirtualSensor(int type, String name, IVirtualDevice virtualDevice, IBinder token) {
+ public VirtualSensor(int handle, int type, String name, IVirtualDevice virtualDevice,
+ IBinder token) {
+ mHandle = handle;
mType = type;
mName = name;
mVirtualDevice = virtualDevice;
mToken = token;
}
+ private VirtualSensor(Parcel parcel) {
+ mHandle = parcel.readInt();
+ mType = parcel.readInt();
+ mName = parcel.readString8();
+ mVirtualDevice = IVirtualDevice.Stub.asInterface(parcel.readStrongBinder());
+ mToken = parcel.readStrongBinder();
+ }
+
+ /**
+ * Returns the unique handle of the sensor.
+ *
+ * @hide
+ */
+ public int getHandle() {
+ return mHandle;
+ }
+
/**
* Returns the type of the sensor.
*
@@ -87,6 +90,32 @@ public class VirtualSensor {
}
/**
+ * Returns the identifier of the
+ * {@link android.companion.virtual.VirtualDeviceManager.VirtualDevice} this sensor belongs to.
+ */
+ public int getDeviceId() {
+ try {
+ return mVirtualDevice.getDeviceId();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeInt(mHandle);
+ parcel.writeInt(mType);
+ parcel.writeString8(mName);
+ parcel.writeStrongBinder(mVirtualDevice.asBinder());
+ parcel.writeStrongBinder(mToken);
+ }
+
+ /**
* Send a sensor event to the system.
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@@ -97,4 +126,16 @@ public class VirtualSensor {
throw e.rethrowFromSystemServer();
}
}
+
+ @NonNull
+ public static final Parcelable.Creator<VirtualSensor> CREATOR =
+ new Parcelable.Creator<VirtualSensor>() {
+ public VirtualSensor createFromParcel(Parcel in) {
+ return new VirtualSensor(in);
+ }
+
+ public VirtualSensor[] newArray(int size) {
+ return new VirtualSensor[size];
+ }
+ };
}
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorCallback.java b/core/java/android/companion/virtual/sensor/VirtualSensorCallback.java
new file mode 100644
index 000000000000..e09718941302
--- /dev/null
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorCallback.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion.virtual.sensor;
+
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.time.Duration;
+
+/**
+ * Interface for notifying the sensor owner about whether and how sensor events should be injected.
+ *
+ * <p>This callback can be used for controlling the sensor event injection - e.g. if the sensor is
+ * not enabled, then no events should be injected. Similarly, the rate and delay of the injected
+ * events that the registered listeners expect are specified here.
+ *
+ * <p>The callback is tied to the VirtualDevice's lifetime as the virtual sensors are created when
+ * the device is created and destroyed when the device is destroyed.
+ *
+ * @hide
+ */
+@SystemApi
+public interface VirtualSensorCallback {
+ /**
+ * Called when the requested sensor event injection parameters have changed.
+ *
+ * <p>This is effectively called when the registered listeners to a virtual sensor have changed.
+ *
+ * @param sensor The sensor whose requested injection parameters have changed.
+ * @param enabled Whether the sensor is enabled. True if any listeners are currently registered,
+ * and false otherwise.
+ * @param samplingPeriod The requested sampling period of the sensor.
+ * @param batchReportLatency The requested maximum time interval between the delivery of two
+ * batches of sensor events.
+ */
+ void onConfigurationChanged(@NonNull VirtualSensor sensor, boolean enabled,
+ @NonNull Duration samplingPeriod, @NonNull Duration batchReportLatency);
+}
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
index eb2f9dde48db..6d45365ebbd4 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
@@ -16,20 +16,15 @@
package android.companion.virtual.sensor;
-import static java.util.concurrent.TimeUnit.MICROSECONDS;
-import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.hardware.Sensor;
import android.os.Parcel;
import android.os.Parcelable;
-import java.time.Duration;
import java.util.Objects;
-import java.util.concurrent.Executor;
/**
* Configuration for creation of a virtual sensor.
@@ -44,23 +39,17 @@ public final class VirtualSensorConfig implements Parcelable {
private final String mName;
@Nullable
private final String mVendor;
- @Nullable
- private final IVirtualSensorStateChangeCallback mStateChangeCallback;
- private VirtualSensorConfig(int type, @NonNull String name, @Nullable String vendor,
- @Nullable IVirtualSensorStateChangeCallback stateChangeCallback) {
+ private VirtualSensorConfig(int type, @NonNull String name, @Nullable String vendor) {
mType = type;
mName = name;
mVendor = vendor;
- mStateChangeCallback = stateChangeCallback;
}
private VirtualSensorConfig(@NonNull Parcel parcel) {
mType = parcel.readInt();
mName = parcel.readString8();
mVendor = parcel.readString8();
- mStateChangeCallback =
- IVirtualSensorStateChangeCallback.Stub.asInterface(parcel.readStrongBinder());
}
@Override
@@ -73,8 +62,6 @@ public final class VirtualSensorConfig implements Parcelable {
parcel.writeInt(mType);
parcel.writeString8(mName);
parcel.writeString8(mVendor);
- parcel.writeStrongBinder(
- mStateChangeCallback != null ? mStateChangeCallback.asBinder() : null);
}
/**
@@ -105,15 +92,6 @@ public final class VirtualSensorConfig implements Parcelable {
}
/**
- * Returns the callback to get notified about changes in the sensor listeners.
- * @hide
- */
- @Nullable
- public IVirtualSensorStateChangeCallback getStateChangeCallback() {
- return mStateChangeCallback;
- }
-
- /**
* Builder for {@link VirtualSensorConfig}.
*/
public static final class Builder {
@@ -123,32 +101,6 @@ public final class VirtualSensorConfig implements Parcelable {
private final String mName;
@Nullable
private String mVendor;
- @Nullable
- private IVirtualSensorStateChangeCallback mStateChangeCallback;
-
- private static class SensorStateChangeCallbackDelegate
- extends IVirtualSensorStateChangeCallback.Stub {
- @NonNull
- private final Executor mExecutor;
- @NonNull
- private final VirtualSensor.SensorStateChangeCallback mCallback;
-
- SensorStateChangeCallbackDelegate(@NonNull @CallbackExecutor Executor executor,
- @NonNull VirtualSensor.SensorStateChangeCallback callback) {
- mCallback = callback;
- mExecutor = executor;
- }
- @Override
- public void onStateChanged(boolean enabled, int samplingPeriodMicros,
- int batchReportLatencyMicros) {
- final Duration samplingPeriod =
- Duration.ofNanos(MICROSECONDS.toNanos(samplingPeriodMicros));
- final Duration batchReportingLatency =
- Duration.ofNanos(MICROSECONDS.toNanos(batchReportLatencyMicros));
- mExecutor.execute(() -> mCallback.onStateChanged(
- enabled, samplingPeriod, batchReportingLatency));
- }
- }
/**
* Creates a new builder.
@@ -167,7 +119,7 @@ public final class VirtualSensorConfig implements Parcelable {
*/
@NonNull
public VirtualSensorConfig build() {
- return new VirtualSensorConfig(mType, mName, mVendor, mStateChangeCallback);
+ return new VirtualSensorConfig(mType, mName, mVendor);
}
/**
@@ -178,24 +130,6 @@ public final class VirtualSensorConfig implements Parcelable {
mVendor = vendor;
return this;
}
-
- /**
- * Sets the callback to get notified about changes in the sensor listeners.
- *
- * @param executor The executor where the callback is executed on.
- * @param callback The callback to get notified when the state of the sensor
- * listeners has changed, see {@link VirtualSensor.SensorStateChangeCallback}
- */
- @SuppressLint("MissingGetterMatchingBuilder")
- @NonNull
- public VirtualSensorConfig.Builder setStateChangeCallback(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull VirtualSensor.SensorStateChangeCallback callback) {
- mStateChangeCallback = new SensorStateChangeCallbackDelegate(
- Objects.requireNonNull(executor),
- Objects.requireNonNull(callback));
- return this;
- }
}
@NonNull
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ffe73d6656a7..7be00a045403 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -679,8 +679,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public static final int PRIVATE_FLAG_PROFILEABLE_BY_SHELL = 1 << 23;
/**
- * Indicates whether this package requires access to non-SDK APIs.
- * Only system apps and tests are allowed to use this property.
+ * Indicates whether this application has declared its user data as fragile,
+ * causing the system to prompt the user on whether to keep the user data
+ * on uninstall.
* @hide
*/
public static final int PRIVATE_FLAG_HAS_FRAGILE_USER_DATA = 1 << 24;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index dfaa0651ff66..baf10ed85511 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -575,8 +575,6 @@ interface IPackageManager {
boolean performDexOptSecondary(String packageName,
String targetCompilerFilter, boolean force);
- void forceDexOpt(String packageName);
-
int getMoveStatus(int moveId);
void registerMoveCallback(in IPackageMoveObserver callback);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 8f864f4f9a79..cfd291f3fa5f 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -30,8 +30,6 @@ import static android.content.pm.PackageInfo.INSTALL_LOCATION_AUTO;
import static android.content.pm.PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
import static android.content.pm.PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
-import static com.android.internal.util.XmlUtils.writeStringAttribute;
-
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.CurrentTimeMillisLong;
@@ -84,7 +82,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ExceptionUtils;
-import android.util.Log;
import com.android.internal.content.InstallLocationUtils;
import com.android.internal.util.ArrayUtils;
@@ -92,7 +89,6 @@ import com.android.internal.util.DataClass;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.modules.utils.TypedXmlSerializer;
import java.io.Closeable;
import java.io.File;
@@ -2313,11 +2309,6 @@ public class PackageInstaller {
private final ArrayMap<String, Integer> mPermissionStates;
/**
- * @see #getFinalPermissionStates()
- */
- private ArrayMap<String, Integer> mFinalPermissionStates;
-
- /**
* Construct parameters for a new package install session.
*
* @param mode one of {@link #MODE_FULL_INSTALL} or
@@ -2563,11 +2554,6 @@ public class PackageInstaller {
+ (permissionName == null ? "null" : "empty"));
}
- if (mFinalPermissionStates != null) {
- Log.wtf(TAG, "Requested permission " + permissionName + " but final permissions"
- + " were already decided for this session: " + mFinalPermissionStates);
- }
-
switch (state) {
case PERMISSION_STATE_DEFAULT:
mPermissionStates.remove(permissionName);
@@ -3008,48 +2994,10 @@ public class PackageInstaller {
}
}
- /**
- * This is only for use by system server. If you need the actual grant state, use
- * {@link #getFinalPermissionStates()}.
- * <p/>
- * This is implemented here to avoid exposing the raw permission sets to external callers,
- * so that enforcement done in the either of the final methods is the single source of truth
- * for default grant/deny policy.
- *
- * @hide
- */
- public void writePermissionStateXml(@NonNull TypedXmlSerializer out,
- @NonNull String grantTag, @NonNull String denyTag, @NonNull String attrName)
- throws IOException {
- for (int index = 0; index < mPermissionStates.size(); index++) {
- var permissionName = mPermissionStates.keyAt(index);
- var state = mPermissionStates.valueAt(index);
- String tag = state == PERMISSION_STATE_GRANTED ? grantTag : denyTag;
- out.startTag(null, tag);
- writeStringAttribute(out, attrName, permissionName);
- out.endTag(null, tag);
- }
- }
-
- /**
- * Snapshot of final permission states taken when this method is first called, to separate
- * what the caller wanted and the effective state that should be applied to the session.
- *
- * This prevents someone from adding more permissions after the fact.
- *
- * @hide
- */
+ /** @hide */
@NonNull
- public ArrayMap<String, Integer> getFinalPermissionStates() {
- if (mFinalPermissionStates == null) {
- mFinalPermissionStates = new ArrayMap<>(mPermissionStates);
- if (!mFinalPermissionStates.containsKey(
- Manifest.permission.USE_FULL_SCREEN_INTENT)) {
- mFinalPermissionStates.put(Manifest.permission.USE_FULL_SCREEN_INTENT,
- PERMISSION_STATE_GRANTED);
- }
- }
- return mFinalPermissionStates;
+ public ArrayMap<String, Integer> getPermissionStates() {
+ return mPermissionStates;
}
/** @hide */
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 49d21dafbd5d..90ed4ce63d97 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -246,8 +246,17 @@ public class ServiceInfo extends ComponentInfo
/**
* Constant corresponding to {@code mediaProjection} in
- * the {@link android.R.attr#foregroundServiceType} attribute.
- * Managing a media projection session, e.g for screen recording or taking screenshots.
+ * the {@link android.R.attr#foregroundServiceType foregroundServiceType} attribute.
+ *
+ * <p>
+ * To capture through {@link android.media.projection.MediaProjection}, an app must start a
+ * foreground service with the type corresponding to this constant. This type should only be
+ * used for {@link android.media.projection.MediaProjection}. Capturing screen contents via
+ * {@link android.media.projection.MediaProjection#createVirtualDisplay(String, int, int, int,
+ * int, android.view.Surface, android.hardware.display.VirtualDisplay.Callback,
+ * android.os.Handler) createVirtualDisplay} conveniently allows recording, presenting screen
+ * contents into a meeting, taking screenshots, or several other scenarios.
+ * </p>
*
* <p>Starting foreground service with this type from apps targeting API level
* {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and later, will require permission
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 7164dc300e06..17e81e5c74e1 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -1429,6 +1429,7 @@ public final class DisplayManager {
* hdrConversionMode.conversionMode is not {@link HdrConversionMode#HDR_CONVERSION_FORCE}.
*
* @see #getHdrConversionMode
+ * @see #getHdrConversionModeSetting
* @see #getSupportedHdrOutputTypes
* @hide
*/
@@ -1440,9 +1441,14 @@ public final class DisplayManager {
/**
* Returns the {@link HdrConversionMode} of the device, which is set by the user.
+
+ * The HDR conversion mode chosen by user which considers the app override is returned. Apps can
+ * override HDR conversion using
+ * {@link android.view.WindowManager.LayoutParams#disableHdrConversion}.
*
* @see #setHdrConversionMode
* @see #getSupportedHdrOutputTypes
+ * @see #getHdrConversionModeSetting()
* @hide
*/
@TestApi
@@ -1452,6 +1458,23 @@ public final class DisplayManager {
}
/**
+ * Returns the {@link HdrConversionMode} of the device, which is set by the user.
+
+ * The HDR conversion mode chosen by user is returned irrespective of whether HDR conversion
+ * is disabled by an app.
+ *
+ * @see #setHdrConversionMode
+ * @see #getSupportedHdrOutputTypes
+ * @see #getHdrConversionMode()
+ * @hide
+ */
+ @TestApi
+ @NonNull
+ public HdrConversionMode getHdrConversionModeSetting() {
+ return mGlobal.getHdrConversionModeSetting();
+ }
+
+ /**
* Returns the HDR output types supported by the device.
*
* @see #getHdrConversionMode
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index d9db177b4c18..4a992f32cec8 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -990,6 +990,19 @@ public final class DisplayManagerGlobal {
}
/**
+ * Returns the {@link HdrConversionMode} of the device, which is set by the user.
+ * The HDR conversion mode chosen by user is returned irrespective of whether HDR conversion
+ * is disabled by an app.
+ */
+ public HdrConversionMode getHdrConversionModeSetting() {
+ try {
+ return mDm.getHdrConversionModeSetting();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the {@link HdrConversionMode} of the device.
*/
public HdrConversionMode getHdrConversionMode() {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 2bd06060b8d4..d6df03321298 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -234,13 +234,14 @@ public abstract class DisplayManagerInternal {
* @param requestedMinimalPostProcessing The preferred minimal post processing setting for the
* display. This is true when there is at least one visible window that wants minimal post
* processng on.
+ * @param disableHdrConversion The preferred HDR conversion setting for the window.
* @param inTraversal True if called from WindowManagerService during a window traversal
* prior to call to performTraversalInTransactionFromWindowManager.
*/
public abstract void setDisplayProperties(int displayId, boolean hasContent,
float requestedRefreshRate, int requestedModeId, float requestedMinRefreshRate,
float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing,
- boolean inTraversal);
+ boolean disableHdrConversion, boolean inTraversal);
/**
* Applies an offset to the contents of a display, for example to avoid burn-in.
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 0a44f8509c76..a3b7b5111b89 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -180,6 +180,7 @@ interface IDisplayManager {
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MODIFY_HDR_CONVERSION_MODE)")
void setHdrConversionMode(in HdrConversionMode hdrConversionMode);
+ HdrConversionMode getHdrConversionModeSetting();
HdrConversionMode getHdrConversionMode();
int[] getSupportedHdrOutputTypes();
diff --git a/core/java/android/hardware/usb/DisplayPortAltModeInfo.java b/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
index 7c62373b982f..9da2f4c12977 100644
--- a/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
+++ b/core/java/android/hardware/usb/DisplayPortAltModeInfo.java
@@ -79,7 +79,7 @@ public final class DisplayPortAltModeInfo implements Parcelable {
* as one of its capabilities, however may not yet have entered DisplayPort Alt Mode or has been
* configured for data transmission.
*/
- public static final int DISPLAYPORT_ALT_MODE_STATUS_CAPABLE = 2;
+ public static final int DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED = 2;
/**
* Port Partners:
@@ -113,7 +113,7 @@ public final class DisplayPortAltModeInfo implements Parcelable {
@IntDef(prefix = { "DISPLAYPORT_ALT_MODE_STATUS_" }, value = {
DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN,
DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE,
- DISPLAYPORT_ALT_MODE_STATUS_CAPABLE,
+ DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED,
DISPLAYPORT_ALT_MODE_STATUS_ENABLED,
})
@Retention(RetentionPolicy.SOURCE)
@@ -150,10 +150,6 @@ public final class DisplayPortAltModeInfo implements Parcelable {
/**
* Returns the DisplayPort Alt Mode Status for a port partner acting as a sink.
*
- * @return {@link #DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN}
- * or {@link #DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE}
- * or {@link #DISPLAYPORT_ALT_MODE_STATUS_CAPABLE}
- * or {@link #DISPLAYPORT_ALT_MODE_STATUS_ENABLED}
*/
public @DisplayPortAltModeStatus int getPartnerSinkStatus() {
return mPartnerSinkStatus;
@@ -162,10 +158,6 @@ public final class DisplayPortAltModeInfo implements Parcelable {
/**
* Returns the DisplayPort Alt Mode Status for the attached cable
*
- * @return {@link #DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN}
- * or {@link #DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE}
- * or {@link #DISPLAYPORT_ALT_MODE_STATUS_CAPABLE}
- * or {@link #DISPLAYPORT_ALT_MODE_STATUS_ENABLED}
*/
public @DisplayPortAltModeStatus int getCableStatus() {
return mCableStatus;
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 71ec1c640d48..889d3df0941a 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -1647,7 +1647,7 @@ public class UsbManager {
/**
* Registers the given listener to listen for DisplayPort Alt Mode changes.
* <p>
- * If this method returns true, the caller should ensure to call
+ * If this method returns without Exceptions, the caller should ensure to call
* {@link #unregisterDisplayPortAltModeListener} when it no longer requires updates.
*
* @param executor Executor on which to run the listener.
@@ -1655,14 +1655,14 @@ public class UsbManager {
* changes. See {@link #DisplayPortAltModeInfoListener} for listener
* details.
*
- * @return true on successful register, false on failed register due to listener already being
- * registered or an internal error.
+ * @throws IllegalStateException if listener has already been registered previously but not
+ * unregistered or an unexpected system failure occurs.
*
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_USB)
- public boolean registerDisplayPortAltModeInfoListener(
+ public void registerDisplayPortAltModeInfoListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull DisplayPortAltModeInfoListener listener) {
Objects.requireNonNull(executor, "registerDisplayPortAltModeInfoListener: "
@@ -1678,15 +1678,15 @@ public class UsbManager {
if (mDisplayPortServiceListener == null) {
if (!registerDisplayPortAltModeEventsIfNeededLocked()) {
- return false;
+ throw new IllegalStateException("Unexpected failure registering service "
+ + "listener");
}
}
if (mDisplayPortListeners.containsKey(listener)) {
- return false;
+ throw new IllegalStateException("Listener has already been registered.");
}
mDisplayPortListeners.put(listener, executor);
- return true;
}
}
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index 73dcb362f383..490b128d8bac 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -54,7 +54,7 @@ import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP;
import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_OTHER;
import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_UNKNOWN;
import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE;
-import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_CAPABLE;
+import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED;
import static android.hardware.usb.DisplayPortAltModeInfo.DISPLAYPORT_ALT_MODE_STATUS_ENABLED;
import android.Manifest;
@@ -807,8 +807,8 @@ public final class UsbPort {
return "Unknown";
case DISPLAYPORT_ALT_MODE_STATUS_NOT_CAPABLE:
return "Not Capable";
- case DISPLAYPORT_ALT_MODE_STATUS_CAPABLE:
- return "Capable";
+ case DISPLAYPORT_ALT_MODE_STATUS_CAPABLE_DISABLED:
+ return "Capable-Disabled";
case DISPLAYPORT_ALT_MODE_STATUS_ENABLED:
return "Enabled";
default:
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index 8c133079a70a..e1662b81b017 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -311,7 +311,7 @@ public final class UsbPortStatus implements Parcelable {
/**
* Indicates that the Type-C plug orientation cannot be
- * determined.
+ * determined because the connected state of the device is unknown.
*/
public static final int PLUG_STATE_UNKNOWN = 0;
@@ -600,13 +600,8 @@ public final class UsbPortStatus implements Parcelable {
}
/**
- * Returns the orientation state of the attached cable/adapter.
+ * Returns the plug state of the attached cable/adapter.
*
- * @return one of {@link #PLUG_STATE_UNKNOWN},
- * {@link #PLUG_STATE_UNPLUGGED},
- * {@link #PLUG_STATE_PLUGGED_ORIENTATION_UNKNOWN},
- * {@link #PLUG_STATE_PLUGGED_ORIENTATION_NORMAL},
- * {@link #PLUG_STATE_PLUGGED_ORIENTATION_FLIPPED},
*/
public @PlugState int getPlugState() {
return mPlugState;
diff --git a/core/java/android/nfc/BeamShareData.java b/core/java/android/nfc/BeamShareData.java
deleted file mode 100644
index 6a40f98fe21c..000000000000
--- a/core/java/android/nfc/BeamShareData.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package android.nfc;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.UserHandle;
-
-/**
- * Class to IPC data to be shared over Android Beam.
- * Allows bundling NdefMessage, Uris and flags in a single
- * IPC call. This is important as we want to reduce the
- * amount of IPC calls at "touch time".
- * @hide
- */
-public final class BeamShareData implements Parcelable {
- public final NdefMessage ndefMessage;
- public final Uri[] uris;
- public final UserHandle userHandle;
- public final int flags;
-
- public BeamShareData(NdefMessage msg, Uri[] uris, UserHandle userHandle, int flags) {
- this.ndefMessage = msg;
- this.uris = uris;
- this.userHandle = userHandle;
- this.flags = flags;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- int urisLength = (uris != null) ? uris.length : 0;
- dest.writeParcelable(ndefMessage, 0);
- dest.writeInt(urisLength);
- if (urisLength > 0) {
- dest.writeTypedArray(uris, 0);
- }
- dest.writeParcelable(userHandle, 0);
- dest.writeInt(this.flags);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BeamShareData> CREATOR =
- new Parcelable.Creator<BeamShareData>() {
- @Override
- public BeamShareData createFromParcel(Parcel source) {
- Uri[] uris = null;
- NdefMessage msg = source.readParcelable(NdefMessage.class.getClassLoader(), android.nfc.NdefMessage.class);
- int numUris = source.readInt();
- if (numUris > 0) {
- uris = new Uri[numUris];
- source.readTypedArray(uris, Uri.CREATOR);
- }
- UserHandle userHandle = source.readParcelable(UserHandle.class.getClassLoader(), android.os.UserHandle.class);
- int flags = source.readInt();
-
- return new BeamShareData(msg, uris, userHandle, flags);
- }
-
- @Override
- public BeamShareData[] newArray(int size) {
- return new BeamShareData[size];
- }
- };
-}
diff --git a/core/java/android/nfc/IAppCallback.aidl b/core/java/android/nfc/IAppCallback.aidl
index 133146de2aa1..b06bf06d5197 100644
--- a/core/java/android/nfc/IAppCallback.aidl
+++ b/core/java/android/nfc/IAppCallback.aidl
@@ -16,7 +16,6 @@
package android.nfc;
-import android.nfc.BeamShareData;
import android.nfc.Tag;
/**
@@ -24,7 +23,5 @@ import android.nfc.Tag;
*/
interface IAppCallback
{
- BeamShareData createBeamShareData(byte peerLlcpVersion);
- oneway void onNdefPushComplete(byte peerLlcpVersion);
oneway void onTagDiscovered(in Tag tag);
}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 8a30ef4c2121..a6d8cafe8263 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -18,7 +18,6 @@ package android.nfc;
import android.app.PendingIntent;
import android.content.IntentFilter;
-import android.nfc.BeamShareData;
import android.nfc.NdefMessage;
import android.nfc.Tag;
import android.nfc.TechListParcel;
@@ -47,24 +46,18 @@ interface INfcAdapter
int getState();
boolean disable(boolean saveState);
boolean enable();
- boolean enableNdefPush();
- boolean disableNdefPush();
- boolean isNdefPushEnabled();
void pausePolling(int timeoutInMs);
void resumePolling();
void setForegroundDispatch(in PendingIntent intent,
in IntentFilter[] filters, in TechListParcel techLists);
void setAppCallback(in IAppCallback callback);
- oneway void invokeBeam();
- oneway void invokeBeamInternal(in BeamShareData shareData);
boolean ignore(int nativeHandle, int debounceMs, ITagRemovedCallback callback);
void dispatch(in Tag tag);
void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
- void setP2pModes(int initatorModes, int targetModes);
void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 911aaf317e3e..8d75cac531fb 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -19,9 +19,6 @@ package android.nfc;
import android.app.Activity;
import android.app.Application;
import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ContentProvider;
-import android.content.Intent;
-import android.net.Uri;
import android.nfc.NfcAdapter.ReaderCallback;
import android.os.Binder;
import android.os.Bundle;
@@ -110,14 +107,8 @@ public final class NfcActivityManager extends IAppCallback.Stub
class NfcActivityState {
boolean resumed = false;
Activity activity;
- NdefMessage ndefMessage = null; // static NDEF message
- NfcAdapter.CreateNdefMessageCallback ndefMessageCallback = null;
- NfcAdapter.OnNdefPushCompleteCallback onNdefPushCompleteCallback = null;
- NfcAdapter.CreateBeamUrisCallback uriCallback = null;
- Uri[] uris = null;
- int flags = 0;
- int readerModeFlags = 0;
NfcAdapter.ReaderCallback readerCallback = null;
+ int readerModeFlags = 0;
Bundle readerModeExtras = null;
Binder token;
@@ -137,24 +128,16 @@ public final class NfcActivityManager extends IAppCallback.Stub
unregisterApplication(activity.getApplication());
resumed = false;
activity = null;
- ndefMessage = null;
- ndefMessageCallback = null;
- onNdefPushCompleteCallback = null;
- uriCallback = null;
- uris = null;
+ readerCallback = null;
readerModeFlags = 0;
+ readerModeExtras = null;
token = null;
}
@Override
public String toString() {
- StringBuilder s = new StringBuilder("[").append(" ");
- s.append(ndefMessage).append(" ").append(ndefMessageCallback).append(" ");
- s.append(uriCallback).append(" ");
- if (uris != null) {
- for (Uri uri : uris) {
- s.append(onNdefPushCompleteCallback).append(" ").append(uri).append("]");
- }
- }
+ StringBuilder s = new StringBuilder("[");
+ s.append(readerCallback);
+ s.append("]");
return s.toString();
}
}
@@ -245,92 +228,6 @@ public final class NfcActivityManager extends IAppCallback.Stub
}
}
- public void setNdefPushContentUri(Activity activity, Uri[] uris) {
- boolean isResumed;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = getActivityState(activity);
- state.uris = uris;
- isResumed = state.resumed;
- }
- if (isResumed) {
- // requestNfcServiceCallback() verifies permission also
- requestNfcServiceCallback();
- } else {
- // Crash API calls early in case NFC permission is missing
- verifyNfcPermission();
- }
- }
-
-
- public void setNdefPushContentUriCallback(Activity activity,
- NfcAdapter.CreateBeamUrisCallback callback) {
- boolean isResumed;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = getActivityState(activity);
- state.uriCallback = callback;
- isResumed = state.resumed;
- }
- if (isResumed) {
- // requestNfcServiceCallback() verifies permission also
- requestNfcServiceCallback();
- } else {
- // Crash API calls early in case NFC permission is missing
- verifyNfcPermission();
- }
- }
-
- public void setNdefPushMessage(Activity activity, NdefMessage message, int flags) {
- boolean isResumed;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = getActivityState(activity);
- state.ndefMessage = message;
- state.flags = flags;
- isResumed = state.resumed;
- }
- if (isResumed) {
- // requestNfcServiceCallback() verifies permission also
- requestNfcServiceCallback();
- } else {
- // Crash API calls early in case NFC permission is missing
- verifyNfcPermission();
- }
- }
-
- public void setNdefPushMessageCallback(Activity activity,
- NfcAdapter.CreateNdefMessageCallback callback, int flags) {
- boolean isResumed;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = getActivityState(activity);
- state.ndefMessageCallback = callback;
- state.flags = flags;
- isResumed = state.resumed;
- }
- if (isResumed) {
- // requestNfcServiceCallback() verifies permission also
- requestNfcServiceCallback();
- } else {
- // Crash API calls early in case NFC permission is missing
- verifyNfcPermission();
- }
- }
-
- public void setOnNdefPushCompleteCallback(Activity activity,
- NfcAdapter.OnNdefPushCompleteCallback callback) {
- boolean isResumed;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = getActivityState(activity);
- state.onNdefPushCompleteCallback = callback;
- isResumed = state.resumed;
- }
- if (isResumed) {
- // requestNfcServiceCallback() verifies permission also
- requestNfcServiceCallback();
- } else {
- // Crash API calls early in case NFC permission is missing
- verifyNfcPermission();
- }
- }
-
/**
* Request or unrequest NFC service callbacks.
* Makes IPC call - do not hold lock.
@@ -351,86 +248,6 @@ public final class NfcActivityManager extends IAppCallback.Stub
}
}
- /** Callback from NFC service, usually on binder thread */
- @Override
- public BeamShareData createBeamShareData(byte peerLlcpVersion) {
- NfcAdapter.CreateNdefMessageCallback ndefCallback;
- NfcAdapter.CreateBeamUrisCallback urisCallback;
- NdefMessage message;
- Activity activity;
- Uri[] uris;
- int flags;
- NfcEvent event = new NfcEvent(mAdapter, peerLlcpVersion);
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = findResumedActivityState();
- if (state == null) return null;
-
- ndefCallback = state.ndefMessageCallback;
- urisCallback = state.uriCallback;
- message = state.ndefMessage;
- uris = state.uris;
- flags = state.flags;
- activity = state.activity;
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- // Make callbacks without lock
- if (ndefCallback != null) {
- message = ndefCallback.createNdefMessage(event);
- }
- if (urisCallback != null) {
- uris = urisCallback.createBeamUris(event);
- if (uris != null) {
- ArrayList<Uri> validUris = new ArrayList<Uri>();
- for (Uri uri : uris) {
- if (uri == null) {
- Log.e(TAG, "Uri not allowed to be null.");
- continue;
- }
- String scheme = uri.getScheme();
- if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
- !scheme.equalsIgnoreCase("content"))) {
- Log.e(TAG, "Uri needs to have " +
- "either scheme file or scheme content");
- continue;
- }
- uri = ContentProvider.maybeAddUserId(uri, activity.getUserId());
- validUris.add(uri);
- }
-
- uris = validUris.toArray(new Uri[validUris.size()]);
- }
- }
- if (uris != null && uris.length > 0) {
- for (Uri uri : uris) {
- // Grant the NFC process permission to read these URIs
- activity.grantUriPermission("com.android.nfc", uri,
- Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- return new BeamShareData(message, uris, activity.getUser(), flags);
- }
-
- /** Callback from NFC service, usually on binder thread */
- @Override
- public void onNdefPushComplete(byte peerLlcpVersion) {
- NfcAdapter.OnNdefPushCompleteCallback callback;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = findResumedActivityState();
- if (state == null) return;
-
- callback = state.onNdefPushCompleteCallback;
- }
- NfcEvent event = new NfcEvent(mAdapter, peerLlcpVersion);
- // Make callback without lock
- if (callback != null) {
- callback.onNdefPushComplete(event);
- }
- }
-
@Override
public void onTagDiscovered(Tag tag) throws RemoteException {
NfcAdapter.ReaderCallback callback;
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 1bb44af81cec..4a244c0f87bb 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -343,8 +343,12 @@ public final class NfcAdapter {
*/
public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
- /** @hide */
+ /**
+ * @hide
+ * @removed
+ */
@SystemApi
+ @UnsupportedAppUsage
public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
/** @hide */
@@ -418,7 +422,6 @@ public final class NfcAdapter {
// Guarded by NfcAdapter.class
static boolean sIsInitialized = false;
static boolean sHasNfcFeature;
- static boolean sHasBeamFeature;
// Final after first constructor, except for
// attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
@@ -483,7 +486,7 @@ public final class NfcAdapter {
* A callback to be invoked when the system successfully delivers your {@link NdefMessage}
* to another device.
* @see #setOnNdefPushCompleteCallback
- * @deprecated this feature is deprecated. File sharing can work using other technology like
+ * @deprecated this feature is removed. File sharing can work using other technology like
* Bluetooth.
*/
@java.lang.Deprecated
@@ -509,7 +512,7 @@ public final class NfcAdapter {
* content currently visible to the user. Alternatively, you can call {@link
* #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the
* same data.
- * @deprecated this feature is deprecated. File sharing can work using other technology like
+ * @deprecated this feature is removed. File sharing can work using other technology like
* Bluetooth.
*/
@java.lang.Deprecated
@@ -539,7 +542,7 @@ public final class NfcAdapter {
/**
- * @deprecated this feature is deprecated. File sharing can work using other technology like
+ * @deprecated this feature is removed. File sharing can work using other technology like
* Bluetooth.
*/
@java.lang.Deprecated
@@ -615,7 +618,6 @@ public final class NfcAdapter {
PackageManager pm;
pm = context.getPackageManager();
sHasNfcFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC);
- sHasBeamFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC_BEAM);
boolean hasHceFeature =
pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
|| pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF);
@@ -1111,35 +1113,17 @@ public final class NfcAdapter {
* @param uris an array of Uri(s) to push over Android Beam
* @param activity activity for which the Uri(s) will be pushed
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @deprecated this feature is deprecated. File sharing can work using other technology like
+ * @removed this feature is removed. File sharing can work using other technology like
* Bluetooth.
*/
@java.lang.Deprecated
+ @UnsupportedAppUsage
public void setBeamPushUris(Uri[] uris, Activity activity) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- if (!sHasBeamFeature) {
- return;
- }
}
- if (activity == null) {
- throw new NullPointerException("activity cannot be null");
- }
- if (uris != null) {
- for (Uri uri : uris) {
- if (uri == null) throw new NullPointerException("Uri not " +
- "allowed to be null");
- String scheme = uri.getScheme();
- if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
- !scheme.equalsIgnoreCase("content"))) {
- throw new IllegalArgumentException("URI needs to have " +
- "either scheme file or scheme content");
- }
- }
- }
- mNfcActivityManager.setNdefPushContentUri(activity, uris);
}
/**
@@ -1199,23 +1183,17 @@ public final class NfcAdapter {
* @param callback callback, or null to disable
* @param activity activity for which the Uri(s) will be pushed
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @deprecated this feature is deprecated. File sharing can work using other technology like
+ * @removed this feature is removed. File sharing can work using other technology like
* Bluetooth.
*/
@java.lang.Deprecated
+ @UnsupportedAppUsage
public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- if (!sHasBeamFeature) {
- return;
- }
}
- if (activity == null) {
- throw new NullPointerException("activity cannot be null");
- }
- mNfcActivityManager.setNdefPushContentUriCallback(activity, callback);
}
/**
@@ -1289,58 +1267,32 @@ public final class NfcAdapter {
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @deprecated this feature is deprecated. File sharing can work using other technology like
+ * @removed this feature is removed. File sharing can work using other technology like
* Bluetooth.
*/
@java.lang.Deprecated
+ @UnsupportedAppUsage
public void setNdefPushMessage(NdefMessage message, Activity activity,
Activity ... activities) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- if (!sHasBeamFeature) {
- return;
- }
- }
- int targetSdkVersion = getSdkVersion();
- try {
- if (activity == null) {
- throw new NullPointerException("activity cannot be null");
- }
- mNfcActivityManager.setNdefPushMessage(activity, message, 0);
- for (Activity a : activities) {
- if (a == null) {
- throw new NullPointerException("activities cannot contain null");
- }
- mNfcActivityManager.setNdefPushMessage(a, message, 0);
- }
- } catch (IllegalStateException e) {
- if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
- // Less strict on old applications - just log the error
- Log.e(TAG, "Cannot call API with Activity that has already " +
- "been destroyed", e);
- } else {
- // Prevent new applications from making this mistake, re-throw
- throw(e);
- }
}
}
/**
* @hide
+ * @removed
*/
@SystemApi
+ @UnsupportedAppUsage
public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
}
- if (activity == null) {
- throw new NullPointerException("activity cannot be null");
- }
- mNfcActivityManager.setNdefPushMessage(activity, message, flags);
}
/**
@@ -1408,57 +1360,21 @@ public final class NfcAdapter {
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @deprecated this feature is deprecated. File sharing can work using other technology like
+ * @removed this feature is removed. File sharing can work using other technology like
* Bluetooth.
*/
@java.lang.Deprecated
+ @UnsupportedAppUsage
public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
Activity ... activities) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- if (!sHasBeamFeature) {
- return;
- }
- }
- int targetSdkVersion = getSdkVersion();
- try {
- if (activity == null) {
- throw new NullPointerException("activity cannot be null");
- }
- mNfcActivityManager.setNdefPushMessageCallback(activity, callback, 0);
- for (Activity a : activities) {
- if (a == null) {
- throw new NullPointerException("activities cannot contain null");
- }
- mNfcActivityManager.setNdefPushMessageCallback(a, callback, 0);
- }
- } catch (IllegalStateException e) {
- if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
- // Less strict on old applications - just log the error
- Log.e(TAG, "Cannot call API with Activity that has already " +
- "been destroyed", e);
- } else {
- // Prevent new applications from making this mistake, re-throw
- throw(e);
- }
}
}
/**
- * @hide
- */
- @UnsupportedAppUsage
- public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
- int flags) {
- if (activity == null) {
- throw new NullPointerException("activity cannot be null");
- }
- mNfcActivityManager.setNdefPushMessageCallback(activity, callback, flags);
- }
-
- /**
* Set a callback on successful Android Beam (TM).
*
* <p>This method may be called at any time before {@link Activity#onDestroy},
@@ -1495,41 +1411,17 @@ public final class NfcAdapter {
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @deprecated this feature is deprecated. File sharing can work using other technology like
+ * @removed this feature is removed. File sharing can work using other technology like
* Bluetooth.
*/
@java.lang.Deprecated
+ @UnsupportedAppUsage
public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
Activity activity, Activity ... activities) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- if (!sHasBeamFeature) {
- return;
- }
- }
- int targetSdkVersion = getSdkVersion();
- try {
- if (activity == null) {
- throw new NullPointerException("activity cannot be null");
- }
- mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callback);
- for (Activity a : activities) {
- if (a == null) {
- throw new NullPointerException("activities cannot contain null");
- }
- mNfcActivityManager.setOnNdefPushCompleteCallback(a, callback);
- }
- } catch (IllegalStateException e) {
- if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
- // Less strict on old applications - just log the error
- Log.e(TAG, "Cannot call API with Activity that has already " +
- "been destroyed", e);
- } else {
- // Prevent new applications from making this mistake, re-throw
- throw(e);
- }
}
}
@@ -1712,46 +1604,18 @@ public final class NfcAdapter {
* @param activity the current foreground Activity that has registered data to share
* @return whether the Beam animation was successfully invoked
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @deprecated this feature is deprecated. File sharing can work using other technology like
+ * @removed this feature is removed. File sharing can work using other technology like
* Bluetooth.
*/
@java.lang.Deprecated
+ @UnsupportedAppUsage
public boolean invokeBeam(Activity activity) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- if (!sHasBeamFeature) {
- return false;
- }
- }
- if (activity == null) {
- throw new NullPointerException("activity may not be null.");
- }
- enforceResumed(activity);
- try {
- sService.invokeBeam();
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "invokeBeam: NFC process has died.");
- attemptDeadServiceRecovery(e);
- return false;
- }
- }
-
- /**
- * @hide
- */
- public boolean invokeBeam(BeamShareData shareData) {
- try {
- Log.e(TAG, "invokeBeamInternal()");
- sService.invokeBeamInternal(shareData);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "invokeBeam: NFC process has died.");
- attemptDeadServiceRecovery(e);
- return false;
}
+ return false;
}
/**
@@ -1777,25 +1641,18 @@ public final class NfcAdapter {
*
* @param activity foreground activity
* @param message a NDEF Message to push over NFC
- * @throws IllegalStateException if the activity is not currently in the foreground
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @deprecated use {@link #setNdefPushMessage} instead
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
+ * @removed this feature is removed. File sharing can work using other technology like
+ * Bluetooth.
*/
@Deprecated
+ @UnsupportedAppUsage
public void enableForegroundNdefPush(Activity activity, NdefMessage message) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- if (!sHasBeamFeature) {
- return;
- }
}
- if (activity == null || message == null) {
- throw new NullPointerException();
- }
- enforceResumed(activity);
- mNfcActivityManager.setNdefPushMessage(activity, message, 0);
}
/**
@@ -1814,27 +1671,18 @@ public final class NfcAdapter {
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param activity the Foreground activity
- * @throws IllegalStateException if the Activity has already been paused
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @deprecated use {@link #setNdefPushMessage} instead
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
+ * @removed this feature is removed. File sharing can work using other technology like
+ * Bluetooth.
*/
@Deprecated
+ @UnsupportedAppUsage
public void disableForegroundNdefPush(Activity activity) {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- if (!sHasBeamFeature) {
- return;
- }
}
- if (activity == null) {
- throw new NullPointerException();
- }
- enforceResumed(activity);
- mNfcActivityManager.setNdefPushMessage(activity, null, 0);
- mNfcActivityManager.setNdefPushMessageCallback(activity, null, 0);
- mNfcActivityManager.setOnNdefPushCompleteCallback(activity, null);
}
/**
@@ -1959,40 +1807,26 @@ public final class NfcAdapter {
* Enable NDEF Push feature.
* <p>This API is for the Settings application.
* @hide
+ * @removed
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @UnsupportedAppUsage
public boolean enableNdefPush() {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- try {
- return sService.enableNdefPush();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- return false;
- }
+ return false;
}
/**
* Disable NDEF Push feature.
* <p>This API is for the Settings application.
* @hide
+ * @removed
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ @UnsupportedAppUsage
public boolean disableNdefPush() {
- synchronized (NfcAdapter.class) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- try {
- return sService.disableNdefPush();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- return false;
- }
+ return false;
}
/**
@@ -2018,26 +1852,18 @@ public final class NfcAdapter {
* @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
* @return true if NDEF Push feature is enabled
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @deprecated this feature is deprecated. File sharing can work using other technology like
+ * @removed this feature is removed. File sharing can work using other technology like
* Bluetooth.
*/
@java.lang.Deprecated
-
+ @UnsupportedAppUsage
public boolean isNdefPushEnabled() {
synchronized (NfcAdapter.class) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
- if (!sHasBeamFeature) {
- return false;
- }
- }
- try {
- return sService.isNdefPushEnabled();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- return false;
}
+ return false;
}
/**
@@ -2128,17 +1954,6 @@ public final class NfcAdapter {
}
/**
- * @hide
- */
- public void setP2pModes(int initiatorModes, int targetModes) {
- try {
- sService.setP2pModes(initiatorModes, targetModes);
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- }
- }
-
- /**
* Registers a new NFC unlock handler with the NFC service.
*
* <p />NFC unlock handlers are intended to unlock the keyguard in the presence of a trusted
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 832f23cdb3e2..9689be25ce84 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -787,12 +787,9 @@ public class Build {
* PackageManager.setComponentEnabledSetting} will now throw an
* IllegalArgumentException if the given component class name does not
* exist in the application's manifest.
- * <li> {@link android.nfc.NfcAdapter#setNdefPushMessage
- * NfcAdapter.setNdefPushMessage},
- * {@link android.nfc.NfcAdapter#setNdefPushMessageCallback
- * NfcAdapter.setNdefPushMessageCallback} and
- * {@link android.nfc.NfcAdapter#setOnNdefPushCompleteCallback
- * NfcAdapter.setOnNdefPushCompleteCallback} will throw
+ * <li> {@code NfcAdapter.setNdefPushMessage},
+ * {@code NfcAdapter.setNdefPushMessageCallback} and
+ * {@code NfcAdapter.setOnNdefPushCompleteCallback} will throw
* IllegalStateException if called after the Activity has been destroyed.
* <li> Accessibility services must require the new
* {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission or
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 2142c4c625fe..13d54ef7b12a 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -2994,6 +2994,7 @@ public final class PowerManager {
*/
@IntDef(prefix = { "LOW_POWER_STANDBY_ALLOWED_REASON_" }, flag = true, value = {
LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION,
+ LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST,
})
@Retention(RetentionPolicy.SOURCE)
public @interface LowPowerStandbyAllowedReason {
@@ -3006,6 +3007,13 @@ public final class PowerManager {
*/
public static final int LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION = 1 << 0;
+ /**
+ * Exempts apps on the temporary powersave allowlist.
+ *
+ * @see #isAllowedInLowPowerStandby(int)
+ */
+ public static final int LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST = 1 << 1;
+
/** @hide */
public static String lowPowerStandbyAllowedReasonsToString(
@LowPowerStandbyAllowedReason int allowedReasons) {
@@ -3014,6 +3022,10 @@ public final class PowerManager {
allowedStrings.add("ALLOWED_REASON_VOICE_INTERACTION");
allowedReasons &= ~LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION;
}
+ if ((allowedReasons & LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST) != 0) {
+ allowedStrings.add("ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST");
+ allowedReasons &= ~LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST;
+ }
if (allowedReasons != 0) {
allowedStrings.add(String.valueOf(allowedReasons));
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1df45d132f34..c60f55868c00 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3612,7 +3612,7 @@ public class UserManager {
*
* <p>Requires {@link android.Manifest.permission#MANAGE_USERS}.
* {@link android.Manifest.permission#CREATE_USERS} suffices if flags are in
- * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION}.
+ * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION.
*
* @param name the user's name
* @param userType the type of user, such as {@link UserManager#USER_TYPE_FULL_GUEST}.
@@ -3686,7 +3686,7 @@ public class UserManager {
*
* <p>Requires {@link android.Manifest.permission#MANAGE_USERS}.
* {@link android.Manifest.permission#CREATE_USERS} suffices if flags are in
- * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION}.
+ * com.android.server.pm.UserManagerService#ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION.
*
* @param userType the type of user, such as {@link UserManager#USER_TYPE_FULL_GUEST}.
* @return the {@link UserInfo} object for the created user.
@@ -3718,25 +3718,23 @@ public class UserManager {
*/
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
- public UserInfo createGuest(Context context) {
+ public @Nullable UserInfo createGuest(Context context) {
try {
final UserInfo guest = mService.createUserWithThrow(null, USER_TYPE_FULL_GUEST, 0);
- if (guest != null) {
- Settings.Secure.putStringForUser(context.getContentResolver(),
- Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
-
- if (UserManager.isGuestUserAllowEphemeralStateChange()) {
- // Mark guest as (changeably) ephemeral if REMOVE_GUEST_ON_EXIT is 1
- // This is done so that a user via a UI controller can choose to
- // make a guest as ephemeral or not.
- // Settings.Global.REMOVE_GUEST_ON_EXIT holds the choice on what the guest state
- // should be, with default being ephemeral.
- boolean resetGuestOnExit = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.REMOVE_GUEST_ON_EXIT, 1) == 1;
-
- if (resetGuestOnExit && !guest.isEphemeral()) {
- setUserEphemeral(guest.id, true);
- }
+ Settings.Secure.putStringForUser(context.getContentResolver(),
+ Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
+
+ if (UserManager.isGuestUserAllowEphemeralStateChange()) {
+ // Mark guest as (changeably) ephemeral if REMOVE_GUEST_ON_EXIT is 1
+ // This is done so that a user via a UI controller can choose to
+ // make a guest as ephemeral or not.
+ // Settings.Global.REMOVE_GUEST_ON_EXIT holds the choice on what the guest state
+ // should be, with default being ephemeral.
+ boolean resetGuestOnExit = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.REMOVE_GUEST_ON_EXIT, 1) == 1;
+
+ if (resetGuestOnExit && !guest.isEphemeral()) {
+ setUserEphemeral(guest.id, true);
}
}
return guest;
@@ -3855,7 +3853,7 @@ public class UserManager {
*/
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
- public UserInfo createProfileForUser(String name, @NonNull String userType,
+ public @Nullable UserInfo createProfileForUser(String name, @NonNull String userType,
@UserInfoFlag int flags, @UserIdInt int userId) {
return createProfileForUser(name, userType, flags, userId, null);
}
@@ -3900,7 +3898,7 @@ public class UserManager {
*/
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
- public UserInfo createProfileForUserEvenWhenDisallowed(String name,
+ public @Nullable UserInfo createProfileForUserEvenWhenDisallowed(String name,
@NonNull String userType, @UserInfoFlag int flags, @UserIdInt int userId,
String[] disallowedPackages) {
try {
@@ -3931,11 +3929,9 @@ public class UserManager {
try {
final int parentUserId = mUserId;
final UserInfo profile = mService.createRestrictedProfileWithThrow(name, parentUserId);
- if (profile != null) {
- final UserHandle parentUserHandle = UserHandle.of(parentUserId);
- AccountManager.get(mContext).addSharedAccountsFromParentUser(parentUserHandle,
- UserHandle.of(profile.id));
- }
+ final UserHandle parentUserHandle = UserHandle.of(parentUserId);
+ AccountManager.get(mContext).addSharedAccountsFromParentUser(parentUserHandle,
+ UserHandle.of(profile.id));
return profile;
} catch (ServiceSpecificException e) {
return null;
diff --git a/core/java/android/provider/DeviceConfigInitializer.java b/core/java/android/provider/DeviceConfigInitializer.java
new file mode 100644
index 000000000000..d60449f800d5
--- /dev/null
+++ b/core/java/android/provider/DeviceConfigInitializer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+import java.util.Objects;
+
+/**
+ * Class that will hold an instance of {@link DeviceConfigServiceManager}
+ * which is used by {@link DeviceConfig} to retrieve an instance of the service.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public class DeviceConfigInitializer {
+ private static DeviceConfigServiceManager sDeviceConfigServiceManager;
+
+ private static final Object sLock = new Object();
+
+ private DeviceConfigInitializer() {
+ // fully static class
+ }
+
+ /**
+ * Setter for {@link DeviceConfigServiceManager}. Should be called only once.
+ *
+ */
+ public static void setDeviceConfigServiceManager(
+ @NonNull DeviceConfigServiceManager serviceManager) {
+ synchronized (sLock) {
+ if (sDeviceConfigServiceManager != null) {
+ throw new IllegalStateException("setDeviceConfigServiceManager called twice!");
+ }
+ Objects.requireNonNull(serviceManager, "serviceManager must not be null");
+
+ sDeviceConfigServiceManager = serviceManager;
+ }
+ }
+
+ /**
+ * Getter for {@link DeviceConfigServiceManager}.
+ *
+ */
+ @Nullable
+ public static DeviceConfigServiceManager getDeviceConfigServiceManager() {
+ synchronized (sLock) {
+ return sDeviceConfigServiceManager;
+ }
+ }
+}
diff --git a/core/java/android/provider/DeviceConfigServiceManager.java b/core/java/android/provider/DeviceConfigServiceManager.java
new file mode 100644
index 000000000000..c362c37954c0
--- /dev/null
+++ b/core/java/android/provider/DeviceConfigServiceManager.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * Service Manager for the {@code android.provider.DeviceConfig} service.
+ *
+ * <p>Used to be able to get an instance of the service in places that don't have access to a
+ * {@code Context}
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public class DeviceConfigServiceManager {
+
+ /**
+ * @hide
+ */
+ public DeviceConfigServiceManager() {
+ }
+
+ /**
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final class ServiceRegisterer {
+ private final String mServiceName;
+
+ /**
+ * @hide
+ */
+ public ServiceRegisterer(String serviceName) {
+ mServiceName = serviceName;
+ }
+
+ /**
+ * Register a system server binding object for a service.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void register(@NonNull IBinder service) {
+ ServiceManager.addService(mServiceName, service);
+ }
+
+ /**
+ * Get the system server binding object for a service.
+ *
+ * <p>This blocks until the service instance is ready,
+ * or a timeout happens, in which case it returns null.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @Nullable
+ public IBinder get() {
+ return ServiceManager.getService(mServiceName);
+ }
+
+ /**
+ * Get the system server binding object for a service.
+ *
+ * <p>This blocks until the service instance is ready,
+ * or a timeout happens, in which case it throws {@link ServiceNotFoundException}.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public IBinder getOrThrow() throws ServiceNotFoundException {
+ try {
+ return ServiceManager.getServiceOrThrow(mServiceName);
+ } catch (ServiceManager.ServiceNotFoundException e) {
+ throw new ServiceNotFoundException(mServiceName);
+ }
+ }
+
+ /**
+ * Get the system server binding object for a service. If the specified service is
+ * not available, it returns null.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @Nullable
+ public IBinder tryGet() {
+ return ServiceManager.checkService(mServiceName);
+ }
+
+ }
+
+ /**
+ * See {@link ServiceRegisterer#getOrThrow}.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static class ServiceNotFoundException extends ServiceManager.ServiceNotFoundException {
+ /**
+ * Constructor.
+ *
+ * @param name the name of the binder service that cannot be found.
+ *
+ * @hide
+ */
+ public ServiceNotFoundException(@NonNull String name) {
+ super(name);
+ }
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the device config service that
+ * is updatable via mainline.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public ServiceRegisterer getDeviceConfigUpdatableServiceRegisterer() {
+ return new ServiceRegisterer("device_config_updatable");
+ }
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e0c022f9204d..563adf83e479 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1716,7 +1716,6 @@ public final class Settings {
* Input: Nothing.
* <p>
* Output: Nothing
- * @see android.nfc.NfcAdapter#isNdefPushEnabled()
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_NFCSHARING_SETTINGS =
diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java
index cdcd65910974..a8fcf865bceb 100644
--- a/core/java/android/service/autofill/InlineSuggestionRenderService.java
+++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java
@@ -166,7 +166,7 @@ public abstract class InlineSuggestionRenderService extends Service {
PixelFormat.TRANSPARENT);
final SurfaceControlViewHost host = new SurfaceControlViewHost(this, getDisplay(),
- hostInputToken);
+ hostInputToken, "InlineSuggestionRenderService");
host.setView(suggestionRoot, lp);
// Set the suggestion view to be non-focusable so that if its background is set to a
diff --git a/core/java/android/service/games/GameSessionService.java b/core/java/android/service/games/GameSessionService.java
index 52c8ec3d4018..f84442344567 100644
--- a/core/java/android/service/games/GameSessionService.java
+++ b/core/java/android/service/games/GameSessionService.java
@@ -125,7 +125,7 @@ public abstract class GameSessionService extends Service {
final Context windowContext = createWindowContext(display,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, /*options=*/ null);
SurfaceControlViewHost surfaceControlViewHost =
- new SurfaceControlViewHost(windowContext, display, hostToken);
+ new SurfaceControlViewHost(windowContext, display, hostToken, "GameSessionService");
gameSession.attach(
gameSessionController,
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 38076858084c..9696dbcc421b 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -51,8 +51,17 @@ public final class Adjustment implements Parcelable {
/** @hide */
@StringDef (prefix = { "KEY_" }, value = {
- KEY_CONTEXTUAL_ACTIONS, KEY_GROUP_KEY, KEY_IMPORTANCE, KEY_PEOPLE, KEY_SNOOZE_CRITERIA,
- KEY_TEXT_REPLIES, KEY_USER_SENTIMENT, KEY_IMPORTANCE_PROPOSAL, KEY_SENSITIVE_CONTENT
+ KEY_PEOPLE,
+ KEY_SNOOZE_CRITERIA,
+ KEY_GROUP_KEY,
+ KEY_USER_SENTIMENT,
+ KEY_CONTEXTUAL_ACTIONS,
+ KEY_TEXT_REPLIES,
+ KEY_IMPORTANCE,
+ KEY_IMPORTANCE_PROPOSAL,
+ KEY_SENSITIVE_CONTENT,
+ KEY_RANKING_SCORE,
+ KEY_NOT_CONVERSATION
})
@Retention(RetentionPolicy.SOURCE)
public @interface Keys {}
@@ -65,6 +74,7 @@ public final class Adjustment implements Parcelable {
*/
@SystemApi
public static final String KEY_PEOPLE = "key_people";
+
/**
* Parcelable {@code ArrayList} of {@link SnoozeCriterion}. These criteria may be visible to
* users. If a user chooses to snooze a notification until one of these criterion, the
@@ -72,6 +82,7 @@ public final class Adjustment implements Parcelable {
* {@link NotificationAssistantService#onNotificationSnoozedUntilContext}.
*/
public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
+
/**
* Data type: String. Used to change what {@link Notification#getGroup() group} a notification
* belongs to.
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index b384b66bf680..37a91e720aad 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -58,6 +58,7 @@ oneway interface INotificationListener
void onSuggestedReplySent(String key, in CharSequence reply, int source);
void onActionClicked(String key, in Notification.Action action, int source);
void onNotificationClicked(String key);
+ // @deprecated changing allowed adjustments is no longer supported.
void onAllowedAdjustmentsChanged();
void onNotificationFeedbackReceived(String key, in NotificationRankingUpdate update, in Bundle feedback);
}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index a38ef9676072..76889dfc300a 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -293,7 +293,10 @@ public abstract class NotificationAssistantService extends NotificationListenerS
* their notifications the assistant can modify.
* <p> Query {@link NotificationManager#getAllowedAssistantAdjustments()} to see what
* {@link Adjustment adjustments} you are currently allowed to make.</p>
+ *
+ * @deprecated changing allowed adjustments is no longer supported.
*/
+ @Deprecated
public void onAllowedAdjustmentsChanged() {
}
diff --git a/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java b/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java
index 9292e9608261..59e3a5e70376 100644
--- a/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java
+++ b/core/java/android/service/selectiontoolbar/RemoteSelectionToolbar.java
@@ -275,7 +275,7 @@ final class RemoteSelectionToolbar {
mHostInputToken, mTransferTouchListener);
contentHolder.addView(mContentContainer);
mSurfaceControlViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(),
- mHostInputToken);
+ mHostInputToken, "RemoteSelectionToolbar");
mSurfaceControlViewHost.setView(contentHolder, mPopupWidth, mPopupHeight);
}
if (mSurfacePackage == null) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 23513fad2a53..120e8711e607 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -45,7 +45,6 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
-import android.content.res.TypedArray;
import android.graphics.BLASTBufferQueue;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -1153,11 +1152,6 @@ public abstract class WallpaperService extends Service {
mLayout.token = mWindowToken;
if (!mCreated) {
- // Retrieve watch round info
- TypedArray windowStyle = obtainStyledAttributes(
- com.android.internal.R.styleable.Window);
- windowStyle.recycle();
-
// Add window
mLayout.type = mIWallpaperEngine.mWindowType;
mLayout.gravity = Gravity.START|Gravity.TOP;
diff --git a/core/java/android/nfc/BeamShareData.aidl b/core/java/android/speech/RecognitionPart.aidl
index a47e24057a54..f7754a28e823 100644
--- a/core/java/android/nfc/BeamShareData.aidl
+++ b/core/java/android/speech/RecognitionPart.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.nfc;
+package android.speech;
-parcelable BeamShareData;
+parcelable RecognitionPart;
diff --git a/core/java/android/speech/RecognitionPart.java b/core/java/android/speech/RecognitionPart.java
new file mode 100644
index 000000000000..e551cdc9f21f
--- /dev/null
+++ b/core/java/android/speech/RecognitionPart.java
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Info about a single recognition part.
+ *
+ * <p> A recognition part represents a recognized word or character, as well as any potential
+ * adjacent punctuation, that is returned by the {@link SpeechRecognizer}.
+ *
+ * <p> Each recognition part is described with a {@link String} denoting the raw text.
+ * Additionally, if formatting is enabled with {@link RecognizerIntent#EXTRA_ENABLE_FORMATTING},
+ * another {@link String} representation exists denoting the formatted text.
+ *
+ * <p> If the timestamps are requested with {@link RecognizerIntent#EXTRA_REQUEST_WORD_TIMING}, each
+ * recognition part will contain a value representing the offset of the beginning of this part from
+ * the start of the recognition session in milliseconds.
+ *
+ * <p> If the confidence levels are requested with
+ * {@link RecognizerIntent#EXTRA_REQUEST_WORD_CONFIDENCE}, each recognition part will contain
+ * a value describing the level of recognition confidence.
+ */
+@DataClass(
+ genBuilder = true,
+ genEqualsHashCode = true,
+ genHiddenConstDefs = true,
+ genToString = true)
+public final class RecognitionPart implements Parcelable {
+
+ /** Confidence level not requested. */
+ public static final int CONFIDENCE_LEVEL_UNKNOWN = 0;
+
+ /** Lowest level of confidence out of five levels. */
+ public static final int CONFIDENCE_LEVEL_LOW = 1;
+
+ /** Second-lowest level of confidence out of five levels. */
+ public static final int CONFIDENCE_LEVEL_LOW_MEDIUM = 2;
+
+ /** Medium level of confidence out of five levels. */
+ public static final int CONFIDENCE_LEVEL_MEDIUM = 3;
+
+ /** Second-highest level of confidence out of five levels. */
+ public static final int CONFIDENCE_LEVEL_MEDIUM_HIGH = 4;
+
+ /** Highest level of confidence out of five levels. */
+ public static final int CONFIDENCE_LEVEL_HIGH = 5;
+
+ /** The {@code non-null} raw text version of the recognized part of the result. */
+ @NonNull
+ private final String mRawText;
+
+ /**
+ * The formatted text version of the recognized part of the result. If formatting is enabled
+ * with {@link RecognizerIntent#EXTRA_ENABLE_FORMATTING}, it has a {@code non-null} value.
+ *
+ * <p> Otherwise, it should be {@code null} by default.
+ */
+ @Nullable
+ private final String mFormattedText;
+ private static String defaultFormattedText() {
+ return null;
+ }
+
+ /**
+ * Non-negative offset of the beginning of this part from
+ * the start of the recognition session in milliseconds
+ * if requested with {@link RecognizerIntent#EXTRA_REQUEST_WORD_TIMING}.
+ *
+ * <p> Otherwise, this should equal 0.
+ */
+ private final long mTimestampMillis;
+ private static long defaultTimestampMillis() {
+ return 0;
+ }
+
+ /**
+ * The level of confidence for this part if requested
+ * with {@link RecognizerIntent#EXTRA_REQUEST_WORD_CONFIDENCE}.
+ *
+ * <p> Otherwise, this should equal {@link #CONFIDENCE_LEVEL_UNKNOWN}.
+ */
+ @ConfidenceLevel
+ private final int mConfidenceLevel;
+ @ConfidenceLevel
+ private static int defaultConfidenceLevel() {
+ return CONFIDENCE_LEVEL_UNKNOWN;
+ }
+
+ private void onConstructed() {
+ Preconditions.checkArgumentNonnegative(mTimestampMillis,
+ "The timestamp must be non-negative.");
+ }
+
+ @DataClass.Suppress("setFormattedText")
+ abstract static class BaseBuilder {
+ /**
+ * The formatted text version of the recognized part of the result. If formatting is enabled
+ * with {@link RecognizerIntent#EXTRA_ENABLE_FORMATTING}, it has a {@code non-null} value.
+ *
+ * <p> Otherwise, it should be {@code null} by default.
+ */
+ @NonNull
+ public Builder setFormattedText(@NonNull String value) {
+ // Method explicitly defined, so that the argument can be checked for non-null.
+ com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, value);
+
+ final Builder builder = (Builder) this;
+ builder.checkNotUsed();
+ builder.mBuilderFieldsSet |= 0x2;
+ builder.mFormattedText = value;
+ return builder;
+ }
+ }
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/speech/RecognitionPart.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /** @hide */
+ @android.annotation.IntDef(prefix = "CONFIDENCE_LEVEL_", value = {
+ CONFIDENCE_LEVEL_UNKNOWN,
+ CONFIDENCE_LEVEL_LOW,
+ CONFIDENCE_LEVEL_LOW_MEDIUM,
+ CONFIDENCE_LEVEL_MEDIUM,
+ CONFIDENCE_LEVEL_MEDIUM_HIGH,
+ CONFIDENCE_LEVEL_HIGH
+ })
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface ConfidenceLevel {}
+
+ /** @hide */
+ @DataClass.Generated.Member
+ public static String confidenceLevelToString(@ConfidenceLevel int value) {
+ switch (value) {
+ case CONFIDENCE_LEVEL_UNKNOWN:
+ return "CONFIDENCE_LEVEL_UNKNOWN";
+ case CONFIDENCE_LEVEL_LOW:
+ return "CONFIDENCE_LEVEL_LOW";
+ case CONFIDENCE_LEVEL_LOW_MEDIUM:
+ return "CONFIDENCE_LEVEL_LOW_MEDIUM";
+ case CONFIDENCE_LEVEL_MEDIUM:
+ return "CONFIDENCE_LEVEL_MEDIUM";
+ case CONFIDENCE_LEVEL_MEDIUM_HIGH:
+ return "CONFIDENCE_LEVEL_MEDIUM_HIGH";
+ case CONFIDENCE_LEVEL_HIGH:
+ return "CONFIDENCE_LEVEL_HIGH";
+ default: return Integer.toHexString(value);
+ }
+ }
+
+ @DataClass.Generated.Member
+ /* package-private */ RecognitionPart(
+ @NonNull String rawText,
+ @Nullable String formattedText,
+ long timestampMillis,
+ @ConfidenceLevel int confidenceLevel) {
+ this.mRawText = rawText;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mRawText);
+ this.mFormattedText = formattedText;
+ this.mTimestampMillis = timestampMillis;
+ this.mConfidenceLevel = confidenceLevel;
+
+ if (!(mConfidenceLevel == CONFIDENCE_LEVEL_UNKNOWN)
+ && !(mConfidenceLevel == CONFIDENCE_LEVEL_LOW)
+ && !(mConfidenceLevel == CONFIDENCE_LEVEL_LOW_MEDIUM)
+ && !(mConfidenceLevel == CONFIDENCE_LEVEL_MEDIUM)
+ && !(mConfidenceLevel == CONFIDENCE_LEVEL_MEDIUM_HIGH)
+ && !(mConfidenceLevel == CONFIDENCE_LEVEL_HIGH)) {
+ throw new java.lang.IllegalArgumentException(
+ "confidenceLevel was " + mConfidenceLevel + " but must be one of: "
+ + "CONFIDENCE_LEVEL_UNKNOWN(" + CONFIDENCE_LEVEL_UNKNOWN + "), "
+ + "CONFIDENCE_LEVEL_LOW(" + CONFIDENCE_LEVEL_LOW + "), "
+ + "CONFIDENCE_LEVEL_LOW_MEDIUM(" + CONFIDENCE_LEVEL_LOW_MEDIUM + "), "
+ + "CONFIDENCE_LEVEL_MEDIUM(" + CONFIDENCE_LEVEL_MEDIUM + "), "
+ + "CONFIDENCE_LEVEL_MEDIUM_HIGH(" + CONFIDENCE_LEVEL_MEDIUM_HIGH + "), "
+ + "CONFIDENCE_LEVEL_HIGH(" + CONFIDENCE_LEVEL_HIGH + ")");
+ }
+
+
+ onConstructed();
+ }
+
+ /**
+ * The {@code non-null} raw text version of the recognized part of the result.
+ */
+ @DataClass.Generated.Member
+ public @NonNull String getRawText() {
+ return mRawText;
+ }
+
+ /**
+ * The formatted text version of the recognized part of the result. If formatting is enabled
+ * with {@link RecognizerIntent#EXTRA_ENABLE_FORMATTING}, it has a {@code non-null} value.
+ *
+ * <p> Otherwise, it should be {@code null} by default.
+ */
+ @DataClass.Generated.Member
+ public @Nullable String getFormattedText() {
+ return mFormattedText;
+ }
+
+ /**
+ * Non-negative offset of the beginning of this part from
+ * the start of the recognition session in milliseconds
+ * if requested with {@link RecognizerIntent#EXTRA_REQUEST_WORD_TIMING}.
+ *
+ * <p> Otherwise, this should equal 0.
+ */
+ @DataClass.Generated.Member
+ public long getTimestampMillis() {
+ return mTimestampMillis;
+ }
+
+ /**
+ * The level of confidence for this part if requested
+ * with {@link RecognizerIntent#EXTRA_REQUEST_WORD_CONFIDENCE}.
+ *
+ * <p> Otherwise, this should equal {@link #CONFIDENCE_LEVEL_UNKNOWN}.
+ */
+ @DataClass.Generated.Member
+ public @ConfidenceLevel int getConfidenceLevel() {
+ return mConfidenceLevel;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "RecognitionPart { " +
+ "rawText = " + mRawText + ", " +
+ "formattedText = " + mFormattedText + ", " +
+ "timestampMillis = " + mTimestampMillis + ", " +
+ "confidenceLevel = " + confidenceLevelToString(mConfidenceLevel) +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(RecognitionPart other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ RecognitionPart that = (RecognitionPart) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && java.util.Objects.equals(mRawText, that.mRawText)
+ && java.util.Objects.equals(mFormattedText, that.mFormattedText)
+ && mTimestampMillis == that.mTimestampMillis
+ && mConfidenceLevel == that.mConfidenceLevel;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + java.util.Objects.hashCode(mRawText);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mFormattedText);
+ _hash = 31 * _hash + Long.hashCode(mTimestampMillis);
+ _hash = 31 * _hash + mConfidenceLevel;
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ byte flg = 0;
+ if (mFormattedText != null) flg |= 0x2;
+ dest.writeByte(flg);
+ dest.writeString(mRawText);
+ if (mFormattedText != null) dest.writeString(mFormattedText);
+ dest.writeLong(mTimestampMillis);
+ dest.writeInt(mConfidenceLevel);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ RecognitionPart(@NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ String rawText = in.readString();
+ String formattedText = (flg & 0x2) == 0 ? null : in.readString();
+ long timestampMillis = in.readLong();
+ int confidenceLevel = in.readInt();
+
+ this.mRawText = rawText;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mRawText);
+ this.mFormattedText = formattedText;
+ this.mTimestampMillis = timestampMillis;
+ this.mConfidenceLevel = confidenceLevel;
+
+ if (!(mConfidenceLevel == CONFIDENCE_LEVEL_UNKNOWN)
+ && !(mConfidenceLevel == CONFIDENCE_LEVEL_LOW)
+ && !(mConfidenceLevel == CONFIDENCE_LEVEL_LOW_MEDIUM)
+ && !(mConfidenceLevel == CONFIDENCE_LEVEL_MEDIUM)
+ && !(mConfidenceLevel == CONFIDENCE_LEVEL_MEDIUM_HIGH)
+ && !(mConfidenceLevel == CONFIDENCE_LEVEL_HIGH)) {
+ throw new java.lang.IllegalArgumentException(
+ "confidenceLevel was " + mConfidenceLevel + " but must be one of: "
+ + "CONFIDENCE_LEVEL_UNKNOWN(" + CONFIDENCE_LEVEL_UNKNOWN + "), "
+ + "CONFIDENCE_LEVEL_LOW(" + CONFIDENCE_LEVEL_LOW + "), "
+ + "CONFIDENCE_LEVEL_LOW_MEDIUM(" + CONFIDENCE_LEVEL_LOW_MEDIUM + "), "
+ + "CONFIDENCE_LEVEL_MEDIUM(" + CONFIDENCE_LEVEL_MEDIUM + "), "
+ + "CONFIDENCE_LEVEL_MEDIUM_HIGH(" + CONFIDENCE_LEVEL_MEDIUM_HIGH + "), "
+ + "CONFIDENCE_LEVEL_HIGH(" + CONFIDENCE_LEVEL_HIGH + ")");
+ }
+
+
+ onConstructed();
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<RecognitionPart> CREATOR
+ = new Parcelable.Creator<RecognitionPart>() {
+ @Override
+ public RecognitionPart[] newArray(int size) {
+ return new RecognitionPart[size];
+ }
+
+ @Override
+ public RecognitionPart createFromParcel(@NonNull android.os.Parcel in) {
+ return new RecognitionPart(in);
+ }
+ };
+
+ /**
+ * A builder for {@link RecognitionPart}
+ */
+ @SuppressWarnings("WeakerAccess")
+ @DataClass.Generated.Member
+ public static final class Builder extends BaseBuilder {
+
+ private @NonNull String mRawText;
+ private @Nullable String mFormattedText;
+ private long mTimestampMillis;
+ private @ConfidenceLevel int mConfidenceLevel;
+
+ private long mBuilderFieldsSet = 0L;
+
+ /**
+ * Creates a new Builder.
+ *
+ * @param rawText
+ * The {@code non-null} raw text version of the recognized part of the result.
+ */
+ public Builder(
+ @NonNull String rawText) {
+ mRawText = rawText;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mRawText);
+ }
+
+ /**
+ * The {@code non-null} raw text version of the recognized part of the result.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setRawText(@NonNull String value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x1;
+ mRawText = value;
+ return this;
+ }
+
+ /**
+ * Non-negative offset of the beginning of this part from
+ * the start of the recognition session in milliseconds
+ * if requested with {@link RecognizerIntent#EXTRA_REQUEST_WORD_TIMING}.
+ *
+ * <p> Otherwise, this should equal 0.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setTimestampMillis(long value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x4;
+ mTimestampMillis = value;
+ return this;
+ }
+
+ /**
+ * The level of confidence for this part if requested
+ * with {@link RecognizerIntent#EXTRA_REQUEST_WORD_CONFIDENCE}.
+ *
+ * <p> Otherwise, this should equal {@link #CONFIDENCE_LEVEL_UNKNOWN}.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setConfidenceLevel(@ConfidenceLevel int value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x8;
+ mConfidenceLevel = value;
+ return this;
+ }
+
+ /** Builds the instance. This builder should not be touched after calling this! */
+ public @NonNull RecognitionPart build() {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x10; // Mark builder used
+
+ if ((mBuilderFieldsSet & 0x2) == 0) {
+ mFormattedText = defaultFormattedText();
+ }
+ if ((mBuilderFieldsSet & 0x4) == 0) {
+ mTimestampMillis = defaultTimestampMillis();
+ }
+ if ((mBuilderFieldsSet & 0x8) == 0) {
+ mConfidenceLevel = defaultConfidenceLevel();
+ }
+ RecognitionPart o = new RecognitionPart(
+ mRawText,
+ mFormattedText,
+ mTimestampMillis,
+ mConfidenceLevel);
+ return o;
+ }
+
+ private void checkNotUsed() {
+ if ((mBuilderFieldsSet & 0x10) != 0) {
+ throw new IllegalStateException(
+ "This Builder should not be reused. Use a new Builder instance instead");
+ }
+ }
+ }
+
+ @DataClass.Generated(
+ time = 1676294616910L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/speech/RecognitionPart.java",
+ inputSignatures = "public static final int CONFIDENCE_LEVEL_UNKNOWN\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\nprivate final @android.annotation.NonNull java.lang.String mRawText\nprivate final @android.annotation.Nullable java.lang.String mFormattedText\nprivate final long mTimestampMillis\nprivate final @android.speech.RecognitionPart.ConfidenceLevel int mConfidenceLevel\nprivate static java.lang.String defaultFormattedText()\nprivate static long defaultTimestampMillis()\nprivate static @android.speech.RecognitionPart.ConfidenceLevel int defaultConfidenceLevel()\nprivate void onConstructed()\nclass RecognitionPart extends java.lang.Object implements [android.os.Parcelable]\npublic @android.annotation.NonNull android.speech.RecognitionPart.Builder setFormattedText(java.lang.String)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genToString=true)\npublic @android.annotation.NonNull android.speech.RecognitionPart.Builder setFormattedText(java.lang.String)\nclass BaseBuilder extends java.lang.Object implements []")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index 1cc772ac4455..a5dbdd7ce89a 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -142,6 +142,10 @@ public abstract class RecognitionService extends Service {
if (preflightPermissionCheckPassed) {
currentCallback = new Callback(listener, attributionSource);
sessionState = new SessionState(currentCallback);
+ mSessions.put(listener.asBinder(), sessionState);
+ if (DBG) {
+ Log.d(TAG, "Added a new session to the map, pending permission checks");
+ }
RecognitionService.this.onStartListening(intent, currentCallback);
}
@@ -151,16 +155,12 @@ public abstract class RecognitionService extends Service {
if (preflightPermissionCheckPassed) {
// If start listening was attempted, cancel the callback.
RecognitionService.this.onCancel(currentCallback);
+ mSessions.remove(listener.asBinder());
finishDataDelivery(sessionState);
sessionState.reset();
}
Log.i(TAG, "#startListening received from a caller "
+ "without permission " + Manifest.permission.RECORD_AUDIO + ".");
- } else {
- if (DBG) {
- Log.d(TAG, "Added a new session to the map.");
- }
- mSessions.put(listener.asBinder(), sessionState);
}
} else {
listener.onError(SpeechRecognizer.ERROR_CLIENT);
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index cd18c19ddf3f..7127fa1fd657 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -558,4 +558,18 @@ public class RecognizerIntent {
* @see #EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS
*/
public static final String EXTRA_SEGMENTED_SESSION = "android.speech.extra.SEGMENTED_SESSION";
+
+ /**
+ * Optional boolean indicating whether the recognizer should return the timestamp
+ * of each word in the final recognition results.
+ */
+ public static final String EXTRA_REQUEST_WORD_TIMING =
+ "android.speech.extra.REQUEST_WORD_TIMING";
+
+ /**
+ * Optional boolean indicating whether the recognizer should return the confidence
+ * level of each word in the final recognition results.
+ */
+ public static final String EXTRA_REQUEST_WORD_CONFIDENCE =
+ "android.speech.extra.REQUEST_WORD_CONFIDENCE";
}
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index bcb8005e35cf..33c5b5a27fab 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -113,6 +113,17 @@ public class SpeechRecognizer {
public static final String RESULTS_ALTERNATIVES = "results_alternatives";
/**
+ * Key used to receive an ArrayList&lt;{@link RecognitionPart}&gt; object from the
+ * {@link Bundle} passed to the {@link RecognitionListener#onResults(Bundle)} and
+ * {@link RecognitionListener#onSegmentResults(Bundle)} methods.
+ *
+ * <p> A single {@link SpeechRecognizer} result is represented as a {@link String}. Each word of
+ * the resulting String, as well as any potential adjacent punctuation, is represented by a
+ * {@link RecognitionPart} item from the ArrayList retrieved by this key.
+ */
+ public static final String RECOGNITION_PARTS = "recognition_parts";
+
+ /**
* The reason speech recognition failed.
*
* @hide
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 680e8f7f87b2..a746dc6c15f0 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -96,12 +96,6 @@ public class FeatureFlagUtils {
public static final String SETTINGS_NEW_KEYBOARD_UI = "settings_new_keyboard_ui";
/**
- * Enable new shortcut list UI
- * @hide
- */
- public static final String SETTINGS_NEW_KEYBOARD_SHORTCUT = "settings_new_keyboard_shortcut";
-
- /**
* Enable new modifier key settings UI
* @hide
*/
@@ -227,7 +221,6 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, "true");
DEFAULT_FLAGS.put(SETTINGS_AUTO_TEXT_WRAPPING, "false");
DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "false");
- DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_SHORTCUT, "false");
DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY, "false");
DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD, "false");
DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE, "false");
@@ -255,7 +248,6 @@ public class FeatureFlagUtils {
PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
PERSISTENT_FLAGS.add(SETTINGS_AUTO_TEXT_WRAPPING);
PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_UI);
- PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_SHORTCUT);
PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY);
PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD);
PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE);
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index af432228183c..98c0d7f4fbf1 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -129,7 +129,8 @@ public abstract class NtpTrustedTime implements TrustedTime {
*
* @hide
*/
- public static final class TimeResult {
+ // Non-final for mocking frameworks
+ public static class TimeResult {
private final long mUnixEpochTimeMillis;
private final long mElapsedRealtimeMillis;
private final int mUncertaintyMillis;
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
index 6f8c5dbdb6f8..ea7efc79de87 100644
--- a/core/java/android/util/PackageUtils.java
+++ b/core/java/android/util/PackageUtils.java
@@ -184,24 +184,15 @@ public final class PackageUtils {
}
/**
- * @see #computeSha256DigestForLargeFile(String, byte[], String)
- */
- public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath,
- @NonNull byte[] fileBuffer) {
- return computeSha256DigestForLargeFile(filePath, fileBuffer, null);
- }
-
- /**
- * Computes the SHA256 digest of large files. This is typically useful for large APEXs.
+ * Computes the SHA256 digest of a large file.
* @param filePath The path to which the file's content is to be hashed.
* @param fileBuffer A buffer to read file's content into memory. It is strongly recommended to
* make use of the {@link #createLargeFileBuffer()} method to create this
* buffer.
- * @param separator Separator between each pair of characters, such as colon, or null to omit.
- * @return The SHA256 digest or null if an error occurs.
+ * @return The byte array of SHA256 digest or null if an error occurs.
*/
- public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath,
- @NonNull byte[] fileBuffer, @Nullable String separator) {
+ public static @Nullable byte[] computeSha256DigestForLargeFileAsBytes(@NonNull String filePath,
+ @NonNull byte[] fileBuffer) {
MessageDigest messageDigest;
try {
messageDigest = MessageDigest.getInstance("SHA256");
@@ -221,8 +212,30 @@ public final class PackageUtils {
return null;
}
- byte[] resultBytes = messageDigest.digest();
+ return messageDigest.digest();
+ }
+ /**
+ * @see #computeSha256DigestForLargeFile(String, byte[], String)
+ */
+ public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath,
+ @NonNull byte[] fileBuffer) {
+ return computeSha256DigestForLargeFile(filePath, fileBuffer, null);
+ }
+
+ /**
+ * Computes the SHA256 digest of a large file.
+ * @param filePath The path to which the file's content is to be hashed.
+ * @param fileBuffer A buffer to read file's content into memory. It is strongly recommended to
+ * make use of the {@link #createLargeFileBuffer()} method to create this
+ * buffer.
+ * @param separator Separator between each pair of characters, such as colon, or null to omit.
+ * @see #computeSha256DigestForLargeFile(String, byte[])
+ * @return The encoded string of SHA256 digest or null if an error occurs.
+ */
+ public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath,
+ @NonNull byte[] fileBuffer, @Nullable String separator) {
+ byte[] resultBytes = computeSha256DigestForLargeFileAsBytes(filePath, fileBuffer);
if (separator == null) {
return HexEncoding.encodeToString(resultBytes, false);
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 3dc79cf13422..d0acedb3437b 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -367,6 +367,14 @@ public final class Choreographer {
}
/**
+ * Check if the sourced looper and the current looper are same.
+ * @hide
+ */
+ boolean isTheLooperSame(Looper looper) {
+ return mLooper == looper;
+ }
+
+ /**
* The amount of time, in milliseconds, between each frame of the animation.
* <p>
* This is a requested time that the animation will attempt to honor, but the actual delay
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index bda707b48627..1898407c83db 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -619,10 +619,11 @@ public class DragEvent implements Parcelable {
}
if (in.readInt() != 0) {
event.mDragSurface = SurfaceControl.CREATOR.createFromParcel(in);
+ event.mDragSurface.setUnreleasedWarningCallSite("DragEvent");
}
if (in.readInt() != 0) {
event.mDragAndDropPermissions =
- IDragAndDropPermissions.Stub.asInterface(in.readStrongBinder());;
+ IDragAndDropPermissions.Stub.asInterface(in.readStrongBinder());
}
return event;
}
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index 8d8ddb930c23..5ea640c66f22 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -296,6 +296,9 @@ public class RemoteAnimationTarget implements Parcelable {
taskId = in.readInt();
mode = in.readInt();
leash = in.readTypedObject(SurfaceControl.CREATOR);
+ if (leash != null) {
+ leash.setUnreleasedWarningCallSite("RemoteAnimationTarget[leash]");
+ }
isTranslucent = in.readBoolean();
clipRect = in.readTypedObject(Rect.CREATOR);
contentInsets = in.readTypedObject(Rect.CREATOR);
@@ -307,6 +310,9 @@ public class RemoteAnimationTarget implements Parcelable {
windowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR);
isNotInRecents = in.readBoolean();
startLeash = in.readTypedObject(SurfaceControl.CREATOR);
+ if (startLeash != null) {
+ startLeash.setUnreleasedWarningCallSite("RemoteAnimationTarget[startLeash]");
+ }
startBounds = in.readTypedObject(Rect.CREATOR);
taskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
allowEnterPip = in.readBoolean();
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 8e0941144b51..a3c0d7e0ea62 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -742,13 +742,6 @@ public final class SurfaceControl implements Parcelable {
*/
public static final int POWER_MODE_ON_SUSPEND = 4;
- /**
- * internal representation of how to interpret pixel value, used only to convert to ColorSpace.
- */
- private static final int INTERNAL_DATASPACE_SRGB = 142671872;
- private static final int INTERNAL_DATASPACE_DISPLAY_P3 = 143261696;
- private static final int INTERNAL_DATASPACE_SCRGB = 411107328;
-
private void assignNativeObject(long nativeObject, String callsite) {
if (mNativeObject != 0) {
release();
@@ -1291,6 +1284,20 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * Provides more information to show about the source of this SurfaceControl if it is finalized
+ * without being released. This is primarily intended for callers to update the call site after
+ * receiving a SurfaceControl from another process, which would otherwise get a generic default
+ * call site.
+ * @hide
+ */
+ public void setUnreleasedWarningCallSite(@NonNull String callsite) {
+ if (!isValid()) {
+ return;
+ }
+ mCloseGuard.openWithCallSite("release", callsite);
+ }
+
+ /**
* Checks whether two {@link SurfaceControl} objects represent the same surface.
*
* @param other The other object to check
@@ -1303,27 +1310,36 @@ public final class SurfaceControl implements Parcelable {
}
/**
- * Returns the associated {@link Choreographer} instance with the
- * current instance of the SurfaceControl.
- * Must be called from a thread that already has a {@link android.os.Looper}
- * associated with it.
- * If there is no {@link Choreographer} associated with the SurfaceControl then a new instance
- * of the {@link Choreographer} is created.
+ * When called for the first time a new instance of the {@link Choreographer} is created
+ * with a {@link android.os.Looper} of the current thread. Every subsequent call will return
+ * the same instance of the Choreographer.
+ *
+ * @see #getChoreographer(Looper) to create Choreographer with a different
+ * looper than current thread looper.
*
* @hide
*/
@TestApi
public @NonNull Choreographer getChoreographer() {
- return getChoreographer(Looper.myLooper());
+ checkNotReleased();
+ synchronized (mChoreographerLock) {
+ if (mChoreographer == null) {
+ return getChoreographer(Looper.myLooper());
+ }
+ return mChoreographer;
+ }
}
/**
- * Returns the associated {@link Choreographer} instance with the
- * current instance of the SurfaceControl.
- * If there is no {@link Choreographer} associated with the SurfaceControl then a new instance
- * of the {@link Choreographer} is created.
+ * When called for the first time a new instance of the {@link Choreographer} is created with
+ * the sourced {@link android.os.Looper}. Every subsequent call will return the same
+ * instance of the Choreographer.
+ *
+ * @see #getChoreographer()
*
- * @param looper the choreographer is attached on this looper
+ * @throws IllegalStateException when a {@link Choreographer} instance exists with a different
+ * looper than sourced.
+ * @param looper the choreographer is attached on this looper.
*
* @hide
*/
@@ -1331,11 +1347,12 @@ public final class SurfaceControl implements Parcelable {
public @NonNull Choreographer getChoreographer(@NonNull Looper looper) {
checkNotReleased();
synchronized (mChoreographerLock) {
- if (mChoreographer != null) {
- return mChoreographer;
+ if (mChoreographer == null) {
+ mChoreographer = Choreographer.getInstanceForSurfaceControl(mNativeHandle, looper);
+ } else if (!mChoreographer.isTheLooperSame(looper)) {
+ throw new IllegalStateException(
+ "Choreographer already exists with a different looper");
}
-
- mChoreographer = Choreographer.getInstanceForSurfaceControl(mNativeHandle, looper);
return mChoreographer;
}
}
@@ -2171,18 +2188,9 @@ public final class SurfaceControl implements Parcelable {
ColorSpace[] colorSpaces = { srgb, srgb };
if (dataspaces.length == 2) {
for (int i = 0; i < 2; ++i) {
- switch(dataspaces[i]) {
- case INTERNAL_DATASPACE_DISPLAY_P3:
- colorSpaces[i] = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
- break;
- case INTERNAL_DATASPACE_SCRGB:
- colorSpaces[i] = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
- break;
- case INTERNAL_DATASPACE_SRGB:
- // Other dataspace is not recognized, use SRGB color space instead,
- // the default value of the array is already SRGB, thus do nothing.
- default:
- break;
+ ColorSpace cs = ColorSpace.getFromDataSpace(dataspaces[i]);
+ if (cs != null) {
+ colorSpaces[i] = cs;
}
}
}
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index f7bdd094ff2c..ac50d09cc091 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -32,6 +32,8 @@ import android.view.accessibility.IAccessibilityEmbeddedConnection;
import android.window.ISurfaceSyncGroup;
import android.window.WindowTokenClient;
+import dalvik.system.CloseGuard;
+
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -51,6 +53,7 @@ import java.util.concurrent.TimeoutException;
public class SurfaceControlViewHost {
private final static String TAG = "SurfaceControlViewHost";
private final ViewRootImpl mViewRoot;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
private WindowlessWindowManager mWm;
private SurfaceControl mSurfaceControl;
@@ -170,6 +173,7 @@ public class SurfaceControlViewHost {
private SurfacePackage(Parcel in) {
mSurfaceControl = new SurfaceControl();
mSurfaceControl.readFromParcel(in);
+ mSurfaceControl.setUnreleasedWarningCallSite("SurfacePackage(Parcel)");
mAccessibilityEmbeddedConnection = IAccessibilityEmbeddedConnection.Stub.asInterface(
in.readStrongBinder());
mInputToken = in.readStrongBinder();
@@ -291,9 +295,10 @@ public class SurfaceControlViewHost {
/** @hide */
public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d,
- @NonNull WindowlessWindowManager wwm) {
+ @NonNull WindowlessWindowManager wwm, @NonNull String callsite) {
mWm = wwm;
mViewRoot = new ViewRootImpl(c, d, mWm, new WindowlessWindowLayout());
+ mCloseGuard.openWithCallSite("release", callsite);
addConfigCallback(c, d);
WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
@@ -315,15 +320,35 @@ public class SurfaceControlViewHost {
*/
public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
@Nullable IBinder hostToken) {
+ this(context, display, hostToken, "untracked");
+ }
+
+ /**
+ * Construct a new SurfaceControlViewHost. The root Surface will be
+ * allocated internally and is accessible via getSurfacePackage().
+ *
+ * The {@param hostToken} parameter, primarily used for ANR reporting,
+ * must be obtained from whomever will be hosting the embedded hierarchy.
+ * It's accessible from {@link SurfaceView#getHostToken}.
+ *
+ * @param context The Context object for your activity or application.
+ * @param display The Display the hierarchy will be placed on.
+ * @param hostToken The host token, as discussed above.
+ * @param callsite The call site, used for tracking leakage of the host
+ * @hide
+ */
+ public SurfaceControlViewHost(@NonNull Context context, @NonNull Display display,
+ @Nullable IBinder hostToken, @NonNull String callsite) {
mSurfaceControl = new SurfaceControl.Builder()
.setContainerLayer()
.setName("SurfaceControlViewHost")
- .setCallsite("SurfaceControlViewHost")
+ .setCallsite("SurfaceControlViewHost[" + callsite + "]")
.build();
mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
mSurfaceControl, hostToken);
mViewRoot = new ViewRootImpl(context, display, mWm, new WindowlessWindowLayout());
+ mCloseGuard.openWithCallSite("release", callsite);
addConfigCallback(context, display);
WindowManagerGlobal.getInstance().addWindowlessRoot(mViewRoot);
@@ -349,7 +374,9 @@ public class SurfaceControlViewHost {
if (mReleased) {
return;
}
- Log.e(TAG, "SurfaceControlViewHost finalized without being released: " + this);
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
// We aren't on the UI thread here so we need to pass false to doDie
mViewRoot.die(false /* immediate */);
WindowManagerGlobal.getInstance().removeWindowlessRoot(mViewRoot);
@@ -465,6 +492,7 @@ public class SurfaceControlViewHost {
mViewRoot.die(true /* immediate */);
WindowManagerGlobal.getInstance().removeWindowlessRoot(mViewRoot);
mReleased = true;
+ mCloseGuard.close();
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cecfc8a7d66e..241ee5a28dd8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8945,11 +8945,33 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
outRect.set(position.left, position.top, position.right, position.bottom);
}
+ /**
+ * Gets the location of this view in window coordinates.
+ *
+ * @param outRect The output location
+ * @param clipToParent Whether to clip child bounds to the parent ones.
+ * @hide
+ */
+ public void getBoundsInWindow(Rect outRect, boolean clipToParent) {
+ if (mAttachInfo == null) {
+ return;
+ }
+ RectF position = mAttachInfo.mTmpTransformRect;
+ getBoundsToWindowInternal(position, clipToParent);
+ outRect.set(Math.round(position.left), Math.round(position.top),
+ Math.round(position.right), Math.round(position.bottom));
+ }
+
private void getBoundsToScreenInternal(RectF position, boolean clipToParent) {
position.set(0, 0, mRight - mLeft, mBottom - mTop);
mapRectFromViewToScreenCoords(position, clipToParent);
}
+ private void getBoundsToWindowInternal(RectF position, boolean clipToParent) {
+ position.set(0, 0, mRight - mLeft, mBottom - mTop);
+ mapRectFromViewToWindowCoords(position, clipToParent);
+ }
+
/**
* Map a rectangle from view-relative coordinates to screen-relative coordinates
*
@@ -8958,6 +8980,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) {
+ mapRectFromViewToWindowCoords(rect, clipToParent);
+ rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
+ }
+
+ /**
+ * Map a rectangle from view-relative coordinates to window-relative coordinates
+ *
+ * @param rect The rectangle to be mapped
+ * @param clipToParent Whether to clip child bounds to the parent ones.
+ * @hide
+ */
+ public void mapRectFromViewToWindowCoords(RectF rect, boolean clipToParent) {
if (!hasIdentityMatrix()) {
getMatrix().mapRect(rect);
}
@@ -8990,8 +9024,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
ViewRootImpl viewRootImpl = (ViewRootImpl) parent;
rect.offset(0, -viewRootImpl.mCurScrollY);
}
-
- rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
}
/**
@@ -10578,6 +10610,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
getBoundsOnScreen(bounds, true);
info.setBoundsInScreen(bounds);
+ getBoundsInWindow(bounds, true);
+ info.setBoundsInWindow(bounds);
ViewParent parent = getParentForAccessibility();
if (parent instanceof View) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d0f095c0dbf0..480abe03b5f3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3741,7 +3741,7 @@ public final class ViewRootImpl implements ViewParent,
}
if (mAttachInfo.mContentCaptureEvents != null) {
- notifyContentCatpureEvents();
+ notifyContentCaptureEvents();
}
mIsInTraversal = false;
@@ -3782,7 +3782,7 @@ public final class ViewRootImpl implements ViewParent,
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
- private void notifyContentCatpureEvents() {
+ private void notifyContentCaptureEvents() {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "notifyContentCaptureEvents");
try {
MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0f68cd0f3293..82b390e3ebf8 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3569,6 +3569,22 @@ public interface WindowManager extends ViewManager {
*/
public float preferredMaxDisplayRefreshRate;
+ /** Indicates whether this window wants the HDR conversion is disabled. */
+ public static final int DISPLAY_FLAG_DISABLE_HDR_CONVERSION = 1 << 0;
+
+ /**
+ * Flags that can be used to set display properties.
+ *
+ * @hide
+ */
+ @IntDef(flag = true, prefix = "DISPLAY_FLAG_", value = {
+ DISPLAY_FLAG_DISABLE_HDR_CONVERSION,
+ })
+ public @interface DisplayFlags {}
+
+ @DisplayFlags
+ private int mDisplayFlags;
+
/**
* An internal annotation for flags that can be specified to {@link #systemUiVisibility}
* and {@link #subtreeSystemUiVisibility}.
@@ -4286,6 +4302,24 @@ public interface WindowManager extends ViewManager {
preservePreviousSurfaceInsets = preservePrevious;
}
+ /** Returns whether the HDR conversion is enabled for the window */
+ public boolean isHdrConversionEnabled() {
+ return ((mDisplayFlags & DISPLAY_FLAG_DISABLE_HDR_CONVERSION) == 0);
+ }
+
+ /**
+ * Enables/disables the HDR conversion for the window.
+ *
+ * By default, the HDR conversion is enabled for the window.
+ */
+ public void setHdrConversionEnabled(boolean enabled) {
+ if (!enabled) {
+ mDisplayFlags |= DISPLAY_FLAG_DISABLE_HDR_CONVERSION;
+ } else {
+ mDisplayFlags &= ~DISPLAY_FLAG_DISABLE_HDR_CONVERSION;
+ }
+ }
+
/**
* <p>Set the color mode of the window. Setting the color mode might
* override the window's pixel {@link WindowManager.LayoutParams#format format}.</p>
@@ -4460,6 +4494,7 @@ public interface WindowManager extends ViewManager {
out.writeTypedArray(providedInsets, 0 /* parcelableFlags */);
checkNonRecursiveParams();
out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */);
+ out.writeInt(mDisplayFlags);
}
public static final @android.annotation.NonNull Parcelable.Creator<LayoutParams> CREATOR
@@ -4530,6 +4565,7 @@ public interface WindowManager extends ViewManager {
mWallpaperTouchEventsEnabled = in.readBoolean();
providedInsets = in.createTypedArray(InsetsFrameProvider.CREATOR);
paramsForRotation = in.createTypedArray(LayoutParams.CREATOR);
+ mDisplayFlags = in.readInt();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -4565,6 +4601,8 @@ public interface WindowManager extends ViewManager {
/** {@hide} */
public static final int PREFERRED_REFRESH_RATE_CHANGED = 1 << 21;
/** {@hide} */
+ public static final int DISPLAY_FLAGS_CHANGED = 1 << 22;
+ /** {@hide} */
public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
/** {@hide} */
public static final int ACCESSIBILITY_ANCHOR_CHANGED = 1 << 24;
@@ -4724,6 +4762,11 @@ public interface WindowManager extends ViewManager {
changes |= PREFERRED_MAX_DISPLAY_REFRESH_RATE;
}
+ if (mDisplayFlags != o.mDisplayFlags) {
+ mDisplayFlags = o.mDisplayFlags;
+ changes |= DISPLAY_FLAGS_CHANGED;
+ }
+
if (systemUiVisibility != o.systemUiVisibility
|| subtreeSystemUiVisibility != o.subtreeSystemUiVisibility) {
systemUiVisibility = o.systemUiVisibility;
@@ -4979,6 +5022,10 @@ public interface WindowManager extends ViewManager {
sb.append(" preferredMaxDisplayRefreshRate=");
sb.append(preferredMaxDisplayRefreshRate);
}
+ if (mDisplayFlags != 0) {
+ sb.append(" displayFlags=0x");
+ sb.append(Integer.toHexString(mDisplayFlags));
+ }
if (hasSystemUiListeners) {
sb.append(" sysuil=");
sb.append(hasSystemUiListeners);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index d88cdf1493e1..4576d627dd61 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -906,6 +906,7 @@ public class AccessibilityNodeInfo implements Parcelable {
private int mBooleanProperties;
private final Rect mBoundsInParent = new Rect();
private final Rect mBoundsInScreen = new Rect();
+ private final Rect mBoundsInWindow = new Rect();
private int mDrawingOrderInParent;
private CharSequence mPackageName;
@@ -2156,6 +2157,49 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Gets the node bounds in window coordinates.
+ * <p>
+ * When magnification is enabled, the bounds in window are scaled up by magnification scale
+ * and the positions are also adjusted according to the offset of magnification viewport.
+ * For example, it returns Rect(-180, -180, 0, 0) for original bounds Rect(10, 10, 100, 100),
+ * when the magnification scale is 2 and offsets for X and Y are both 200.
+ * <p/>
+ *
+ * @param outBounds The output node bounds.
+ */
+ public void getBoundsInWindow(@NonNull Rect outBounds) {
+ outBounds.set(mBoundsInWindow.left, mBoundsInWindow.top,
+ mBoundsInWindow.right, mBoundsInWindow.bottom);
+ }
+
+ /**
+ * Returns the actual rect containing the node bounds in window coordinates.
+ *
+ * @hide Not safe to expose outside the framework.
+ */
+ @NonNull
+ public Rect getBoundsInWindow() {
+ return mBoundsInWindow;
+ }
+
+ /**
+ * Sets the node bounds in window coordinates.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param bounds The node bounds.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setBoundsInWindow(@NonNull Rect bounds) {
+ enforceNotSealed();
+ mBoundsInWindow.set(bounds);
+ }
+
+ /**
* Gets whether this node is checkable.
*
* @return True if the node is checkable.
@@ -4054,6 +4098,11 @@ public class AccessibilityNodeInfo implements Parcelable {
nonDefaultFields |= bitAt(fieldIndex);
}
fieldIndex++;
+ if (!Objects.equals(mBoundsInWindow, DEFAULT.mBoundsInWindow)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+
if (!Objects.equals(mActions, DEFAULT.mActions)) nonDefaultFields |= bitAt(fieldIndex);
fieldIndex++;
if (mMaxTextLength != DEFAULT.mMaxTextLength) nonDefaultFields |= bitAt(fieldIndex);
@@ -4203,6 +4252,13 @@ public class AccessibilityNodeInfo implements Parcelable {
}
if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ parcel.writeInt(mBoundsInWindow.top);
+ parcel.writeInt(mBoundsInWindow.bottom);
+ parcel.writeInt(mBoundsInWindow.left);
+ parcel.writeInt(mBoundsInWindow.right);
+ }
+
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
if (mActions != null && !mActions.isEmpty()) {
final int actionCount = mActions.size();
@@ -4333,6 +4389,7 @@ public class AccessibilityNodeInfo implements Parcelable {
mUniqueId = other.mUniqueId;
mBoundsInParent.set(other.mBoundsInParent);
mBoundsInScreen.set(other.mBoundsInScreen);
+ mBoundsInWindow.set(other.mBoundsInWindow);
mPackageName = other.mPackageName;
mClassName = other.mClassName;
mText = other.mText;
@@ -4465,6 +4522,13 @@ public class AccessibilityNodeInfo implements Parcelable {
}
if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ mBoundsInWindow.top = parcel.readInt();
+ mBoundsInWindow.bottom = parcel.readInt();
+ mBoundsInWindow.left = parcel.readInt();
+ mBoundsInWindow.right = parcel.readInt();
+ }
+
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
final long standardActions = parcel.readLong();
addStandardActions(standardActions);
final int nonStandardActionCount = parcel.readInt();
@@ -4815,6 +4879,7 @@ public class AccessibilityNodeInfo implements Parcelable {
builder.append("; boundsInParent: ").append(mBoundsInParent);
builder.append("; boundsInScreen: ").append(mBoundsInScreen);
+ builder.append("; boundsInWindow: ").append(mBoundsInScreen);
builder.append("; packageName: ").append(mPackageName);
builder.append("; className: ").append(mClassName);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index e87cd12a9705..d1c4201c9bb4 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -168,6 +168,9 @@ public class Editor {
private static final String TAG = "Editor";
private static final boolean DEBUG_UNDO = false;
+ // TODO(nona): Make this configurable.
+ private static final boolean FLAG_USE_NEW_CONTEXT_MENU = false;
+
// Specifies whether to use the magnifier when pressing the insertion or selection handles.
private static final boolean FLAG_USE_MAGNIFIER = true;
@@ -198,16 +201,6 @@ public class Editor {
private static final int ACTION_MODE_MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START = 50;
private static final int ACTION_MODE_MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100;
- // Ordering constants used to place the Context Menu items in their menu.
- private static final int CONTEXT_MENU_ITEM_ORDER_UNDO = 2;
- private static final int CONTEXT_MENU_ITEM_ORDER_REDO = 3;
- private static final int CONTEXT_MENU_ITEM_ORDER_CUT = 4;
- private static final int CONTEXT_MENU_ITEM_ORDER_COPY = 5;
- private static final int CONTEXT_MENU_ITEM_ORDER_PASTE = 6;
- private static final int CONTEXT_MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 7;
- private static final int CONTEXT_MENU_ITEM_ORDER_SELECT_ALL = 8;
- private static final int CONTEXT_MENU_ITEM_ORDER_SHARE = 9;
- private static final int CONTEXT_MENU_ITEM_ORDER_AUTOFILL = 10;
private static final int CONTEXT_MENU_ITEM_ORDER_REPLACE = 11;
private static final int CONTEXT_MENU_GROUP_UNDO_REDO = Menu.FIRST;
@@ -3142,56 +3135,76 @@ public class Editor {
}
}
- menu.setOptionalIconsVisible(true);
+ final int menuItemOrderUndo = 2;
+ final int menuItemOrderRedo = 3;
+ final int menuItemOrderCut = 4;
+ final int menuItemOrderCopy = 5;
+ final int menuItemOrderPaste = 6;
+ final int menuItemOrderPasteAsPlainText;
+ final int menuItemOrderSelectAll;
+ final int menuItemOrderShare;
+ final int menuItemOrderAutofill;
+ if (FLAG_USE_NEW_CONTEXT_MENU) {
+ menuItemOrderPasteAsPlainText = 7;
+ menuItemOrderSelectAll = 8;
+ menuItemOrderShare = 9;
+ menuItemOrderAutofill = 10;
- final int keyboard = mTextView.getResources().getConfiguration().keyboard;
- menu.setQwertyMode(keyboard == Configuration.KEYBOARD_QWERTY);
+ menu.setOptionalIconsVisible(true);
+ menu.setGroupDividerEnabled(true);
- menu.setGroupDividerEnabled(true);
+ final int keyboard = mTextView.getResources().getConfiguration().keyboard;
+ menu.setQwertyMode(keyboard == Configuration.KEYBOARD_QWERTY);
+ } else {
+ menuItemOrderShare = 7;
+ menuItemOrderSelectAll = 8;
+ menuItemOrderAutofill = 10;
+ menuItemOrderPasteAsPlainText = 11;
+ }
- menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, CONTEXT_MENU_ITEM_ORDER_UNDO,
+ menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo,
com.android.internal.R.string.undo)
.setAlphabeticShortcut('z')
.setOnMenuItemClickListener(mOnContextMenuItemClickListener)
.setEnabled(mTextView.canUndo());
- menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, CONTEXT_MENU_ITEM_ORDER_REDO,
+ menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, menuItemOrderRedo,
com.android.internal.R.string.redo)
.setAlphabeticShortcut('z', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
.setOnMenuItemClickListener(mOnContextMenuItemClickListener)
.setEnabled(mTextView.canRedo());
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, CONTEXT_MENU_ITEM_ORDER_CUT,
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, menuItemOrderCut,
com.android.internal.R.string.cut)
.setAlphabeticShortcut('x')
.setOnMenuItemClickListener(mOnContextMenuItemClickListener)
.setEnabled(mTextView.canCut());
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, CONTEXT_MENU_ITEM_ORDER_COPY,
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, menuItemOrderCopy,
com.android.internal.R.string.copy)
.setAlphabeticShortcut('c')
.setOnMenuItemClickListener(mOnContextMenuItemClickListener)
.setEnabled(mTextView.canCopy());
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, CONTEXT_MENU_ITEM_ORDER_PASTE,
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, menuItemOrderPaste,
com.android.internal.R.string.paste)
.setAlphabeticShortcut('v')
.setEnabled(mTextView.canPaste())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE_AS_PLAIN_TEXT,
- CONTEXT_MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT,
+ menuItemOrderPasteAsPlainText,
com.android.internal.R.string.paste_as_plain_text)
.setAlphabeticShortcut('v', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
.setEnabled(mTextView.canPasteAsPlainText())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_SELECT_ALL,
- CONTEXT_MENU_ITEM_ORDER_SELECT_ALL, com.android.internal.R.string.selectAll)
+ menuItemOrderSelectAll, com.android.internal.R.string.selectAll)
.setAlphabeticShortcut('a')
.setEnabled(mTextView.canSelectAllText())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
- menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, CONTEXT_MENU_ITEM_ORDER_SHARE,
+ menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, menuItemOrderShare,
com.android.internal.R.string.share)
.setEnabled(mTextView.canShare())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
- menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, CONTEXT_MENU_ITEM_ORDER_AUTOFILL,
+ menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, menuItemOrderAutofill,
android.R.string.autofill)
.setEnabled(mTextView.canRequestAutofill())
.setOnMenuItemClickListener(mOnContextMenuItemClickListener);
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index bc9f74ecec99..bdaad2b68fc2 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -333,7 +333,8 @@ public final class SplashScreenView extends FrameLayout {
SurfaceControlViewHost viewHost = new SurfaceControlViewHost(viewContext,
viewContext.getDisplay(),
- surfaceView.getHostToken());
+ surfaceView.getHostToken(),
+ "SplashScreenView");
ImageView imageView = new ImageView(viewContext);
imageView.setBackground(mIconDrawable);
viewHost.setView(imageView, mIconSize, mIconSize);
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index c8a69e274e81..e277b49ee508 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -198,6 +198,7 @@ public final class TransitionInfo implements Parcelable {
in.readTypedList(mChanges, Change.CREATOR);
mRootLeash = new SurfaceControl();
mRootLeash.readFromParcel(in);
+ mRootLeash.setUnreleasedWarningCallSite("TransitionInfo");
mRootOffset.readFromParcel(in);
mOptions = in.readTypedObject(AnimationOptions.CREATOR);
}
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index b0a4b541c284..8b41829154e1 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -167,8 +167,9 @@ public class LocaleStore {
*/
@UnsupportedAppUsage
public String getFullNameInUiLanguage() {
+ Locale locale = mLocale.stripExtensions();
// We don't cache the UI name because the default locale keeps changing
- return LocaleHelper.getDisplayName(mLocale, true /* sentence case */);
+ return LocaleHelper.getDisplayName(locale, true /* sentence case */);
}
private String getLangScriptKey() {
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 1084c71397e4..f42bc81229cf 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -48,25 +48,10 @@ public final class SystemUiDeviceConfigFlags {
public static final String NAS_MAX_SUGGESTIONS = "nas_max_suggestions";
/**
- * Whether the Notification Assistant can change ranking.
- */
- public static final String ENABLE_NAS_RANKING = "enable_nas_ranking";
-
- /**
- * Whether the Notification Assistant can prioritize notification.
- */
- public static final String ENABLE_NAS_PRIORITIZER = "enable_nas_prioritizer";
-
- /**
* Whether to enable feedback UI for Notification Assistant
*/
public static final String ENABLE_NAS_FEEDBACK = "enable_nas_feedback";
- /**
- * Whether the Notification Assistant can label a notification not a conversation
- */
- public static final String ENABLE_NAS_NOT_CONVERSATION = "enable_nas_not_conversation";
-
// Flags related to screenshot intelligence
/**
diff --git a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
index 205c5fd735ea..d2b612a9e6f3 100644
--- a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
+++ b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
@@ -73,6 +73,23 @@ public class GestureNavigationSettingsObserver extends ContentObserver {
mOnPropertiesChangedListener);
}
+ public void registerForCurrentUser() {
+ ContentResolver r = mContext.getContentResolver();
+ r.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT),
+ false, this);
+ r.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.BACK_GESTURE_INSET_SCALE_RIGHT),
+ false, this);
+ r.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
+ false, this);
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ runnable -> mMainHandler.post(runnable),
+ mOnPropertiesChangedListener);
+ }
+
public void unregister() {
mContext.getContentResolver().unregisterContentObserver(this);
DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index b79c54059730..b4599c8429b6 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -332,7 +332,6 @@ cc_library_shared {
"libdl",
"libdl_android",
"libtimeinstate",
- "libtflite",
"server_configurable_flags",
"libimage_io",
"libjpegdecoder",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index bcb0da33c111..d2d87d6916d2 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -427,7 +427,7 @@ static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return 0;
} else if (err != NO_ERROR) {
- jniThrowException(env, OutOfResourcesException, NULL);
+ jniThrowException(env, OutOfResourcesException, statusToString(err).c_str());
return 0;
}
diff --git a/core/proto/android/app/OWNERS b/core/proto/android/app/OWNERS
index 4d76aee9d722..a137ea97b3a4 100644
--- a/core/proto/android/app/OWNERS
+++ b/core/proto/android/app/OWNERS
@@ -1,2 +1,3 @@
+per-file appstartinfo.proto = file:/services/core/java/com/android/server/am/OWNERS
per-file location_time_zone_manager.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
per-file time_zone_detector.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/proto/android/nfc/nfc_service.proto b/core/proto/android/nfc/nfc_service.proto
index 2df1d5d210da..1dcd5cc210d9 100644
--- a/core/proto/android/nfc/nfc_service.proto
+++ b/core/proto/android/nfc/nfc_service.proto
@@ -60,7 +60,7 @@ message NfcServiceDumpProto {
optional bool secure_nfc_capable = 13;
optional bool vr_mode_enabled = 14;
optional DiscoveryParamsProto discovery_params = 15;
- optional P2pLinkManagerProto p2p_link_manager = 16;
+ reserved 16;
optional com.android.nfc.cardemulation.CardEmulationManagerProto card_emulation_manager = 17;
optional NfcDispatcherProto nfc_dispatcher = 18;
optional string native_crash_logs = 19 [(.android.privacy).dest = DEST_EXPLICIT];
@@ -77,38 +77,6 @@ message DiscoveryParamsProto {
optional bool enable_p2p = 5;
}
-// Debugging information for com.android.nfc.P2pLinkManager
-message P2pLinkManagerProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- enum LinkState {
- LINK_STATE_UNKNOWN = 0;
- LINK_STATE_DOWN = 1;
- LINK_STATE_DEBOUNCE = 2;
- LINK_STATE_UP = 3;
- }
-
- enum SendState {
- SEND_STATE_UNKNOWN = 0;
- SEND_STATE_NOTHING_TO_SEND = 1;
- SEND_STATE_NEED_CONFIRMATION = 2;
- SEND_STATE_SENDING = 3;
- SEND_STATE_COMPLETE = 4;
- SEND_STATE_CANCELED = 5;
- }
-
- optional int32 default_miu = 1;
- optional int32 default_rw_size = 2;
- optional LinkState link_state = 3;
- optional SendState send_state = 4;
- optional int32 send_flags = 5;
- optional bool send_enabled = 6;
- optional bool receive_enabled = 7;
- optional string callback_ndef = 8 [(.android.privacy).dest = DEST_EXPLICIT];
- optional .android.nfc.NdefMessageProto message_to_send = 9;
- repeated string uris_to_send = 10 [(.android.privacy).dest = DEST_EXPLICIT];
-}
-
// Debugging information for com.android.nfc.NfcDispatcher
message NfcDispatcherProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/proto/android/server/OWNERS b/core/proto/android/server/OWNERS
index 72d39bfb3cd6..c6d3cda1eaf5 100644
--- a/core/proto/android/server/OWNERS
+++ b/core/proto/android/server/OWNERS
@@ -1 +1,2 @@
+per-file activitymanagerservice.proto = file:/services/core/java/com/android/server/am/OWNERS
per-file window*.proto = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f93739005472..a4818c7e871f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -176,6 +176,7 @@
<protected-broadcast android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" />
<protected-broadcast android:name="android.bluetooth.device.action.SDP_RECORD" />
<protected-broadcast android:name="android.bluetooth.device.action.BATTERY_LEVEL_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.REMOTE_ISSUE_OCCURRED" />
<protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" />
<protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" />
<protected-broadcast
@@ -2823,6 +2824,13 @@
<permission android:name="android.permission.BIND_INCALL_SERVICE"
android:protectionLevel="signature|privileged" />
+ <!-- Must be required by a {@link android.telecom.CallStreamingService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature
+ @SystemApi @hide-->
+ <permission android:name="android.permission.BIND_CALL_STREAMING_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- Allows to query ongoing call details and manage ongoing calls
<p>Protection level: signature|appop -->
<permission android:name="android.permission.MANAGE_ONGOING_CALLS"
@@ -5537,6 +5545,12 @@
<permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
android:protectionLevel="signature|installer" />
+ <!-- @SystemApi Allows an application to manage the holders of roles associated with default
+ applications.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_DEFAULT_APPLICATIONS"
+ android:protectionLevel="signature|role" />
+
<!-- @SystemApi Allows an application to bypass role qualification. This allows switching role
holders to otherwise non eligible holders. Only the shell is allowed to do this, the
qualification for the shell role itself cannot be bypassed, and each role needs to
@@ -6077,6 +6091,11 @@
<permission android:name="android.permission.REGISTER_STATS_PULL_ATOM"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi @hide Allows an application to read restricted stats from statsd.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.READ_RESTRICTED_STATS"
+ android:protectionLevel="internal|privileged" />
+
<!-- @SystemApi Allows an application to control the backup and restore process.
<p>Not for use by third-party applications.
@hide pending API council -->
@@ -8096,7 +8115,7 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
- <service android:name="com.android.server.healthconnect.storage.AutoDeleteService"
+ <service android:name="com.android.server.healthconnect.HealthConnectDailyService"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 11a4ed7376d8..d2ee5dea2bb0 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1648,14 +1648,25 @@
or has been granted the access to one of the attached USB devices/accessories.
-->
<flag name="connectedDevice" value="0x10" />
- <!-- Managing a media projection session, e.g, for screen recording or taking
- screenshots.
+ <!-- Managing a {@link android.media.projection.MediaProjection MediaProjection} session,
+ e.g., for screen recording or takingscreenshots.
- <p>For apps with <code>targetSdkVersion</code>
- {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a foreground
- service with this type will require permission
- {@link android.Manifest.permission#FOREGROUND_SERVICE_MEDIA_PROJECTION}, and the user
- must have allowed the screen capture request from this app.
+ <p>
+ To capture through {@link android.media.projection.MediaProjection}, an app must start
+ a foreground service with the type corresponding to this constant. This type should
+ only be used for {@link android.media.projection.MediaProjection}. Capturing screen
+ contents via
+ {@link android.media.projection.MediaProjection#createVirtualDisplay(String, int, int,
+ int, int, android.view.Surface, android.hardware.display.VirtualDisplay.Callback,
+ android.os.Handler) createVirtualDisplay} conveniently allows recording, presenting
+ screen contents into a meeting, taking screenshots, or several other scenarios.
+ </p>
+
+ <p>For apps with <code>targetSdkVersion</code>
+ {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, starting a
+ foreground service with this type will require permission
+ {@link android.Manifest.permission#FOREGROUND_SERVICE_MEDIA_PROJECTION}, and the user
+ must have allowed the screen capture request from this app.
-->
<flag name="mediaProjection" value="0x20" />
<!-- Use the camera device or record video.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c75ee93b6c39..8e5ae9cf21ae 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2997,6 +2997,12 @@
<string name="config_customAdbWifiNetworkConfirmationSecondaryUserComponent"
>com.android.systemui/com.android.systemui.wifi.WifiDebuggingSecondaryUserActivity</string>
+ <!-- Package name of the system service that implements the shared connectivity service -->
+ <string translatable="false" name="shared_connectivity_service_package"></string>
+
+ <!-- Intent action used when binding to the shared connectivity service -->
+ <string translatable="false" name="shared_connectivity_service_intent_action"></string>
+
<!-- Component name of the activity that shows the usb containment status. -->
<string name="config_usbContaminantActivity" translatable="false"
>com.android.systemui/com.android.systemui.usb.UsbContaminantActivity</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d7cdf73c5c92..91d5692d4e9a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4938,6 +4938,9 @@
<java-symbol type="bool" name="config_stopSystemPackagesByDefault"/>
<java-symbol type="string" name="config_wearServiceComponent" />
+ <java-symbol type="string" name="shared_connectivity_service_package" />
+ <java-symbol type="string" name="shared_connectivity_service_intent_action" />
+
<!-- Whether to show weather on the lockscreen by default. -->
<java-symbol type="bool" name="config_lockscreenWeatherEnabledByDefault" />
</resources>
diff --git a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
index 2a1881e56a6d..f97099d04572 100644
--- a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
+++ b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
@@ -20,28 +20,13 @@ import static android.hardware.Sensor.TYPE_ACCELEROMETER;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.os.BackgroundThread;
-
-import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.time.Duration;
@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -50,23 +35,11 @@ public class VirtualSensorConfigTest {
private static final String SENSOR_NAME = "VirtualSensorName";
private static final String SENSOR_VENDOR = "VirtualSensorVendor";
- @Rule
- public final MockitoRule mockito = MockitoJUnit.rule();
-
- @Mock
- private VirtualSensor.SensorStateChangeCallback mSensorCallback;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
@Test
public void parcelAndUnparcel_matches() {
final VirtualSensorConfig originalConfig =
new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
.setVendor(SENSOR_VENDOR)
- .setStateChangeCallback(BackgroundThread.getExecutor(), mSensorCallback)
.build();
final Parcel parcel = Parcel.obtain();
originalConfig.writeToParcel(parcel, /* flags= */ 0);
@@ -76,7 +49,6 @@ public class VirtualSensorConfigTest {
assertThat(recreatedConfig.getType()).isEqualTo(originalConfig.getType());
assertThat(recreatedConfig.getName()).isEqualTo(originalConfig.getName());
assertThat(recreatedConfig.getVendor()).isEqualTo(originalConfig.getVendor());
- assertThat(recreatedConfig.getStateChangeCallback()).isNotNull();
}
@Test
@@ -84,23 +56,5 @@ public class VirtualSensorConfigTest {
final VirtualSensorConfig config =
new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME).build();
assertThat(config.getVendor()).isNull();
- assertThat(config.getStateChangeCallback()).isNull();
- }
-
- @Test
- public void sensorConfig_sensorCallbackInvocation() throws Exception {
- final VirtualSensorConfig config =
- new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
- .setStateChangeCallback(BackgroundThread.getExecutor(), mSensorCallback)
- .build();
-
- final Duration samplingPeriod = Duration.ofMillis(123);
- final Duration batchLatency = Duration.ofMillis(456);
-
- config.getStateChangeCallback().onStateChanged(true,
- (int) MILLISECONDS.toMicros(samplingPeriod.toMillis()),
- (int) MILLISECONDS.toMicros(batchLatency.toMillis()));
-
- verify(mSensorCallback, timeout(1000)).onStateChanged(true, samplingPeriod, batchLatency);
}
}
diff --git a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
index d8799cb182c8..34ca502851a0 100644
--- a/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
+++ b/core/tests/coretests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -17,12 +17,15 @@ package android.hardware.hdmi;
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+@Presubmit
@SmallTest
@RunWith(JUnit4.class)
/** Tests for {@link HdmiUtils} class. */
diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java
index bbb25a37dd0b..c10ef007c3c0 100644
--- a/core/tests/coretests/src/android/view/KeyEventTest.java
+++ b/core/tests/coretests/src/android/view/KeyEventTest.java
@@ -18,8 +18,8 @@ package android.view;
import static android.view.Display.INVALID_DISPLAY;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -27,6 +27,9 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.google.common.truth.Expect;
+
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,7 +39,7 @@ import java.util.Set;
@SmallTest
@RunWith(AndroidJUnit4.class)
@Presubmit
-public class KeyEventTest {
+public final class KeyEventTest {
private static final int DOWN_TIME = 50;
private static final long EVENT_TIME = 100;
@@ -52,22 +55,14 @@ public class KeyEventTest {
private static final int ID_SOURCE_MASK = 0x3 << 30;
+ @Rule public final Expect expect = Expect.create();
+
@Test
public void testObtain() {
KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
- assertEquals(DOWN_TIME, keyEvent.getDownTime());
- assertEquals(EVENT_TIME, keyEvent.getEventTime());
- assertEquals(ACTION, keyEvent.getAction());
- assertEquals(KEYCODE, keyEvent.getKeyCode());
- assertEquals(REPEAT, keyEvent.getRepeatCount());
- assertEquals(METASTATE, keyEvent.getMetaState());
- assertEquals(DEVICE_ID, keyEvent.getDeviceId());
- assertEquals(SCAN_CODE, keyEvent.getScanCode());
- assertEquals(FLAGS, keyEvent.getFlags());
- assertEquals(SOURCE, keyEvent.getSource());
- assertEquals(INVALID_DISPLAY, keyEvent.getDisplayId());
- assertEquals(CHARACTERS, keyEvent.getCharacters());
+
+ assertHasDefaultFields(keyEvent, INVALID_DISPLAY);
}
@Test
@@ -75,6 +70,7 @@ public class KeyEventTest {
KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
KeyEvent keyEvent2 = KeyEvent.obtain(keyEvent);
+
compareKeys(keyEvent, keyEvent2);
}
@@ -83,18 +79,8 @@ public class KeyEventTest {
final int displayId = 5;
KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, CHARACTERS);
- assertEquals(DOWN_TIME, keyEvent.getDownTime());
- assertEquals(EVENT_TIME, keyEvent.getEventTime());
- assertEquals(ACTION, keyEvent.getAction());
- assertEquals(KEYCODE, keyEvent.getKeyCode());
- assertEquals(REPEAT, keyEvent.getRepeatCount());
- assertEquals(METASTATE, keyEvent.getMetaState());
- assertEquals(DEVICE_ID, keyEvent.getDeviceId());
- assertEquals(SCAN_CODE, keyEvent.getScanCode());
- assertEquals(FLAGS, keyEvent.getFlags());
- assertEquals(SOURCE, keyEvent.getSource());
- assertEquals(displayId, keyEvent.getDisplayId());
- assertEquals(CHARACTERS, keyEvent.getCharacters());
+
+ assertHasDefaultFields(keyEvent, displayId);
}
/**
@@ -109,8 +95,8 @@ public class KeyEventTest {
for (int i = 0; i < 500; ++i) {
KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
- assertFalse("Found duplicate ID in round " + i,
- set.contains(keyEvent.getId()));
+ assertWithMessage("event IDs (event generated on round %s: %s)", i, keyEvent)
+ .that(set).doesNotContain(keyEvent.getId());
set.add(keyEvent.getSequenceNumber());
}
}
@@ -120,8 +106,8 @@ public class KeyEventTest {
Set<Integer> set = new HashSet<>();
for (int i = 0; i < 500; ++i) {
KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT);
- assertFalse("Found duplicate sequence number in round " + i,
- set.contains(keyEvent.getId()));
+ assertWithMessage("sequence numbers (event generated on round %s: %s)", i, keyEvent)
+ .that(set).doesNotContain(keyEvent.getSequenceNumber());
set.add(keyEvent.getSequenceNumber());
}
}
@@ -131,7 +117,7 @@ public class KeyEventTest {
for (int i = 0; i < 500; ++i) {
KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
- assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId());
+ assertThat((ID_SOURCE_MASK & keyEvent.getId())).isEqualTo((0x3 << 30));
}
}
@@ -139,48 +125,166 @@ public class KeyEventTest {
public void testConstructorGeneratesIdWithRightSource() {
for (int i = 0; i < 500; ++i) {
KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT);
- assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId());
+ assertThat((ID_SOURCE_MASK & keyEvent.getId())).isEqualTo((0x3 << 30));
}
}
@Test
public void testParcelUnparcel() {
KeyEvent key1 = createKey();
+ KeyEvent key2;
+
Parcel parcel = Parcel.obtain();
- key1.writeToParcel(parcel, 0 /*flags*/);
- parcel.setDataPosition(0);
+ try {
+ key1.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
- KeyEvent key2 = KeyEvent.CREATOR.createFromParcel(parcel);
- parcel.recycle();
+ key2 = KeyEvent.CREATOR.createFromParcel(parcel);
+ } finally {
+ parcel.recycle();
+ }
compareKeys(key1, key2);
}
@Test
- public void testConstructor() {
+ public void testCopyConstructor() {
KeyEvent key1 = createKey();
KeyEvent key2 = new KeyEvent(key1);
+
compareKeys(key1, key2);
}
+ @Test
+ public void testConstructorWith10Args() {
+ KeyEvent key = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
+ DEVICE_ID, SCAN_CODE, FLAGS, SOURCE);
+
+ assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
+ DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, CHARACTERS);
+ }
+
+ @Test
+ public void testConstructorWith9Args() {
+ KeyEvent key = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
+ DEVICE_ID, SCAN_CODE, FLAGS);
+
+ assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
+ DEVICE_ID, SCAN_CODE, FLAGS, /* source= */ 0, /* displayId= */ 0,
+ CHARACTERS);
+ }
+
+ @Test
+ public void testConstructorWith8Args() {
+ KeyEvent key = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
+ DEVICE_ID, SCAN_CODE);
+
+ assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
+ DEVICE_ID, SCAN_CODE, /* flags= */ 0, /* source= */ 0, /* displayId= */ 0,
+ CHARACTERS);
+ }
+
+ @Test
+ public void testConstructorWith6Args() {
+ KeyEvent key = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE);
+
+ assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
+ KeyCharacterMap.VIRTUAL_KEYBOARD, /* scanCode= */ 0, /* flags= */ 0,
+ /* source= */ 0, /* displayId= */ 0, CHARACTERS);
+ }
+
+ @Test
+ public void testConstructorWith5Args() {
+ KeyEvent key = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT);
+
+ assertKeyEventFields(key, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
+ /* metaState= */ 0, KeyCharacterMap.VIRTUAL_KEYBOARD, /* scanCode= */ 0,
+ /* flags= */ 0, /* source= */ 0, /* displayId= */ 0, CHARACTERS);
+ }
+
+ @Test
+ public void testConstructorWith4Args() {
+ KeyEvent key = new KeyEvent(42, CHARACTERS, DEVICE_ID, FLAGS);
+
+ assertKeyEventFields(key, /* downTime= */ 42, /* eventTime= */ 42, KeyEvent.ACTION_MULTIPLE,
+ KeyEvent.KEYCODE_UNKNOWN, /* repeat= */ 0, /* metaState= */ 0, DEVICE_ID,
+ /* scanCode= */ 0, FLAGS, InputDevice.SOURCE_KEYBOARD, INVALID_DISPLAY, CHARACTERS);
+ }
+
+ @Test
+ public void testConstructorWith2rgs() {
+ KeyEvent key = new KeyEvent(ACTION, KEYCODE);
+
+ assertKeyEventFields(key, /* downTime= */ 0, /* eventTime= */ 0, ACTION, KEYCODE,
+ /* repeat= */ 0, /* metaState= */ 0, KeyCharacterMap.VIRTUAL_KEYBOARD,
+ /* scanCode= */ 0, FLAGS, /* source= */ 0, /* displayId= */ 0, CHARACTERS);
+ }
+
private static KeyEvent createKey() {
return KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, CHARACTERS);
}
- private static void compareKeys(KeyEvent key1, KeyEvent key2) {
- assertEquals(key1.getId(), key2.getId());
- assertEquals(key1.getDownTime(), key2.getDownTime());
- assertEquals(key1.getEventTime(), key2.getEventTime());
- assertEquals(key1.getAction(), key2.getAction());
- assertEquals(key1.getKeyCode(), key2.getKeyCode());
- assertEquals(key1.getRepeatCount(), key2.getRepeatCount());
- assertEquals(key1.getMetaState(), key2.getMetaState());
- assertEquals(key1.getDeviceId(), key2.getDeviceId());
- assertEquals(key1.getScanCode(), key2.getScanCode());
- assertEquals(key1.getFlags(), key2.getFlags());
- assertEquals(key1.getSource(), key2.getSource());
- assertEquals(key1.getDisplayId(), key2.getDisplayId());
- assertEquals(key1.getCharacters(), key2.getCharacters());
+ private void compareKeys(KeyEvent key1, KeyEvent key2) {
+ expect.withMessage("id (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getId()).isEqualTo(key1.getId());
+ expect.withMessage("downTime (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getDownTime()).isEqualTo(key1.getDownTime());
+ expect.withMessage("eventTime (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getEventTime()).isEqualTo(key1.getEventTime());
+ expect.withMessage("action (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getAction()).isEqualTo(key1.getAction());
+ expect.withMessage("keyCode (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getKeyCode()).isEqualTo(key1.getKeyCode());
+ expect.withMessage("repatCount (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getRepeatCount()).isEqualTo(key1.getRepeatCount());
+ expect.withMessage("metaState (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getMetaState()).isEqualTo(key1.getMetaState());
+ expect.withMessage("deviceId (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getDeviceId()).isEqualTo(key1.getDeviceId());
+ expect.withMessage("scanCode (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getScanCode()).isEqualTo(key1.getScanCode());
+ expect.withMessage("flags (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getFlags()).isEqualTo(key1.getFlags());
+ expect.withMessage("source (key1=%s, key2=%s)", key1, key2)
+ .that(key2.getSource()).isEqualTo(key1.getSource());
+ expect.withMessage("displayId(key1=%s, key2=%s)", key1, key2)
+ .that(key2.getDisplayId()).isEqualTo(key1.getDisplayId());
+ expect.withMessage("characters(key1=%s, key2=%s)", key1, key2)
+ .that(key2.getCharacters()).isEqualTo(key1.getCharacters());
+ }
+
+ private void assertHasDefaultFields(KeyEvent keyEvent, int displayId) {
+ assertKeyEventFields(keyEvent, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
+ DEVICE_ID, SCAN_CODE, FLAGS, InputDevice.SOURCE_KEYBOARD, displayId, CHARACTERS);
+ }
+
+ private void assertKeyEventFields(KeyEvent keyEvent, long downTime, long eventTime,
+ int action, int keyCode, int repeat, int metaState, int deviceId, int scanCode,
+ int flags, int source, int displayId, String characters) {
+ expect.withMessage("downTime on %s", keyEvent)
+ .that(keyEvent.getDownTime()).isEqualTo(downTime);
+ expect.withMessage("eventTime on %s", keyEvent)
+ .that(keyEvent.getEventTime()).isEqualTo(eventTime);
+ expect.withMessage("action on %s", keyEvent)
+ .that(keyEvent.getAction()).isEqualTo(action);
+ expect.withMessage("keyCode on %s", keyEvent)
+ .that(keyEvent.getKeyCode()).isEqualTo(keyCode);
+ expect.withMessage("repeatCount on %s", keyEvent)
+ .that(keyEvent.getRepeatCount()).isEqualTo(repeat);
+ expect.withMessage("metaState on %s", keyEvent)
+ .that(keyEvent.getMetaState()).isEqualTo(metaState);
+ expect.withMessage("deviceId on %s", keyEvent)
+ .that(keyEvent.getDeviceId()).isEqualTo(deviceId);
+ expect.withMessage("scanCode on %s", keyEvent)
+ .that(keyEvent.getScanCode()).isEqualTo(scanCode);
+ expect.withMessage("flags on %s", keyEvent)
+ .that(keyEvent.getFlags()).isEqualTo(flags);
+ expect.withMessage("source on %s", keyEvent)
+ .that(keyEvent.getSource()).isEqualTo(source);
+ expect.withMessage("displayId on %s", keyEvent)
+ .that(keyEvent.getDisplayId()).isEqualTo(displayId);
+ expect.withMessage("characters on %s", keyEvent)
+ .that(keyEvent.getCharacters()).isEqualTo(characters);
}
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 248420f16b80..0d7c8b84dac0 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -46,7 +46,7 @@ public class AccessibilityNodeInfoTest {
// The number of fields tested in the corresponding CTS AccessibilityNodeInfoTest:
// See fullyPopulateAccessibilityNodeInfo, assertEqualsAccessibilityNodeInfo,
// and assertAccessibilityNodeInfoCleared in that class.
- private static final int NUM_MARSHALLED_PROPERTIES = 42;
+ private static final int NUM_MARSHALLED_PROPERTIES = 43;
/**
* The number of properties that are purposely not marshalled
diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp
index f49e05329f62..3d04937c9195 100644
--- a/core/tests/hdmitests/Android.bp
+++ b/core/tests/hdmitests/Android.bp
@@ -29,9 +29,11 @@ android_test {
"androidx.test.rules",
"frameworks-base-testutils",
"guava-android-testlib",
+ "platform-test-annotations",
"truth-prebuilt",
],
libs: ["android.test.runner"],
platform_apis: true,
certificate: "platform",
+ test_suites: ["device-tests"],
}
diff --git a/core/tests/hdmitests/AndroidTest.xml b/core/tests/hdmitests/AndroidTest.xml
index 0c8da28cab7c..7376004653c2 100644
--- a/core/tests/hdmitests/AndroidTest.xml
+++ b/core/tests/hdmitests/AndroidTest.xml
@@ -22,6 +22,9 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="HdmiCecTests.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ <option name="force-root" value="true" />
+ </target_preparer>
<option name="test-suite-tag" value="apct"/>
<option name="test-tag" value="HdmiTests"/>
@@ -30,5 +33,6 @@
<option name="package" value="android.hardware.hdmi" />
<option name="hidden-api-checks" value="false"/>
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+ <option name="test-filter-dir" value="/data/data/android.hardware.hdmi" />
</test>
</configuration> \ No newline at end of file
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java
index 875ab3862354..9005afb1ebbf 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/DeviceFeaturesTest.java
@@ -22,6 +22,8 @@ import static android.hardware.hdmi.DeviceFeatures.FEATURE_SUPPORT_UNKNOWN;
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import com.google.common.testing.EqualsTester;
@@ -31,6 +33,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link DeviceFeatures} */
+@Presubmit
@RunWith(JUnit4.class)
@SmallTest
public class DeviceFeaturesTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index e16a2f8e8560..bb3e76890b85 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -18,6 +18,7 @@ package android.hardware.hdmi;
import android.os.Handler;
import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
import android.util.Log;
import androidx.test.filters.SmallTest;
@@ -34,6 +35,7 @@ import java.util.List;
/**
* Tests for {@link HdmiAudioSystemClient}
*/
+@Presubmit
@RunWith(JUnit4.class)
@SmallTest
public class HdmiAudioSystemClientTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
index 5f7468e084bf..5039fe8b6cc2 100755
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
@@ -16,6 +16,8 @@
package android.hardware.hdmi;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import com.google.common.testing.EqualsTester;
@@ -25,6 +27,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link HdmiDeviceInfo} */
+@Presubmit
@RunWith(JUnit4.class)
@SmallTest
public class HdmiDeviceInfoTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
index 2bce7475f4c0..fde112269003 100755
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiPortInfoTest.java
@@ -16,6 +16,8 @@
package android.hardware.hdmi;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import com.google.common.testing.EqualsTester;
@@ -25,6 +27,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link HdmiPortInfo} */
+@Presubmit
@RunWith(JUnit4.class)
@SmallTest
public class HdmiPortInfoTest {
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
index fdc6b847d055..13212ce8e84e 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiUtilsTest.java
@@ -18,6 +18,8 @@ package android.hardware.hdmi;
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -26,6 +28,7 @@ import org.junit.runners.JUnit4;
/**
* Tests for {@link HdmiUtils}.
*/
+@Presubmit
@RunWith(JUnit4.class)
@SmallTest
public class HdmiUtilsTest {
diff --git a/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml b/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml
index 7475abac4695..b2d59396d58d 100644
--- a/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml
+++ b/libs/WindowManager/Shell/res/animator/tv_window_menu_action_button_animator.xml
@@ -18,6 +18,20 @@
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <set>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleX"
+ android:valueTo="1.0"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleY"
+ android:valueTo="1.0"
+ android:valueType="floatType"/>
+ </set>
+ </item>
<item android:state_focused="true">
<set>
<objectAnimator
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
index b085b73d78ce..34bf9e0dd98f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
@@ -76,6 +76,7 @@ public class RootDisplayAreaOrganizer extends DisplayAreaOrganizer {
+ " mDisplayAreasInfo.get():" + mDisplayAreasInfo.get(displayId));
}
+ leash.setUnreleasedWarningCallSite("RootDisplayAreaOrganizer.onDisplayAreaAppeared");
mDisplayAreasInfo.put(displayId, displayAreaInfo);
mLeashes.put(displayId, leash);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
index ca977ed2cb94..544d75739547 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
@@ -122,6 +122,8 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer {
+ " mDisplayAreasInfo.get():" + mDisplayAreasInfo.get(displayId));
}
+ leash.setUnreleasedWarningCallSite(
+ "RootTaskDisplayAreaOrganizer.onDisplayAreaAppeared");
mDisplayAreasInfo.put(displayId, displayAreaInfo);
mLeashes.put(displayId, leash);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index b5ef72aec6aa..585f81c81a36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -464,6 +464,9 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+ if (leash != null) {
+ leash.setUnreleasedWarningCallSite("ShellTaskOrganizer.onTaskAppeared");
+ }
synchronized (mLock) {
onTaskAppeared(new TaskAppearedInfo(taskInfo, leash));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index b8e83635de6e..d6e1a82a68ff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -25,7 +25,6 @@ import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON
import static android.util.RotationUtils.rotateBounds;
import static android.util.RotationUtils.rotateInsets;
import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -46,9 +45,9 @@ import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
-import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.Surface;
+import android.view.WindowInsets;
import androidx.annotation.VisibleForTesting;
@@ -372,23 +371,20 @@ public class DisplayLayout {
// Only navigation bar
if (hasNavigationBar) {
- final InsetsSource extraNavBar = insetsState.peekSource(ITYPE_EXTRA_NAVIGATION_BAR);
- final boolean hasExtraNav = extraNavBar != null && extraNavBar.isVisible();
+ final Insets insets = insetsState.calculateInsets(
+ insetsState.getDisplayFrame(),
+ WindowInsets.Type.navigationBars(),
+ false /* ignoreVisibility */);
+ outInsets.set(insets.left, insets.top, insets.right, insets.bottom);
int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
int navBarSize =
getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
if (position == NAV_BAR_BOTTOM) {
- outInsets.bottom = hasExtraNav
- ? Math.max(navBarSize, extraNavBar.getFrame().height())
- : navBarSize;
+ outInsets.bottom = Math.max(outInsets.bottom , navBarSize);
} else if (position == NAV_BAR_RIGHT) {
- outInsets.right = hasExtraNav
- ? Math.max(navBarSize, extraNavBar.getFrame().width())
- : navBarSize;
+ outInsets.right = Math.max(outInsets.right , navBarSize);
} else if (position == NAV_BAR_LEFT) {
- outInsets.left = hasExtraNav
- ? Math.max(navBarSize, extraNavBar.getFrame().width())
- : navBarSize;
+ outInsets.left = Math.max(outInsets.left , navBarSize);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 5e46023cd84f..5e42782431fd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -223,7 +223,7 @@ public class SystemWindows {
}
final Display display = mDisplayController.getDisplay(mDisplayId);
SurfaceControlViewHost viewRoot =
- new SurfaceControlViewHost(view.getContext(), display, wwm);
+ new SurfaceControlViewHost(view.getContext(), display, wwm, "SystemWindows");
attrs.flags |= FLAG_HARDWARE_ACCELERATED;
viewRoot.setView(view, attrs);
mViewRoots.put(view, viewRoot);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index fa3a6ad016b0..e44257ebef5c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -114,7 +114,8 @@ public class SplitDecorManager extends WindowlessWindowManager {
context = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY,
null /* options */);
mHostLeash = rootLeash;
- mViewHost = new SurfaceControlViewHost(context, context.getDisplay(), this);
+ mViewHost = new SurfaceControlViewHost(context, context.getDisplay(), this,
+ "SplitDecorManager");
mIconSize = context.getResources().getDimensionPixelSize(R.dimen.split_icon_size);
final FrameLayout rootLayout = (FrameLayout) LayoutInflater.from(context)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 6b5ddcb7ebe3..eb3c1df0ae73 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -113,7 +113,8 @@ public final class SplitWindowManager extends WindowlessWindowManager {
"Try to inflate divider view again without release first");
}
- mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+ mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this,
+ "SplitWindowManager");
mDividerView = (DividerView) LayoutInflater.from(mContext)
.inflate(R.layout.split_divider, null /* root */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
index 34e650a72ced..efd459498adb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -363,7 +363,8 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana
/** Creates a {@link SurfaceControlViewHost} for this window manager. */
@VisibleForTesting(visibility = PRIVATE)
public SurfaceControlViewHost createSurfaceViewHost() {
- return new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+ return new SurfaceControlViewHost(mContext, mContext.getDisplay(), this,
+ getClass().getSimpleName());
}
/** Gets the layout params. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
index f376e1fd6174..32894cdc5aec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
@@ -117,6 +117,7 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer {
@Override
public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
@NonNull SurfaceControl leash) {
+ leash.setUnreleasedWarningCallSite("HideDisplayCutoutOrganizer.onDisplayAreaAppeared");
if (!addDisplayAreaInfoAndLeashToMap(displayAreaInfo, leash)) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
index 8ebcd815cf12..71cc8df80cad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
@@ -122,7 +122,8 @@ public final class BackgroundWindowManager extends WindowlessWindowManager {
return false;
}
- mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+ mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this,
+ "BackgroundWindowManager");
mBackgroundView = (View) LayoutInflater.from(mContext)
.inflate(R.layout.background_panel, null /* root */);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index 451afa08040c..38ce16489b06 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -154,6 +154,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
@Override
public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
@NonNull SurfaceControl leash) {
+ leash.setUnreleasedWarningCallSite(
+ "OneHandedSiaplyAreaOrganizer.onDisplayAreaAppeared");
mDisplayAreaTokenMap.put(displayAreaInfo.token, leash);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index ec34f73126fb..00ed09445721 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -1215,6 +1215,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb
@Override
public void stopSwipePipToHome(int taskId, ComponentName componentName,
Rect destinationBounds, SurfaceControl overlay) {
+ if (overlay != null) {
+ overlay.setUnreleasedWarningCallSite("PipController.stopSwipePipToHome");
+ }
executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome",
(controller) -> {
controller.stopSwipePipToHome(taskId, componentName, destinationBounds,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 02b919777f0f..a437a3bc2826 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -740,7 +740,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
if (mRegistered) return;
mContext.registerReceiverForAllUsers(this, mIntentFilter, SYSTEMUI_PERMISSION,
- mMainHandler);
+ mMainHandler, Context.RECEIVER_NOT_EXPORTED);
mRegistered = true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index ae685ad4b8d9..91b0aa193aad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -484,7 +484,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
interface SurfaceControlViewHostFactory {
default SurfaceControlViewHost create(Context c, Display d, WindowlessWindowManager wmm) {
- return new SurfaceControlViewHost(c, d, wmm);
+ return new SurfaceControlViewHost(c, d, wmm, "WindowDecoration");
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index 05fd889521f2..e8784d77be1b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -18,7 +18,6 @@ package com.android.wm.shell.compatui;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.WindowInsets.Type.navigationBars;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -333,7 +332,8 @@ public class CompatUIControllerTest extends ShellTestCase {
mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
/* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
InsetsState insetsState = new InsetsState();
- InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR, navigationBars());
+ InsetsSource insetsSource = new InsetsSource(
+ InsetsSource.createId(null, 0, navigationBars()), navigationBars());
insetsSource.setFrame(0, 0, 1000, 1000);
insetsState.addSource(insetsSource);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index f3f615d97a56..4de529885565 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -20,7 +20,6 @@ import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.WindowInsets.Type.navigationBars;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -338,8 +337,10 @@ public class CompatUIWindowManagerTest extends ShellTestCase {
// Update if the insets change on the existing display layout
clearInvocations(mWindowManager);
InsetsState insetsState = new InsetsState();
- InsetsSource insetsSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR, navigationBars());
- insetsSource.setFrame(0, 0, 1000, 1000);
+ insetsState.setDisplayFrame(new Rect(0, 0, 1000, 2000));
+ InsetsSource insetsSource = new InsetsSource(
+ InsetsSource.createId(null, 0, navigationBars()), navigationBars());
+ insetsSource.setFrame(0, 1800, 1000, 2000);
insetsState.addSource(insetsSource);
displayLayout.setInsets(mContext.getResources(), insetsState);
mWindowManager.updateDisplayLayout(displayLayout);
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index 10c287d1e07d..23a7520bd3da 100644
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -1,5 +1,6 @@
#undef LOG_TAG
#define LOG_TAG "Bitmap"
+// #define LOG_NDEBUG 0
#include "Bitmap.h"
#include <hwui/Bitmap.h>
@@ -372,15 +373,33 @@ static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src,
return srcPM.readPixels(dstPM);
}
-static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
- jint dstConfigHandle, jboolean isMutable) {
+static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle,
+ jboolean isMutable) {
+ LocalScopedBitmap bitmapHolder(srcHandle);
+ if (!bitmapHolder.valid()) {
+ return NULL;
+ }
+ const Bitmap& original = bitmapHolder->bitmap();
+ const bool hasGainmap = original.hasGainmap();
SkBitmap src;
- reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
+ bitmapHolder->getSkBitmap(&src);
+
if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) {
sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src));
if (!bitmap.get()) {
return NULL;
}
+ if (hasGainmap) {
+ auto gainmap = sp<uirenderer::Gainmap>::make();
+ gainmap->info = original.gainmap()->info;
+ const SkBitmap skSrcBitmap = original.gainmap()->bitmap->getSkBitmap();
+ sk_sp<Bitmap> skBitmap(Bitmap::allocateHardwareBitmap(skSrcBitmap));
+ if (!skBitmap.get()) {
+ return NULL;
+ }
+ gainmap->bitmap = std::move(skBitmap);
+ bitmap->setGainmap(std::move(gainmap));
+ }
return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable));
}
@@ -392,6 +411,18 @@ static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
return NULL;
}
auto bitmap = allocator.getStorageObjAndReset();
+ if (hasGainmap) {
+ auto gainmap = sp<uirenderer::Gainmap>::make();
+ gainmap->info = original.gainmap()->info;
+ const SkBitmap skSrcBitmap = original.gainmap()->bitmap->getSkBitmap();
+ SkBitmap skDestBitmap;
+ HeapAllocator destAllocator;
+ if (!bitmapCopyTo(&skDestBitmap, dstCT, skSrcBitmap, &destAllocator)) {
+ return NULL;
+ }
+ gainmap->bitmap = sk_sp<Bitmap>(destAllocator.getStorageObjAndReset());
+ bitmap->setGainmap(std::move(gainmap));
+ }
return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable));
}
diff --git a/libs/hwui/jni/YuvToJpegEncoder.cpp b/libs/hwui/jni/YuvToJpegEncoder.cpp
index 80bca1f3a72f..6c070fe60844 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.cpp
+++ b/libs/hwui/jni/YuvToJpegEncoder.cpp
@@ -238,7 +238,7 @@ void Yuv422IToJpegEncoder::configSamplingFactors(jpeg_compress_struct* cinfo) {
}
///////////////////////////////////////////////////////////////////////////////
-using namespace android::recoverymap;
+using namespace android::jpegrecoverymap;
jpegr_color_gamut P010Yuv420ToJpegREncoder::findColorGamut(JNIEnv* env, int aDataSpace) {
switch (aDataSpace & ADataSpace::STANDARD_MASK) {
@@ -294,7 +294,7 @@ bool P010Yuv420ToJpegREncoder::encode(JNIEnv* env,
return false;
}
- RecoveryMap recoveryMap;
+ JpegR jpegREncoder;
jpegr_uncompressed_struct p010;
p010.data = hdr;
@@ -314,7 +314,7 @@ bool P010Yuv420ToJpegREncoder::encode(JNIEnv* env,
std::unique_ptr<uint8_t[]> jpegr_data = std::make_unique<uint8_t[]>(jpegR.maxLength);
jpegR.data = jpegr_data.get();
- if (int success = recoveryMap.encodeJPEGR(&p010, &yuv420,
+ if (int success = jpegREncoder.encodeJPEGR(&p010, &yuv420,
hdrTransferFunction,
&jpegR, jpegQuality, nullptr); success != android::OK) {
ALOGW("Encode JPEG/R failed, error code: %d.", success);
diff --git a/libs/hwui/jni/YuvToJpegEncoder.h b/libs/hwui/jni/YuvToJpegEncoder.h
index 3d6d1f3fd3dd..d22a26c83567 100644
--- a/libs/hwui/jni/YuvToJpegEncoder.h
+++ b/libs/hwui/jni/YuvToJpegEncoder.h
@@ -2,7 +2,7 @@
#define _ANDROID_GRAPHICS_YUV_TO_JPEG_ENCODER_H_
#include <android/data_space.h>
-#include <jpegrecoverymap/recoverymap.h>
+#include <jpegrecoverymap/jpegr.h>
extern "C" {
#include "jpeglib.h"
@@ -77,7 +77,7 @@ private:
class P010Yuv420ToJpegREncoder {
public:
/** Encode YUV data to jpeg/r, which is output to a stream.
- * This method will call RecoveryMap::EncodeJPEGR() method. If encoding failed,
+ * This method will call JpegR::EncodeJPEGR() method. If encoding failed,
* Corresponding error code (defined in jpegrerrorcode.h) will be printed and this
* method will be terminated and return false.
*
@@ -103,7 +103,7 @@ public:
* @param aDataSpace data space defined in data_space.h.
* @return color gamut for JPEG/R.
*/
- static android::recoverymap::jpegr_color_gamut findColorGamut(JNIEnv* env, int aDataSpace);
+ static android::jpegrecoverymap::jpegr_color_gamut findColorGamut(JNIEnv* env, int aDataSpace);
/** Map data space (defined in DataSpace.java and data_space.h) to the transfer function
* used in JPEG/R
@@ -112,7 +112,7 @@ public:
* @param aDataSpace data space defined in data_space.h.
* @return color gamut for JPEG/R.
*/
- static android::recoverymap::jpegr_transfer_function findHdrTransferFunction(
+ static android::jpegrecoverymap::jpegr_transfer_function findHdrTransferFunction(
JNIEnv* env, int aDataSpace);
};
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index a55de95035a7..00919dc3f22a 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -33,7 +33,8 @@ namespace skiapipeline {
// Cache size limits.
static const size_t maxKeySize = 1024;
static const size_t maxValueSize = 2 * 1024 * 1024;
-static const size_t maxTotalSize = 1024 * 1024;
+static const size_t maxTotalSize = 4 * 1024 * 1024;
+static_assert(maxKeySize + maxValueSize < maxTotalSize);
ShaderCache::ShaderCache() {
// There is an "incomplete FileBlobCache type" compilation error, if ctor is moved to header.
@@ -175,14 +176,13 @@ void set(BlobCache* cache, const void* key, size_t keySize, const void* value, s
void ShaderCache::saveToDiskLocked() {
ATRACE_NAME("ShaderCache::saveToDiskLocked");
- if (mInitialized && mBlobCache && mSavePending) {
+ if (mInitialized && mBlobCache) {
if (mIDHash.size()) {
auto key = sIDKey;
set(mBlobCache.get(), &key, sizeof(key), mIDHash.data(), mIDHash.size());
}
mBlobCache->writeToFile();
}
- mSavePending = false;
}
void ShaderCache::store(const SkData& key, const SkData& data, const SkString& /*description*/) {
@@ -225,10 +225,10 @@ void ShaderCache::store(const SkData& key, const SkData& data, const SkString& /
}
set(bc, key.data(), keySize, value, valueSize);
- if (!mSavePending && mDeferredSaveDelay > 0) {
+ if (!mSavePending && mDeferredSaveDelayMs > 0) {
mSavePending = true;
std::thread deferredSaveThread([this]() {
- sleep(mDeferredSaveDelay);
+ usleep(mDeferredSaveDelayMs * 1000); // milliseconds to microseconds
std::lock_guard<std::mutex> lock(mMutex);
// Store file on disk if there a new shader or Vulkan pipeline cache size changed.
if (mCacheDirty || mNewPipelineCacheSize != mOldPipelineCacheSize) {
@@ -237,6 +237,7 @@ void ShaderCache::store(const SkData& key, const SkData& data, const SkString& /
mTryToStorePipelineCache = false;
mCacheDirty = false;
}
+ mSavePending = false;
});
deferredSaveThread.detach();
}
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index bc35fa5f9987..f5506d60f811 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -156,7 +156,8 @@ private:
* pending. Each time a key/value pair is inserted into the cache via
* load, a deferred save is initiated if one is not already pending.
* This will wait some amount of time and then trigger a save of the cache
- * contents to disk.
+ * contents to disk, unless mDeferredSaveDelayMs is 0 in which case saving
+ * is disabled.
*/
bool mSavePending = false;
@@ -166,9 +167,11 @@ private:
size_t mObservedBlobValueSize = 20 * 1024;
/**
- * The time in seconds to wait before saving newly inserted cache entries.
+ * The time in milliseconds to wait before saving newly inserted cache entries.
+ *
+ * WARNING: setting this to 0 will disable writing the cache to disk.
*/
- unsigned int mDeferredSaveDelay = 4;
+ unsigned int mDeferredSaveDelayMs = 4 * 1000;
/**
* "mMutex" is the mutex used to prevent concurrent access to the member
diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp
index 576e9466d322..7bcd45c6b643 100644
--- a/libs/hwui/tests/unit/ShaderCacheTests.cpp
+++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#include <GrDirectContext.h>
+#include <Properties.h>
+#include <SkData.h>
+#include <SkRefCnt.h>
#include <cutils/properties.h>
#include <dirent.h>
#include <errno.h>
@@ -22,11 +26,12 @@
#include <stdlib.h>
#include <sys/types.h>
#include <utils/Log.h>
+
#include <cstdint>
+
#include "FileBlobCache.h"
#include "pipeline/skia/ShaderCache.h"
-#include <SkData.h>
-#include <SkRefCnt.h>
+#include "tests/common/TestUtils.h"
using namespace android::uirenderer::skiapipeline;
@@ -37,11 +42,38 @@ namespace skiapipeline {
class ShaderCacheTestUtils {
public:
/**
- * "setSaveDelay" sets the time in seconds to wait before saving newly inserted cache entries.
- * If set to 0, then deferred save is disabled.
+ * Hack to reset all member variables of the given cache to their default / initial values.
+ *
+ * WARNING: this must be kept up to date manually, since ShaderCache's parent disables just
+ * reassigning a new instance.
*/
- static void setSaveDelay(ShaderCache& cache, unsigned int saveDelay) {
- cache.mDeferredSaveDelay = saveDelay;
+ static void reinitializeAllFields(ShaderCache& cache) {
+ ShaderCache newCache = ShaderCache();
+ std::lock_guard<std::mutex> lock(cache.mMutex);
+ // By order of declaration
+ cache.mInitialized = newCache.mInitialized;
+ cache.mBlobCache.reset(nullptr);
+ cache.mFilename = newCache.mFilename;
+ cache.mIDHash.clear();
+ cache.mSavePending = newCache.mSavePending;
+ cache.mObservedBlobValueSize = newCache.mObservedBlobValueSize;
+ cache.mDeferredSaveDelayMs = newCache.mDeferredSaveDelayMs;
+ cache.mTryToStorePipelineCache = newCache.mTryToStorePipelineCache;
+ cache.mInStoreVkPipelineInProgress = newCache.mInStoreVkPipelineInProgress;
+ cache.mNewPipelineCacheSize = newCache.mNewPipelineCacheSize;
+ cache.mOldPipelineCacheSize = newCache.mOldPipelineCacheSize;
+ cache.mCacheDirty = newCache.mCacheDirty;
+ cache.mNumShadersCachedInRam = newCache.mNumShadersCachedInRam;
+ }
+
+ /**
+ * "setSaveDelayMs" sets the time in milliseconds to wait before saving newly inserted cache
+ * entries. If set to 0, then deferred save is disabled, and "saveToDiskLocked" must be called
+ * manually, as seen in the "terminate" testing helper function.
+ */
+ static void setSaveDelayMs(ShaderCache& cache, unsigned int saveDelayMs) {
+ std::lock_guard<std::mutex> lock(cache.mMutex);
+ cache.mDeferredSaveDelayMs = saveDelayMs;
}
/**
@@ -50,8 +82,9 @@ public:
*/
static void terminate(ShaderCache& cache, bool saveContent) {
std::lock_guard<std::mutex> lock(cache.mMutex);
- cache.mSavePending = saveContent;
- cache.saveToDiskLocked();
+ if (saveContent) {
+ cache.saveToDiskLocked();
+ }
cache.mBlobCache = NULL;
}
@@ -62,6 +95,38 @@ public:
static bool validateCache(ShaderCache& cache, std::vector<T> hash) {
return cache.validateCache(hash.data(), hash.size() * sizeof(T));
}
+
+ /**
+ * Waits until cache::mSavePending is false, checking every 0.1 ms *while the mutex is free*.
+ *
+ * Fails if there was no save pending, or if the cache was already being written to disk, or if
+ * timeoutMs is exceeded.
+ *
+ * Note: timeoutMs only guards against mSavePending getting stuck like in b/268205519, and
+ * cannot protect against mutex-based deadlock. Reaching timeoutMs implies something is broken,
+ * so setting it to a sufficiently large value will not delay execution in the happy state.
+ */
+ static void waitForPendingSave(ShaderCache& cache, const int timeoutMs = 50) {
+ {
+ std::lock_guard<std::mutex> lock(cache.mMutex);
+ ASSERT_TRUE(cache.mSavePending);
+ }
+ bool saving = true;
+ float elapsedMilliseconds = 0;
+ while (saving) {
+ if (elapsedMilliseconds >= timeoutMs) {
+ FAIL() << "Timed out after waiting " << timeoutMs << " ms for a pending save";
+ }
+ // This small (0.1 ms) delay is to avoid working too much while waiting for
+ // deferredSaveThread to take the mutex and start the disk write.
+ const int delayMicroseconds = 100;
+ usleep(delayMicroseconds);
+ elapsedMilliseconds += (float)delayMicroseconds / 1000;
+
+ std::lock_guard<std::mutex> lock(cache.mMutex);
+ saving = cache.mSavePending;
+ }
+ }
};
} /* namespace skiapipeline */
@@ -83,6 +148,18 @@ bool folderExist(const std::string& folderName) {
return false;
}
+/**
+ * Attempts to delete the given file, and asserts that either:
+ * 1. Deletion was successful, OR
+ * 2. The file did not exist.
+ *
+ * Tip: wrap calls to this in ASSERT_NO_FATAL_FAILURE(x) if a test should exit early if this fails.
+ */
+void deleteFileAssertSuccess(const std::string& filePath) {
+ int deleteResult = remove(filePath.c_str());
+ ASSERT_TRUE(0 == deleteResult || ENOENT == errno);
+}
+
inline bool checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) {
return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() &&
0 == memcmp(shader1->data(), shader2->data(), shader1->size());
@@ -93,6 +170,10 @@ inline bool checkShader(const sk_sp<SkData>& shader, const char* program) {
return checkShader(shader, shader2);
}
+inline bool checkShader(const sk_sp<SkData>& shader, const std::string& program) {
+ return checkShader(shader, program.c_str());
+}
+
template <typename T>
bool checkShader(const sk_sp<SkData>& shader, std::vector<T>& program) {
sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size() * sizeof(T));
@@ -103,6 +184,10 @@ void setShader(sk_sp<SkData>& shader, const char* program) {
shader = SkData::MakeWithCString(program);
}
+void setShader(sk_sp<SkData>& shader, const std::string& program) {
+ setShader(shader, program.c_str());
+}
+
template <typename T>
void setShader(sk_sp<SkData>& shader, std::vector<T>& buffer) {
shader = SkData::MakeWithCopy(buffer.data(), buffer.size() * sizeof(T));
@@ -126,13 +211,13 @@ TEST(ShaderCacheTest, testWriteAndRead) {
std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
// remove any test files from previous test run
- int deleteFile = remove(cacheFile1.c_str());
- ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
+ ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
+ ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
std::srand(0);
// read the cache from a file that does not exist
ShaderCache::get().setFilename(cacheFile1.c_str());
- ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save
+ ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 0); // disable deferred save
ShaderCache::get().initShaderDiskCache();
// read a key - should not be found since the cache is empty
@@ -186,7 +271,8 @@ TEST(ShaderCacheTest, testWriteAndRead) {
ASSERT_TRUE(checkShader(outVS2, dataBuffer));
ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
- remove(cacheFile1.c_str());
+ ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
+ ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
}
TEST(ShaderCacheTest, testCacheValidation) {
@@ -198,13 +284,13 @@ TEST(ShaderCacheTest, testCacheValidation) {
std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
// remove any test files from previous test run
- int deleteFile = remove(cacheFile1.c_str());
- ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
+ ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
+ ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
std::srand(0);
// generate identity and read the cache from a file that does not exist
ShaderCache::get().setFilename(cacheFile1.c_str());
- ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save
+ ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 0); // disable deferred save
std::vector<uint8_t> identity(1024);
genRandomData(identity);
ShaderCache::get().initShaderDiskCache(
@@ -278,7 +364,81 @@ TEST(ShaderCacheTest, testCacheValidation) {
}
ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
- remove(cacheFile1.c_str());
+ ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
+ ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
+}
+
+using namespace android::uirenderer;
+RENDERTHREAD_SKIA_PIPELINE_TEST(ShaderCacheTest, testOnVkFrameFlushed) {
+ if (Properties::getRenderPipelineType() != RenderPipelineType::SkiaVulkan) {
+ // RENDERTHREAD_SKIA_PIPELINE_TEST declares both SkiaVK and SkiaGL variants.
+ GTEST_SKIP() << "This test is only applicable to RenderPipelineType::SkiaVulkan";
+ }
+ if (!folderExist(getExternalStorageFolder())) {
+ // Don't run the test if external storage folder is not available
+ return;
+ }
+ std::string cacheFile = getExternalStorageFolder() + "/shaderCacheTest";
+ GrDirectContext* grContext = renderThread.getGrContext();
+
+ // Remove any test files from previous test run
+ ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile));
+
+ // The first iteration of this loop is to save an initial VkPipelineCache data blob to disk,
+ // which sets up the second iteration for a common scenario of comparing a "new" VkPipelineCache
+ // blob passed to "store" against the same blob that's already in the persistent cache from a
+ // previous launch. "reinitializeAllFields" is critical to emulate each iteration being as close
+ // to the state of a freshly launched app as possible, as the initial values of member variables
+ // like mInStoreVkPipelineInProgress and mOldPipelineCacheSize are critical to catch issues
+ // such as b/268205519
+ for (int flushIteration = 1; flushIteration <= 2; flushIteration++) {
+ SCOPED_TRACE("Frame flush iteration " + std::to_string(flushIteration));
+ // Reset *all* in-memory data and reload the cache from disk.
+ ShaderCacheTestUtils::reinitializeAllFields(ShaderCache::get());
+ ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 10); // Delay must be > 0 to save.
+ ShaderCache::get().setFilename(cacheFile.c_str());
+ ShaderCache::get().initShaderDiskCache();
+
+ // 1st iteration: store pipeline data to be read back on a subsequent "boot" of the "app".
+ // 2nd iteration: ensure that an initial frame flush (without storing any shaders) given the
+ // same pipeline data that's already on disk doesn't break the cache.
+ ShaderCache::get().onVkFrameFlushed(grContext);
+ ASSERT_NO_FATAL_FAILURE(ShaderCacheTestUtils::waitForPendingSave(ShaderCache::get()));
+ }
+
+ constexpr char shader1[] = "sassas";
+ constexpr char shader2[] = "someVS";
+ constexpr int numIterations = 3;
+ // Also do n iterations of separate "store some shaders then flush the frame" pairs to just
+ // double-check the cache also doesn't get stuck from that use case.
+ for (int saveIteration = 1; saveIteration <= numIterations; saveIteration++) {
+ SCOPED_TRACE("Shader save iteration " + std::to_string(saveIteration));
+ // Write twice to the in-memory cache, which should start a deferred save with both queued.
+ sk_sp<SkData> inVS;
+ setShader(inVS, shader1 + std::to_string(saveIteration));
+ ShaderCache::get().store(GrProgramDescTest(100), *inVS.get(), SkString());
+ setShader(inVS, shader2 + std::to_string(saveIteration));
+ ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
+
+ // Simulate flush to also save latest pipeline info.
+ ShaderCache::get().onVkFrameFlushed(grContext);
+ ASSERT_NO_FATAL_FAILURE(ShaderCacheTestUtils::waitForPendingSave(ShaderCache::get()));
+ }
+
+ // Reload from disk to ensure saving succeeded.
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
+ ShaderCache::get().initShaderDiskCache();
+
+ // Read twice, ensure equal to last store.
+ sk_sp<SkData> outVS;
+ ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS, shader1 + std::to_string(numIterations)));
+ ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS, shader2 + std::to_string(numIterations)));
+
+ // Clean up.
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
+ ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile));
}
} // namespace
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7de3abc3b0de..5a03ad3780db 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -7625,22 +7625,13 @@ public class AudioManager {
return codecConfigList;
}
- /**
- * Returns a list of audio formats that corresponds to encoding formats
- * supported on offload path for Le audio playback.
- *
- * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
- * supported for offload Le Audio playback
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @NonNull
- public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
+ private List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio(
+ @AudioSystem.BtOffloadDeviceType int deviceType) {
ArrayList<Integer> formatsList = new ArrayList<>();
ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
- AudioSystem.DEVICE_OUT_BLE_HEADSET, formatsList);
+ deviceType, formatsList);
if (status != AudioManager.SUCCESS) {
Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
return leAudioCodecConfigList;
@@ -7657,6 +7648,34 @@ public class AudioManager {
return leAudioCodecConfigList;
}
+ /**
+ * Returns a list of audio formats that corresponds to encoding formats
+ * supported on offload path for Le audio playback.
+ *
+ * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
+ * supported for offload Le Audio playback
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
+ return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_HEADSET);
+ }
+
+ /**
+ * Returns a list of audio formats that corresponds to encoding formats
+ * supported on offload path for Le Broadcast playback.
+ *
+ * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
+ * supported for offload Le Broadcast playback
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @NonNull
+ public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast() {
+ return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
+ }
+
// Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
// (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
// of the ports that exist at the time of the last notification.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 9339c3d69ba2..293d3d2861cd 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -273,10 +273,11 @@ public class AudioSystem
/** @hide */
@IntDef(flag = false, prefix = "DEVICE_", value = {
DEVICE_OUT_BLUETOOTH_A2DP,
- DEVICE_OUT_BLE_HEADSET}
+ DEVICE_OUT_BLE_HEADSET,
+ DEVICE_OUT_BLE_BROADCAST}
)
@Retention(RetentionPolicy.SOURCE)
- public @interface DeviceType {}
+ public @interface BtOffloadDeviceType {}
/**
* @hide
@@ -1970,7 +1971,7 @@ public class AudioSystem
* Returns a list of audio formats (codec) supported on the A2DP and LE audio offload path.
*/
public static native int getHwOffloadFormatsSupportedForBluetoothMedia(
- @DeviceType int deviceType, ArrayList<Integer> formatList);
+ @BtOffloadDeviceType int deviceType, ArrayList<Integer> formatList);
/** @hide */
public static native int setSurroundFormatEnabled(int audioFormat, boolean enabled);
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index 6d65c26b4361..f327e4e76f16 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -29,6 +29,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
+import android.view.Surface;
import java.util.Map;
@@ -74,8 +75,9 @@ public final class MediaProjectionManager {
* Returns an {@link Intent} that <b>must</b> be passed to
* {@link Activity#startActivityForResult(Intent, int)} (or similar) in order to start screen
* capture. The activity will prompt the user whether to allow screen capture. The result of
- * this activity (received by overriding {@link Activity#onActivityResult(int, int, Intent)}
- * should be passed to {@link #getMediaProjection(int, Intent)}.
+ * this activity (received by overriding {@link Activity#onActivityResult(int, int, Intent)
+ * onActivityResult(int, int, Intent)}) should be passed to
+ * {@link #getMediaProjection(int, Intent)}.
* <p>
* Identical to calling {@link #createScreenCaptureIntent(MediaProjectionConfig)} with
* a {@link MediaProjectionConfig#createConfigForUserChoice()}.
@@ -102,8 +104,8 @@ public final class MediaProjectionManager {
* capture. Customizes the activity and resulting {@link MediaProjection} session based up
* the provided {@code config}. The activity will prompt the user whether to allow screen
* capture. The result of this activity (received by overriding
- * {@link Activity#onActivityResult(int, int, Intent)}) should be passed to
- * {@link #getMediaProjection(int, Intent)}.
+ * {@link Activity#onActivityResult(int, int, Intent) onActivityResult(int, int, Intent)})
+ * should be passed to {@link #getMediaProjection(int, Intent)}.
*
* <p>
* If {@link MediaProjectionConfig} was created from:
@@ -146,47 +148,48 @@ public final class MediaProjectionManager {
/**
* Retrieves the {@link MediaProjection} obtained from a successful screen
- * capture request. The result code and data from the request are provided
- * by overriding {@link Activity#onActivityResult(int, int, Intent)
- * onActivityResult(int, int, Intent)}, which is called after starting an
- * activity using {@link #createScreenCaptureIntent()}.
- *
- * <p>Starting from Android {@link android.os.Build.VERSION_CODES#R}, if
- * your application requests the
- * {@link android.Manifest.permission#SYSTEM_ALERT_WINDOW
- * SYSTEM_ALERT_WINDOW} permission, and the user has not explicitly denied
- * it, the permission will be automatically granted until the projection is
- * stopped. The permission allows your app to display user controls on top
- * of the screen being captured.
- *
- * <p>Apps targeting SDK version {@link android.os.Build.VERSION_CODES#Q} or
- * later must set the
- * {@link android.R.attr#foregroundServiceType foregroundServiceType}
- * attribute to {@code mediaProjection} in the
- * <a href="/guide/topics/manifest/service-element">
- * <code>&lt;service&gt;</code></a> element of the app's manifest file;
- * {@code mediaProjection} is equivalent to
+ * capture request. The result code and data from the request are provided by overriding
+ * {@link Activity#onActivityResult(int, int, Intent) onActivityResult(int, int, Intent)},
+ * which is called after starting an activity using {@link #createScreenCaptureIntent()}.
+ * <p>
+ * Starting from Android {@link android.os.Build.VERSION_CODES#R R}, if your application
+ * requests the {@link android.Manifest.permission#SYSTEM_ALERT_WINDOW SYSTEM_ALERT_WINDOW}
+ * permission, and the user has not explicitly denied it, the permission will be automatically
+ * granted until the projection is stopped. The permission allows your app to display user
+ * controls on top of the screen being captured.
+ * </p>
+ * <p>
+ * An app targeting SDK version {@link android.os.Build.VERSION_CODES#Q Q} or later must
+ * invoke {@code getMediaProjection} and maintain the capture session
+ * ({@link MediaProjection#createVirtualDisplay(String, int, int, int, int, Surface,
+ * android.hardware.display.VirtualDisplay.Callback, Handler)
+ * MediaProjection#createVirtualDisplay}) while running a foreground service. The app must set
+ * the {@link android.R.attr#foregroundServiceType foregroundServiceType} attribute to
* {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
- * FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}.
+ * FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION} in the
+ * <a href="/guide/topics/manifest/service-element"><code>&lt;service&gt;</code></a> element of
+ * the app's manifest file.
+ * </p>
*
+ * @param resultCode The result code from {@link Activity#onActivityResult(int, int, Intent)
+ * onActivityResult(int, int, Intent)}.
+ * @param resultData The result data from {@link Activity#onActivityResult(int, int, Intent)
+ * onActivityResult(int, int, Intent)}.
+ * @return The media projection obtained from a successful screen capture request, or null if
+ * the result of the screen capture request is not {@link Activity#RESULT_OK RESULT_OK}.
+ * @throws IllegalStateException On
+ * pre-{@link android.os.Build.VERSION_CODES#Q Q} devices if a
+ * previously obtained {@code MediaProjection} from the same
+ * {@code resultData} has not yet been stopped.
+ * @throws SecurityException On {@link android.os.Build.VERSION_CODES#Q Q}+ devices if not
+ * invoked from a foreground service with type
+ * {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
+ * FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}, unless caller is a
+ * privileged app.
* @see <a href="/guide/components/foreground-services">
- * Foreground services developer guide</a>
+ * Foreground services developer guide</a>
* @see <a href="/guide/topics/large-screens/media-projection">
- * Media projection developer guide</a>
- *
- * @param resultCode The result code from
- * {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)
- * onActivityResult(int, int, Intent)}.
- * @param resultData The result data from
- * {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)
- * onActivityResult(int, int, Intent)}.
- * @return The media projection obtained from a successful screen capture
- * request, or null if the result of the screen capture request is not
- * {@link Activity#RESULT_OK RESULT_OK}.
- * @throws IllegalStateException On
- * pre-{@link android.os.Build.VERSION_CODES#Q Q} devices if a
- * previously obtained {@code MediaProjection} from the same
- * {@code resultData} has not yet been stopped.
+ * Media projection developer guide</a>
*/
public MediaProjection getMediaProjection(int resultCode, @NonNull Intent resultData) {
if (resultCode != Activity.RESULT_OK || resultData == null) {
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index de1b1640ad45..8459538f102d 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -317,25 +317,21 @@ public final class TvInputManager {
/**
* Time shift mode: off.
* <p>Time shift is disabled.
- * @hide
*/
public static final int TIME_SHIFT_MODE_OFF = 1;
/**
* Time shift mode: local.
* <p>Time shift is handle locally, using on-device data. E.g. playing a local file.
- * @hide
*/
public static final int TIME_SHIFT_MODE_LOCAL = 2;
/**
* Time shift mode: network.
* <p>Time shift is handle remotely via network. E.g. online streaming.
- * @hide
*/
public static final int TIME_SHIFT_MODE_NETWORK = 3;
/**
* Time shift mode: auto.
* <p>Time shift mode is handled automatically.
- * @hide
*/
public static final int TIME_SHIFT_MODE_AUTO = 4;
@@ -774,7 +770,11 @@ public final class TvInputManager {
* Informs the app available speeds for time-shifting.
* @param session A {@link TvInputManager.Session} associated with this callback.
* @param speeds An ordered array of playback speeds, expressed as values relative to the
- * normal playback speed 1.0.
+ * normal playback speed (1.0), at which the current content can be played as
+ * a time-shifted broadcast. This is an empty array if the supported playback
+ * speeds are unknown or the video/broadcast is not in time shift mode. If
+ * currently in time shift mode, this array will normally include at least
+ * the values 1.0 (normal speed) and 0.0 (paused).
* @see PlaybackParams#getSpeed()
*/
public void onAvailableSpeeds(Session session, float[] speeds) {
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 000ed3b0758e..4bc137da6f00 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1117,7 +1117,6 @@ public abstract class TvInputService extends Service {
* {@link TvInputManager#TIME_SHIFT_MODE_OFF}, {@link TvInputManager#TIME_SHIFT_MODE_LOCAL},
* {@link TvInputManager#TIME_SHIFT_MODE_NETWORK},
* {@link TvInputManager#TIME_SHIFT_MODE_AUTO}.
- * @hide
*/
public void notifyTimeShiftMode(@android.media.tv.TvInputManager.TimeShiftMode int mode) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1141,9 +1140,12 @@ public abstract class TvInputService extends Service {
* <p>This should be called when time-shifting is enabled.
*
* @param speeds An ordered array of playback speeds, expressed as values relative to the
- * normal playback speed 1.0.
+ * normal playback speed (1.0), at which the current content can be played as
+ * a time-shifted broadcast. This is an empty array if the supported playback
+ * speeds are unknown or the video/broadcast is not in time shift mode. If
+ * currently in time shift mode, this array will normally include at least
+ * the values 1.0 (normal speed) and 0.0 (paused).
* @see PlaybackParams#getSpeed()
- * @hide
*/
public void notifyAvailableSpeeds(@NonNull float[] speeds) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1191,7 +1193,6 @@ public abstract class TvInputService extends Service {
*
* @param available {@code true} if cueing message is available; {@code false} if it becomes
* unavailable.
- * @hide
*/
public void notifyCueingMessageAvailability(boolean available) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -1575,7 +1576,6 @@ public abstract class TvInputService extends Service {
* {@link TvInputManager#TIME_SHIFT_MODE_OFF}, {@link TvInputManager#TIME_SHIFT_MODE_LOCAL},
* {@link TvInputManager#TIME_SHIFT_MODE_NETWORK},
* {@link TvInputManager#TIME_SHIFT_MODE_AUTO}.
- * @hide
*/
public void onTimeShiftSetMode(@android.media.tv.TvInputManager.TimeShiftMode int mode) {
}
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index cdeef2bfddd3..9a995a0b9262 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -78,18 +78,28 @@ public class TvRecordingClient {
*
* @param view The related {@link TvInteractiveAppView} instance that is linked to this TV
* recording client. {@code null} to unlink the view.
- * @param recordingId The ID of the recording which is assigned by applications. {@code null} is
- * valid only when the TvInteractiveAppView parameter is null.
- * @hide
+ * @param recordingId The ID of the recording which is assigned by the TV application.
+ * {@code null} if and only if the TvInteractiveAppView parameter is
+ * {@code null}.
+ * @throws IllegalArgumentException when recording ID is {@code null} and the
+ * TvInteractiveAppView is not {@code null}; or when recording
+ * ID is not {@code null} and the TvInteractiveAppView is
+ * {@code null}.
+ * @see TvInteractiveAppView#notifyRecordingScheduled(String, String)
+ * @see TvInteractiveAppView#notifyRecordingStarted(String, String)
*/
public void setTvInteractiveAppView(
@Nullable TvInteractiveAppView view, @Nullable String recordingId) {
if (view != null && recordingId == null) {
throw new IllegalArgumentException(
- "null recordingId is allowed only when the view is null");
+ "null recordingId is not allowed only when the view is not null");
+ }
+ if (view == null && recordingId != null) {
+ throw new IllegalArgumentException(
+ "recordingId should be null when the view is null");
}
mTvIAppView = view;
- mRecordingId = view == null ? null : recordingId;
+ mRecordingId = recordingId;
}
/**
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 372fa6d53b4c..3ef61f289e23 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -633,7 +633,6 @@ public class TvView extends ViewGroup {
* {@link TvInputManager#TIME_SHIFT_MODE_OFF}, {@link TvInputManager#TIME_SHIFT_MODE_LOCAL},
* {@link TvInputManager#TIME_SHIFT_MODE_NETWORK},
* {@link TvInputManager#TIME_SHIFT_MODE_AUTO}.
- * @hide
*/
public void timeShiftSetMode(@android.media.tv.TvInputManager.TimeShiftMode int mode) {
if (mSession != null) {
@@ -1193,7 +1192,6 @@ public class TvView extends ViewGroup {
* @param inputId The ID of the TV input bound to this view.
* @param available The current availability of cueing message. {@code true} if cueing
* message is available; {@code false} if it becomes unavailable.
- * @hide
*/
public void onCueingMessageAvailability(@NonNull String inputId, boolean available) {
}
@@ -1206,7 +1204,6 @@ public class TvView extends ViewGroup {
* {@link TvInputManager#TIME_SHIFT_MODE_OFF}, {@link TvInputManager#TIME_SHIFT_MODE_LOCAL},
* {@link TvInputManager#TIME_SHIFT_MODE_NETWORK},
* {@link TvInputManager#TIME_SHIFT_MODE_AUTO}.
- * @hide
*/
public void onTimeShiftMode(
@NonNull String inputId, @TvInputManager.TimeShiftMode int mode) {
@@ -1217,11 +1214,14 @@ public class TvView extends ViewGroup {
*
* @param inputId The ID of the TV input bound to this view.
* @param speeds An ordered array of playback speeds, expressed as values relative to the
- * normal playback speed 1.0.
+ * normal playback speed (1.0), at which the current content can be played as
+ * a time-shifted broadcast. This is an empty array if the supported playback
+ * speeds are unknown or the video/broadcast is not in time shift mode. If
+ * currently in time shift mode, this array will normally include at least
+ * the values 1.0 (normal speed) and 0.0 (paused).
* @see PlaybackParams#getSpeed()
- * @hide
*/
- public void onAvailableSpeeds(@NonNull String inputId, float[] speeds) {
+ public void onAvailableSpeeds(@NonNull String inputId, @NonNull float[] speeds) {
}
/**
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index aac2d616d2e9..36954ad00f5f 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -51,12 +51,12 @@ oneway interface ITvInteractiveAppClient {
void onRequestCurrentTvInputId(int seq);
void onRequestTimeShiftMode(int seq);
void onRequestAvailableSpeeds(int seq);
- void onRequestStartRecording(in Uri programUri, int seq);
+ void onRequestStartRecording(in String requestId, in Uri programUri, int seq);
void onRequestStopRecording(in String recordingId, int seq);
- void onRequestScheduleRecording(in String inputId, in Uri channelUri, in Uri programUri,
- in Bundle params, int seq);
- void onRequestScheduleRecording2(in String inputId, in Uri channelUri, long start,
- long duration, int repeat, in Bundle params, int seq);
+ void onRequestScheduleRecording(in String requestId, in String inputId, in Uri channelUri,
+ in Uri programUri, in Bundle params, int seq);
+ void onRequestScheduleRecording2(in String requestId, in String inputId, in Uri channelUri,
+ long start, long duration, int repeat, in Bundle params, int seq);
void onSetTvRecordingInfo(in String recordingId, in TvRecordingInfo recordingInfo, int seq);
void onRequestTvRecordingInfo(in String recordingId, int seq);
void onRequestTvRecordingInfoList(in int type, int seq);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
index e362af2249b3..89847a73ccde 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl
@@ -91,7 +91,8 @@ interface ITvInteractiveAppManager {
void notifyContentAllowed(in IBinder sessionToken, int userId);
void notifyContentBlocked(in IBinder sessionToken, in String rating, int userId);
void notifySignalStrength(in IBinder sessionToken, int stength, int userId);
- void notifyRecordingStarted(in IBinder sessionToken, in String recordingId, int userId);
+ void notifyRecordingStarted(in IBinder sessionToken, in String recordingId, String requestId,
+ int userId);
void notifyRecordingStopped(in IBinder sessionToken, in String recordingId, int userId);
void notifyTvMessage(in IBinder sessionToken, in String type, in Bundle data, int userId);
void setSurface(in IBinder sessionToken, in Surface surface, int userId);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
index 8d7714105797..f17d1b73994e 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl
@@ -70,7 +70,7 @@ oneway interface ITvInteractiveAppSession {
void notifyContentAllowed();
void notifyContentBlocked(in String rating);
void notifySignalStrength(int strength);
- void notifyRecordingStarted(in String recordingId);
+ void notifyRecordingStarted(in String recordingId, in String requestId);
void notifyRecordingStopped(in String recordingId);
void notifyTvMessage(in String type, in Bundle data);
void setSurface(in Surface surface);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index b71f23c00392..7db860489e8a 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -50,12 +50,12 @@ oneway interface ITvInteractiveAppSessionCallback {
void onRequestCurrentTvInputId();
void onRequestTimeShiftMode();
void onRequestAvailableSpeeds();
- void onRequestStartRecording(in Uri programUri);
+ void onRequestStartRecording(in String requestId, in Uri programUri);
void onRequestStopRecording(in String recordingId);
- void onRequestScheduleRecording(in String inputId, in Uri channelUri, in Uri programUri,
- in Bundle params);
- void onRequestScheduleRecording2(in String inputId, in Uri channelUri, long start,
- long duration, int repeat, in Bundle params);
+ void onRequestScheduleRecording(in String requestId, in String inputId, in Uri channelUri,
+ in Uri programUri, in Bundle params);
+ void onRequestScheduleRecording2(in String requestId, in String inputId, in Uri channelUri,
+ long start, long duration, int repeat, in Bundle params);
void onSetTvRecordingInfo(in String recordingId, in TvRecordingInfo recordingInfo);
void onRequestTvRecordingInfo(in String recordingId);
void onRequestTvRecordingInfoList(in int type);
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
index f009ceab0a75..ba30e799dbe2 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java
@@ -206,7 +206,9 @@ public class ITvInteractiveAppSessionWrapper
break;
}
case DO_NOTIFY_RECORDING_STARTED: {
- mSessionImpl.notifyRecordingStarted((String) msg.obj);
+ SomeArgs args = (SomeArgs) msg.obj;
+ mSessionImpl.notifyRecordingStarted((String) args.arg1, (String) args.arg2);
+ args.recycle();
break;
}
case DO_NOTIFY_RECORDING_STOPPED: {
@@ -555,9 +557,9 @@ public class ITvInteractiveAppSessionWrapper
}
@Override
- public void notifyRecordingStarted(String recordingId) {
- mCaller.executeOrSendMessage(mCaller.obtainMessageO(
- DO_NOTIFY_RECORDING_STARTED, recordingId));
+ public void notifyRecordingStarted(String recordingId, String requestId) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageOO(
+ DO_NOTIFY_RECORDING_STARTED, recordingId, recordingId));
}
@Override
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index c88c8d405c05..3e31bce30baa 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -542,14 +542,14 @@ public final class TvInteractiveAppManager {
}
@Override
- public void onRequestStartRecording(Uri programUri, int seq) {
+ public void onRequestStartRecording(String requestId, Uri programUri, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
- record.postRequestStartRecording(programUri);
+ record.postRequestStartRecording(requestId, programUri);
}
}
@@ -566,29 +566,31 @@ public final class TvInteractiveAppManager {
}
@Override
- public void onRequestScheduleRecording(String inputId, Uri channelUri, Uri programUri,
- Bundle params, int seq) {
+ public void onRequestScheduleRecording(String requestId, String inputId, Uri channelUri,
+ Uri programUri, Bundle params, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
- record.postRequestScheduleRecording(inputId, channelUri, programUri, params);
+ record.postRequestScheduleRecording(
+ requestId, inputId, channelUri, programUri, params);
}
}
@Override
- public void onRequestScheduleRecording2(String inputId, Uri channelUri, long startTime,
- long duration, int repeatDays, Bundle params, int seq) {
+ public void onRequestScheduleRecording2(String requestId, String inputId,
+ Uri channelUri, long startTime, long duration, int repeatDays, Bundle params,
+ int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
- record.postRequestScheduleRecording(
- inputId, channelUri, startTime, duration, repeatDays, params);
+ record.postRequestScheduleRecording(requestId, inputId, channelUri, startTime,
+ duration, repeatDays, params);
}
}
@@ -935,7 +937,6 @@ public final class TvInteractiveAppManager {
* can be detected by the system.
*
* @return List of {@link AppLinkInfo} for each package that deslares its app link information.
- * @hide
*/
@NonNull
public List<AppLinkInfo> getAppLinkInfoList() {
@@ -1268,13 +1269,13 @@ public final class TvInteractiveAppManager {
}
}
- void notifyRecordingStarted(String recordingId) {
+ void notifyRecordingStarted(String recordingId, String requestId) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
- mService.notifyRecordingStarted(mToken, recordingId, mUserId);
+ mService.notifyRecordingStarted(mToken, recordingId, requestId, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2130,11 +2131,11 @@ public final class TvInteractiveAppManager {
});
}
- void postRequestStartRecording(Uri programUri) {
+ void postRequestStartRecording(String requestId, Uri programUri) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCallback.onRequestStartRecording(mSession, programUri);
+ mSessionCallback.onRequestStartRecording(mSession, requestId, programUri);
}
});
}
@@ -2148,24 +2149,24 @@ public final class TvInteractiveAppManager {
});
}
- void postRequestScheduleRecording(String inputId, Uri channelUri, Uri programUri,
- Bundle params) {
+ void postRequestScheduleRecording(String requestId, String inputId, Uri channelUri,
+ Uri programUri, Bundle params) {
mHandler.post(new Runnable() {
@Override
public void run() {
mSessionCallback.onRequestScheduleRecording(
- mSession, inputId, channelUri, programUri, params);
+ mSession, requestId, inputId, channelUri, programUri, params);
}
});
}
- void postRequestScheduleRecording(String inputId, Uri channelUri, long startTime,
- long duration, int repeatDays, Bundle params) {
+ void postRequestScheduleRecording(String requestId, String inputId, Uri channelUri,
+ long startTime, long duration, int repeatDays, Bundle params) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mSessionCallback.onRequestScheduleRecording(
- mSession, inputId, channelUri, startTime, duration, repeatDays, params);
+ mSessionCallback.onRequestScheduleRecording(mSession, requestId, inputId,
+ channelUri, startTime, duration, repeatDays, params);
}
});
}
@@ -2406,7 +2407,7 @@ public final class TvInteractiveAppManager {
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
* @param programUri The Uri of the program to be recorded.
*/
- public void onRequestStartRecording(Session session, Uri programUri) {
+ public void onRequestStartRecording(Session session, String requestId, Uri programUri) {
}
/**
@@ -2421,7 +2422,7 @@ public final class TvInteractiveAppManager {
/**
* This is called when
- * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, Uri, Bundle)}
+ * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, Uri, Bundle)}
* is called.
*
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
@@ -2434,13 +2435,14 @@ public final class TvInteractiveAppManager {
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
*/
- public void onRequestScheduleRecording(Session session, @NonNull String inputId,
- @NonNull Uri channelUri, @NonNull Uri programUri, @NonNull Bundle params) {
+ public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+ @NonNull String inputId, @NonNull Uri channelUri, @NonNull Uri programUri,
+ @NonNull Bundle params) {
}
/**
* This is called when
- * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, long, long, int, Bundle)}
+ * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, long, long, int, Bundle)}
* is called.
*
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
@@ -2455,9 +2457,9 @@ public final class TvInteractiveAppManager {
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
*/
- public void onRequestScheduleRecording(Session session, @NonNull String inputId,
- @NonNull Uri channelUri, long startTime, long duration, int repeatDays,
- @NonNull Bundle params) {
+ public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+ @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration,
+ int repeatDays, @NonNull Bundle params) {
}
/**
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 80b6e216780f..1ae82f43b9dd 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -231,41 +231,34 @@ public abstract class TvInteractiveAppService extends Service {
* Time shift command type: play.
*
* @see TvView#timeShiftPlay(String, Uri)
- * @hide
*/
public static final String TIME_SHIFT_COMMAND_TYPE_PLAY = "play";
/**
* Time shift command type: pause.
*
* @see TvView#timeShiftPause()
- * @hide
*/
public static final String TIME_SHIFT_COMMAND_TYPE_PAUSE = "pause";
/**
* Time shift command type: resume.
*
* @see TvView#timeShiftResume()
- * @hide
*/
public static final String TIME_SHIFT_COMMAND_TYPE_RESUME = "resume";
/**
* Time shift command type: seek to.
*
* @see TvView#timeShiftSeekTo(long)
- * @hide
*/
public static final String TIME_SHIFT_COMMAND_TYPE_SEEK_TO = "seek_to";
/**
* Time shift command type: set playback params.
*
* @see TvView#timeShiftSetPlaybackParams(PlaybackParams)
- * @hide
*/
public static final String TIME_SHIFT_COMMAND_TYPE_SET_PLAYBACK_PARAMS = "set_playback_params";
/**
* Time shift command type: set time shift mode.
- *
- * @hide
*/
public static final String TIME_SHIFT_COMMAND_TYPE_SET_MODE = "set_mode";
@@ -274,7 +267,6 @@ public abstract class TvInteractiveAppService extends Service {
* <p>Type: android.net.Uri
*
* @see #TIME_SHIFT_COMMAND_TYPE_PLAY
- * @hide
*/
public static final String COMMAND_PARAMETER_KEY_PROGRAM_URI = "command_program_uri";
/**
@@ -282,7 +274,6 @@ public abstract class TvInteractiveAppService extends Service {
* <p>Type: long
*
* @see #TIME_SHIFT_COMMAND_TYPE_SEEK_TO
- * @hide
*/
public static final String COMMAND_PARAMETER_KEY_TIME_POSITION = "command_time_position";
/**
@@ -290,7 +281,6 @@ public abstract class TvInteractiveAppService extends Service {
* <p>Type: android.media.PlaybackParams
*
* @see #TIME_SHIFT_COMMAND_TYPE_SET_PLAYBACK_PARAMS
- * @hide
*/
public static final String COMMAND_PARAMETER_KEY_PLAYBACK_PARAMS = "command_playback_params";
/**
@@ -301,7 +291,6 @@ public abstract class TvInteractiveAppService extends Service {
* {@link TvInputManager#TIME_SHIFT_MODE_AUTO}.
*
* @see #TIME_SHIFT_COMMAND_TYPE_SET_MODE
- * @hide
*/
public static final String COMMAND_PARAMETER_KEY_TIME_SHIFT_MODE = "command_time_shift_mode";
@@ -589,18 +578,24 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Receives current time shift mode.
+ *
* @param mode The current time shift mode. The value is one of the following:
* {@link TvInputManager#TIME_SHIFT_MODE_OFF}, {@link TvInputManager#TIME_SHIFT_MODE_LOCAL},
* {@link TvInputManager#TIME_SHIFT_MODE_NETWORK},
* {@link TvInputManager#TIME_SHIFT_MODE_AUTO}.
- * @hide
*/
public void onTimeShiftMode(@android.media.tv.TvInputManager.TimeShiftMode int mode) {
}
/**
- * Receives available speeds.
- * @hide
+ * Receives available playback speeds.
+ *
+ * @param speeds An ordered array of playback speeds, expressed as values relative to the
+ * normal playback speed (1.0), at which the current content can be played as
+ * a time-shifted broadcast. This is an empty array if the supported playback
+ * speeds are unknown or the video/broadcast is not in time shift mode. If
+ * currently in time shift mode, this array will normally include at least
+ * the values 1.0 (normal speed) and 0.0 (paused).
*/
public void onAvailableSpeeds(@NonNull float[] speeds) {
}
@@ -624,21 +619,28 @@ public abstract class TvInteractiveAppService extends Service {
public void onTvRecordingInfoList(@NonNull List<TvRecordingInfo> recordingInfoList) {}
/**
- * Receives started recording's ID.
+ * This is called when a recording has been started.
+ *
+ * <p>When a scheduled recording is started, this is also called, and the request ID in this
+ * case is {@code null}.
*
* @param recordingId The ID of the recording started. The TV app should provide and
* maintain this ID to identify the recording in the future.
+ * @param requestId The ID of the request when
+ * {@link #requestStartRecording(String, Uri)} is called.
+ * {@code null} if the recording is not triggered by a
+ * {@link #requestStartRecording(String, Uri)} request.
* @see #onRecordingStopped(String)
*/
- public void onRecordingStarted(@NonNull String recordingId) {
+ public void onRecordingStarted(@NonNull String recordingId, @Nullable String requestId) {
}
/**
- * Receives stopped recording's ID.
+ * This is called when the recording has been stopped.
*
* @param recordingId The ID of the recording stopped. This ID is created and maintained by
* the TV app when the recording was started.
- * @see #onRecordingStarted(String)
+ * @see #onRecordingStarted(String, String)
*/
public void onRecordingStopped(@NonNull String recordingId) {
}
@@ -648,10 +650,9 @@ public abstract class TvInteractiveAppService extends Service {
* session for the corresponding TV input.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param inputId The ID of the TV input bound to the current TvRecordingClient.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onConnectionFailed(String)
- * @hide
*/
public void onRecordingConnectionFailed(
@NonNull String recordingId, @NonNull String inputId) {
@@ -661,10 +662,9 @@ public abstract class TvInteractiveAppService extends Service {
* This is called when the connection to the current recording session is lost.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param inputId The ID of the TV input bound to the current TvRecordingClient.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onDisconnected(String)
- * @hide
*/
public void onRecordingDisconnected(@NonNull String recordingId, @NonNull String inputId) {
}
@@ -674,10 +674,9 @@ public abstract class TvInteractiveAppService extends Service {
* ready to start recording.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param channelUri The URI of the tuned channel.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onTuned(Uri)
- * @hide
*/
public void onRecordingTuned(@NonNull String recordingId, @NonNull Uri channelUri) {
}
@@ -687,7 +686,7 @@ public abstract class TvInteractiveAppService extends Service {
* recording session is created until it is released.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param err The error code. Should be one of the following.
* <ul>
* <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
@@ -695,7 +694,6 @@ public abstract class TvInteractiveAppService extends Service {
* <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY}
* </ul>
* @see android.media.tv.TvRecordingClient.RecordingCallback#onError(int)
- * @hide
*/
public void onRecordingError(
@NonNull String recordingId, @TvInputManager.RecordingError int err) {
@@ -707,9 +705,9 @@ public abstract class TvInteractiveAppService extends Service {
* @param recordingId The ID assigned to this recording by the app. It can be used to send
* recording related requests such as
* {@link #requestStopRecording(String)}.
- * @param requestId The ID of the request when requestScheduleRecording is called.
+ * @param requestId The ID of the request when
+ * {@link #requestScheduleRecording} is called.
* {@code null} if the recording is not triggered by a request.
- * @hide
*/
public void onRecordingScheduled(@NonNull String recordingId, @Nullable String requestId) {
}
@@ -742,8 +740,8 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Called when the time shift {@link android.media.PlaybackParams} is set or changed.
*
+ * @param params The new {@link PlaybackParams} that was set or changed.
* @see TvView#timeShiftSetPlaybackParams(PlaybackParams)
- * @hide
*/
public void onTimeShiftPlaybackParams(@NonNull PlaybackParams params) {
}
@@ -753,17 +751,25 @@ public abstract class TvInteractiveAppService extends Service {
*
* @see TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)
* @see android.media.tv.TvInputService.Session#notifyTimeShiftStatusChanged(int)
- * @hide
+ * @param inputId The ID of the input for which the time shift status has changed.
+ * @param status The status of which the input has changed to. Should be one of the
+ * following.
+ * <ul>
+ * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNKNOWN}
+ * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED}
+ * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNAVAILABLE}
+ * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE}
+ * </ul>
*/
public void onTimeShiftStatusChanged(
- @NonNull String inputId, @TvInputManager.TimeShiftStatus int status) {
- }
+ @NonNull String inputId, @TvInputManager.TimeShiftStatus int status) {}
/**
* Called when time shift start position is changed.
*
* @see TvView.TimeShiftPositionCallback#onTimeShiftStartPositionChanged(String, long)
- * @hide
+ * @param inputId The ID of the input for which the time shift start position has changed.
+ * @param timeMs The start position for time shifting, in milliseconds since the epoch.
*/
public void onTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) {
}
@@ -772,7 +778,8 @@ public abstract class TvInteractiveAppService extends Service {
* Called when time shift current position is changed.
*
* @see TvView.TimeShiftPositionCallback#onTimeShiftCurrentPositionChanged(String, long)
- * @hide
+ * @param inputId The ID of the input for which the time shift current position has changed.
+ * @param timeMs The current position for time shifting, in milliseconds since the epoch.
*/
public void onTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) {
}
@@ -1086,7 +1093,6 @@ public abstract class TvInteractiveAppService extends Service {
*
* @param cmdType type of the specific command
* @param parameters parameters of the specific command
- * @hide
*/
@CallSuper
public void sendTimeShiftCommandRequest(
@@ -1275,7 +1281,6 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Requests time shift mode.
- * @hide
*/
@CallSuper
public void requestTimeShiftMode() {
@@ -1299,7 +1304,6 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Requests available speeds for time shift.
- * @hide
*/
@CallSuper
public void requestAvailableSpeeds() {
@@ -1331,18 +1335,22 @@ public abstract class TvInteractiveAppService extends Service {
* program, whereas null {@code programUri} does not impose such a requirement and the
* recording can span across multiple TV programs.
*
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #onRecordingStarted(String, String)} for this request is the
+ * same as the ID sent here.
* @param programUri The URI for the TV program to record.
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
*/
@CallSuper
- public void requestStartRecording(@Nullable Uri programUri) {
+ public void requestStartRecording(@NonNull String requestId, @Nullable Uri programUri) {
executeOrPostRunnableOnMainThread(() -> {
try {
if (DEBUG) {
Log.d(TAG, "requestStartRecording");
}
if (mSessionCallback != null) {
- mSessionCallback.onRequestStartRecording(programUri);
+ mSessionCallback.onRequestStartRecording(requestId, programUri);
}
} catch (RemoteException e) {
Log.w(TAG, "error in requestStartRecording", e);
@@ -1357,7 +1365,7 @@ public abstract class TvInteractiveAppService extends Service {
* call {@link android.media.tv.TvRecordingClient#stopRecording()}.
*
* @param recordingId The ID of the recording to stop. This is provided by the TV app in
- * {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @see android.media.tv.TvRecordingClient#stopRecording()
*/
@CallSuper
@@ -1379,6 +1387,10 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Requests scheduling of a recording.
*
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #onRecordingScheduled(String, String)} for this request is the
+ * same as the ID sent here.
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel to be recorded.
* @param programUri The URI of the TV program to be recorded.
@@ -1387,11 +1399,10 @@ public abstract class TvInteractiveAppService extends Service {
* will not create conflicting keys.
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
- * @hide
*/
@CallSuper
- public void requestScheduleRecording(@NonNull String inputId, @NonNull Uri channelUri,
- @NonNull Uri programUri, @NonNull Bundle params) {
+ public void requestScheduleRecording(@NonNull String requestId, @NonNull String inputId,
+ @NonNull Uri channelUri, @NonNull Uri programUri, @NonNull Bundle params) {
executeOrPostRunnableOnMainThread(() -> {
try {
if (DEBUG) {
@@ -1399,7 +1410,7 @@ public abstract class TvInteractiveAppService extends Service {
}
if (mSessionCallback != null) {
mSessionCallback.onRequestScheduleRecording(
- inputId, channelUri, programUri, params);
+ requestId, inputId, channelUri, programUri, params);
}
} catch (RemoteException e) {
Log.w(TAG, "error in requestScheduleRecording", e);
@@ -1410,6 +1421,10 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Requests scheduling of a recording.
*
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #onRecordingScheduled(String, String)} for this request is the
+ * same as the ID sent here.
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel to be recorded.
* @param startTime The start time of the recording in milliseconds since epoch.
@@ -1420,19 +1435,19 @@ public abstract class TvInteractiveAppService extends Service {
* will not create conflicting keys.
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
- * @hide
*/
@CallSuper
- public void requestScheduleRecording(@NonNull String inputId, @NonNull Uri channelUri,
- long startTime, long duration, int repeatDays, @NonNull Bundle params) {
+ public void requestScheduleRecording(@NonNull String requestId, @NonNull String inputId,
+ @NonNull Uri channelUri, long startTime, long duration, int repeatDays,
+ @NonNull Bundle params) {
executeOrPostRunnableOnMainThread(() -> {
try {
if (DEBUG) {
Log.d(TAG, "requestScheduleRecording");
}
if (mSessionCallback != null) {
- mSessionCallback.onRequestScheduleRecording2(
- inputId, channelUri, startTime, duration, repeatDays, params);
+ mSessionCallback.onRequestScheduleRecording2(requestId, inputId, channelUri,
+ startTime, duration, repeatDays, params);
}
} catch (RemoteException e) {
Log.w(TAG, "error in requestScheduleRecording", e);
@@ -1444,7 +1459,7 @@ public abstract class TvInteractiveAppService extends Service {
* Sets the recording info for the specified recording
*
* @param recordingId The ID of the recording to set the info for. This is provided by the
- * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+ * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param recordingInfo The {@link TvRecordingInfo} to set to the recording.
*/
@CallSuper
@@ -1467,7 +1482,8 @@ public abstract class TvInteractiveAppService extends Service {
/**
* Gets the recording info for the specified recording
* @param recordingId The ID of the recording to set the info for. This is provided by the
- * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+ * TV app in
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
*/
@CallSuper
public void requestTvRecordingInfo(@NonNull String recordingId) {
@@ -1756,10 +1772,10 @@ public abstract class TvInteractiveAppService extends Service {
}
/**
- * Calls {@link #onRecordingStarted(String)}.
+ * Calls {@link #onRecordingStarted(String, String)}.
*/
- void notifyRecordingStarted(String recordingId) {
- onRecordingStarted(recordingId);
+ void notifyRecordingStarted(String recordingId, String requestId) {
+ onRecordingStarted(recordingId, requestId);
}
/**
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
index acc2444e1213..0455d7b82bf4 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java
@@ -68,15 +68,9 @@ public final class TvInteractiveAppServiceInfo implements Parcelable {
public static final int INTERACTIVE_APP_TYPE_ATSC = 0x2;
/** Ginga interactive app type */
public static final int INTERACTIVE_APP_TYPE_GINGA = 0x4;
- /**
- * Targeted Advertisement interactive app type
- * @hide
- */
+ /** Targeted Advertisement interactive app type */
public static final int INTERACTIVE_APP_TYPE_TARGETED_AD = 0x8;
- /**
- * Other interactive app type
- * @hide
- */
+ /** Other interactive app type */
public static final int INTERACTIVE_APP_TYPE_OTHER = 0x80000000;
private final ResolveInfo mService;
@@ -180,7 +174,20 @@ public final class TvInteractiveAppServiceInfo implements Parcelable {
}
/**
- * Gets supported interactive app types
+ * Gets supported interactive app types.
+ *
+ * <p>The supported interactive app types is in a bit map format. For example:
+ * <pre><code>
+ * int types = tvInteractiveAppInfo.getSupportedTypes();
+ * if (types & TvInteractiveAppInfo.INTERACTIVE_APP_TYPE_HBBTV != 0) {
+ * // HbbTV type is supported. Do something...
+ * }
+ * if (types & TvInteractiveAppInfo.INTERACTIVE_APP_TYPE_ATSC == 0) {
+ * // ATSC type is not supported. Do something...
+ * }
+ * </code></pre>
+ *
+ * @return An int bit map representing supported types.
*/
@InteractiveAppType
@NonNull
@@ -189,13 +196,12 @@ public final class TvInteractiveAppServiceInfo implements Parcelable {
}
/**
- * Gets extra supported interactive app types which are not listed.
+ * Gets custom supported interactive app types which are not listed.
*
* @see #getSupportedTypes()
- * @hide
*/
@NonNull
- public List<String> getExtraSupportedTypes() {
+ public List<String> getCustomSupportedTypes() {
return mExtraTypes;
}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
index 2c40f395a621..0a8de127b6c9 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java
@@ -598,13 +598,12 @@ public class TvInteractiveAppView extends ViewGroup {
}
/**
- * Sends current time shift mode to related TV interactive app.
+ * Sends the current time shift mode to the TV interactive app bound to this view
*
* @param mode The current time shift mode. The value is one of the following:
* {@link TvInputManager#TIME_SHIFT_MODE_OFF}, {@link TvInputManager#TIME_SHIFT_MODE_LOCAL},
* {@link TvInputManager#TIME_SHIFT_MODE_NETWORK},
* {@link TvInputManager#TIME_SHIFT_MODE_AUTO}.
- * @hide
*/
public void sendTimeShiftMode(@android.media.tv.TvInputManager.TimeShiftMode int mode) {
if (DEBUG) {
@@ -616,12 +615,15 @@ public class TvInteractiveAppView extends ViewGroup {
}
/**
- * Sends available supported speeds to related TV interactive app.
+ * Sends the available supported playback speeds to the TV interactive app bound to this view.
*
- * @param speeds An ordered array of playback speeds, expressed as values relative to the normal
- * playback speed 1.0.
+ * @param speeds An ordered array of playback speeds, expressed as values relative to the
+ * normal playback speed (1.0), at which the current content can be played as
+ * a time-shifted broadcast. This is an empty array if the supported playback
+ * speeds are unknown or the video/broadcast is not in time shift mode. If
+ * currently in time shift mode, this array will normally include at least
+ * the values 1.0 (normal speed) and 0.0 (paused).
* @see PlaybackParams#getSpeed()
- * @hide
*/
public void sendAvailableSpeeds(@NonNull float[] speeds) {
if (DEBUG) {
@@ -665,19 +667,22 @@ public class TvInteractiveAppView extends ViewGroup {
}
/**
- * Alerts the TV interactive app that a recording has been started.
+ * Alerts the related TV interactive app service that a recording has been started.
*
* @param recordingId The ID of the recording started. This ID is created and maintained by the
* TV app and is used to identify the recording in the future.
+ *
+ * @param requestId The ID of the request when
+ * {@link TvInteractiveAppService.Session#requestStartRecording(String, Uri)}
+ * is called. {@code null} if the recording is not triggered by a request.
* @see TvInteractiveAppView#notifyRecordingStopped(String)
*/
- public void notifyRecordingStarted(@NonNull String recordingId) {
- // TODO: add request ID to identify and map the corresponding request.
+ public void notifyRecordingStarted(@NonNull String recordingId, @Nullable String requestId) {
if (DEBUG) {
Log.d(TAG, "notifyRecordingStarted");
}
if (mSession != null) {
- mSession.notifyRecordingStarted(recordingId);
+ mSession.notifyRecordingStarted(recordingId, recordingId);
}
}
@@ -686,7 +691,7 @@ public class TvInteractiveAppView extends ViewGroup {
*
* @param recordingId The ID of the recording stopped. This ID is created and maintained
* by the TV app when a recording is started.
- * @see TvInteractiveAppView#notifyRecordingStarted(String)
+ * @see TvInteractiveAppView#notifyRecordingStarted(String, String)
*/
public void notifyRecordingStopped(@NonNull String recordingId) {
if (DEBUG) {
@@ -743,7 +748,7 @@ public class TvInteractiveAppView extends ViewGroup {
* {@link android.media.PlaybackParams} is set or changed.
*
* @see TvView#timeShiftSetPlaybackParams(PlaybackParams)
- * @hide
+ * @param params The new {@link PlaybackParams} that was set or changed.
*/
public void notifyTimeShiftPlaybackParams(@NonNull PlaybackParams params) {
if (DEBUG) {
@@ -760,7 +765,15 @@ public class TvInteractiveAppView extends ViewGroup {
*
* @see TvView.TvInputCallback#onTimeShiftStatusChanged(String, int)
* @see android.media.tv.TvInputService.Session#notifyTimeShiftStatusChanged(int)
- * @hide
+ * @param inputId The ID of the input for which the time shift status has changed.
+ * @param status The status of which the input has changed to. Should be one of the
+ * following.
+ * <ul>
+ * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNKNOWN}
+ * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED}
+ * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNAVAILABLE}
+ * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE}
+ * </ul>
*/
public void notifyTimeShiftStatusChanged(
@NonNull String inputId, @TvInputManager.TimeShiftStatus int status) {
@@ -778,7 +791,8 @@ public class TvInteractiveAppView extends ViewGroup {
* start position is changed.
*
* @see TvView.TimeShiftPositionCallback#onTimeShiftStartPositionChanged(String, long)
- * @hide
+ * @param inputId The ID of the input for which the time shift start position has changed.
+ * @param timeMs The start position for time shifting, in milliseconds since the epoch.
*/
public void notifyTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) {
if (DEBUG) {
@@ -795,7 +809,8 @@ public class TvInteractiveAppView extends ViewGroup {
* current position is changed.
*
* @see TvView.TimeShiftPositionCallback#onTimeShiftCurrentPositionChanged(String, long)
- * @hide
+ * @param inputId The ID of the input for which the time shift current position has changed.
+ * @param timeMs The current position for time shifting, in milliseconds since the epoch.
*/
public void notifyTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) {
if (DEBUG) {
@@ -812,7 +827,7 @@ public class TvInteractiveAppView extends ViewGroup {
* while establishing a connection to the recording session for the corresponding TV input.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link #notifyRecordingStarted(String, String)}
* @param inputId The ID of the TV input bound to the current TvRecordingClient.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onConnectionFailed(String)
* @hide
@@ -833,7 +848,7 @@ public class TvInteractiveAppView extends ViewGroup {
* the current recording session is lost.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link #notifyRecordingStarted(String, String)}
* @param inputId The ID of the TV input bound to the current TvRecordingClient.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onDisconnected(String)
* @hide
@@ -854,7 +869,7 @@ public class TvInteractiveAppView extends ViewGroup {
* has been tuned to the given channel and is ready to start recording.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link #notifyRecordingStarted(String, String)}
* @param channelUri The URI of the tuned channel.
* @see android.media.tv.TvRecordingClient.RecordingCallback#onTuned(Uri)
* @hide
@@ -876,7 +891,7 @@ public class TvInteractiveAppView extends ViewGroup {
* it is released.
*
* @param recordingId The ID of the related recording which is sent via
- * {@link #notifyRecordingStarted(String)}
+ * {@link #notifyRecordingStarted(String, String)}
* @param err The error code. Should be one of the following.
* <ul>
* <li>{@link TvInputManager#RECORDING_ERROR_UNKNOWN}
@@ -904,9 +919,9 @@ public class TvInteractiveAppView extends ViewGroup {
* @param recordingId The ID assigned to this recording by the app. It can be used to send
* recording related requests such as
* {@link TvInteractiveAppService.Session#requestStopRecording(String)}.
- * @param requestId The ID of the request when requestScheduleRecording is called.
+ * @param requestId The ID of the request when
+ * {@link TvInteractiveAppService.Session#requestScheduleRecording} is called.
* {@code null} if the recording is not triggered by a request.
- * @hide
*/
public void notifyRecordingScheduled(
@NonNull String recordingId, @Nullable String requestId) {
@@ -1068,7 +1083,6 @@ public class TvInteractiveAppView extends ViewGroup {
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param cmdType type of the command
* @param parameters parameters of the command
- * @hide
*/
public void onTimeShiftCommandRequest(
@NonNull String iAppServiceId,
@@ -1186,7 +1200,6 @@ public class TvInteractiveAppView extends ViewGroup {
* called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
- * @hide
*/
public void onRequestTimeShiftMode(@NonNull String iAppServiceId) {
}
@@ -1196,7 +1209,6 @@ public class TvInteractiveAppView extends ViewGroup {
* called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
- * @hide
*/
public void onRequestAvailableSpeeds(@NonNull String iAppServiceId) {
}
@@ -1206,12 +1218,15 @@ public class TvInteractiveAppView extends ViewGroup {
* is called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #notifyRecordingStarted(String, String)}
+ * for this request should be the same as the ID received here.
* @param programUri The URI of the program to record
*
*/
- public void onRequestStartRecording(
- @NonNull String iAppServiceId,
- @Nullable Uri programUri) {
+ public void onRequestStartRecording(@NonNull String iAppServiceId,
+ @NonNull String requestId, @Nullable Uri programUri) {
}
/**
@@ -1220,8 +1235,8 @@ public class TvInteractiveAppView extends ViewGroup {
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param recordingId The ID of the recording to stop. This is provided by the TV app in
- * {@link #notifyRecordingStarted(String)}
- * @see #notifyRecordingStarted(String)
+ * {@link #notifyRecordingStarted(String, String)}
+ * @see #notifyRecordingStarted(String, String)
* @see #notifyRecordingStopped(String)
*/
public void onRequestStopRecording(
@@ -1231,10 +1246,14 @@ public class TvInteractiveAppView extends ViewGroup {
/**
* This is called when
- * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, Uri, Bundle)}
+ * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, Uri, Bundle)}
* is called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #notifyRecordingScheduled(String, String)} for this request
+ * should be the same as the ID received here.
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel to be recorded.
* @param programUri The URI of the TV program to be recorded.
@@ -1243,19 +1262,22 @@ public class TvInteractiveAppView extends ViewGroup {
* will not create conflicting keys.
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
- * @hide
*/
public void onRequestScheduleRecording(@NonNull String iAppServiceId,
- @NonNull String inputId, @NonNull Uri channelUri, @NonNull Uri programUri,
- @NonNull Bundle params) {
+ @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri,
+ @NonNull Uri programUri, @NonNull Bundle params) {
}
/**
* This is called when
- * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, Uri, long, long, int, Bundle)}
+ * {@link TvInteractiveAppService.Session#requestScheduleRecording(String, String, Uri, long, long, int, Bundle)}
* is called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
+ * @param requestId The ID of this request which is used to match the corresponding
+ * response. The request ID in
+ * {@link #notifyRecordingScheduled(String, String)} for this request
+ * should be the same as the ID received here.
* @param inputId The ID of the TV input for the given channel.
* @param channelUri The URI of a channel to be recorded.
* @param startTime The start time of the recording in milliseconds since epoch.
@@ -1266,11 +1288,10 @@ public class TvInteractiveAppView extends ViewGroup {
* will not create conflicting keys.
* @see android.media.tv.TvRecordingClient#tune(String, Uri, Bundle)
* @see android.media.tv.TvRecordingClient#startRecording(Uri)
- * @hide
*/
public void onRequestScheduleRecording(@NonNull String iAppServiceId,
- @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration,
- int repeatDays, @NonNull Bundle params) {
+ @NonNull String requestId, @NonNull String inputId, @NonNull Uri channelUri,
+ long startTime, long duration, int repeatDays, @NonNull Bundle params) {
}
/**
@@ -1295,7 +1316,7 @@ public class TvInteractiveAppView extends ViewGroup {
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param recordingId The ID of the recording to set the info for. This is provided by the
- * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+ * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
* @param recordingInfo The {@link TvRecordingInfo} to set to the recording.
*/
public void onSetTvRecordingInfo(
@@ -1311,7 +1332,8 @@ public class TvInteractiveAppView extends ViewGroup {
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param recordingId The ID of the recording to get the info for. This is provided by the
- * TV app in {@link TvInteractiveAppView#notifyRecordingStarted(String)}
+ * TV app in
+ * {@link TvInteractiveAppView#notifyRecordingStarted(String, String)}
*/
public void onRequestTvRecordingInfo(
@NonNull String iAppServiceId,
@@ -1715,7 +1737,7 @@ public class TvInteractiveAppView extends ViewGroup {
}
@Override
- public void onRequestStartRecording(Session session, Uri programUri) {
+ public void onRequestStartRecording(Session session, String requestId, Uri programUri) {
if (DEBUG) {
Log.d(TAG, "onRequestStartRecording");
}
@@ -1724,7 +1746,7 @@ public class TvInteractiveAppView extends ViewGroup {
return;
}
if (mCallback != null) {
- mCallback.onRequestStartRecording(mIAppServiceId, programUri);
+ mCallback.onRequestStartRecording(mIAppServiceId, requestId, programUri);
}
}
@@ -1758,8 +1780,25 @@ public class TvInteractiveAppView extends ViewGroup {
}
@Override
- public void onRequestScheduleRecording(Session session, @NonNull String inputId,
- @NonNull Uri channelUri, Uri progarmUri, @NonNull Bundle params) {
+ public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+ @NonNull String inputId, @NonNull Uri channelUri, Uri programUri,
+ @NonNull Bundle params) {
+ if (DEBUG) {
+ Log.d(TAG, "onRequestScheduleRecording");
+ }
+ if (this != mSessionCallback) {
+ Log.w(TAG, "onRequestScheduleRecording - session not created");
+ return;
+ }
+ if (mCallback != null) {
+ mCallback.onRequestScheduleRecording(mIAppServiceId, requestId, inputId, channelUri,
+ programUri, params);
+ }
+ }
+
+ public void onRequestScheduleRecording(Session session, @NonNull String requestId,
+ @NonNull String inputId, @NonNull Uri channelUri, long startTime, long duration,
+ int repeatDays, @NonNull Bundle params) {
if (DEBUG) {
Log.d(TAG, "onRequestScheduleRecording");
}
@@ -1768,8 +1807,8 @@ public class TvInteractiveAppView extends ViewGroup {
return;
}
if (mCallback != null) {
- mCallback.onRequestScheduleRecording(mIAppServiceId, inputId, channelUri,
- progarmUri, params);
+ mCallback.onRequestScheduleRecording(mIAppServiceId, requestId, inputId, channelUri,
+ startTime, duration, repeatDays, params);
}
}
@@ -1803,22 +1842,6 @@ public class TvInteractiveAppView extends ViewGroup {
}
}
- public void onRequestScheduleRecording(Session session, @NonNull String inputId,
- @NonNull Uri channelUri, long startTime, long duration, int repeatDays,
- @NonNull Bundle params) {
- if (DEBUG) {
- Log.d(TAG, "onRequestScheduleRecording");
- }
- if (this != mSessionCallback) {
- Log.w(TAG, "onRequestScheduleRecording - session not created");
- return;
- }
- if (mCallback != null) {
- mCallback.onRequestScheduleRecording(mIAppServiceId, inputId, channelUri, startTime,
- duration, repeatDays, params);
- }
- }
-
@Override
public void onRequestSigning(
Session session, String id, String algorithm, String alias, byte[] data) {
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 7d08b81fd156..5a569456b4a7 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -805,6 +805,7 @@ public class Tuner implements AutoCloseable {
acquireTRMSLock("close()");
try {
releaseAll();
+ mTunerResourceManager.unregisterClientProfile(mClientId);
TunerUtils.throwExceptionForResult(nativeClose(), "failed to close tuner");
} finally {
releaseTRMSLock();
@@ -968,7 +969,6 @@ public class Tuner implements AutoCloseable {
releaseDescramblers();
releaseFilters();
releaseDemux();
- mTunerResourceManager.unregisterClientProfile(mClientId);
}
/**
diff --git a/packages/CompanionDeviceManager/res/drawable-night/ic_glasses.xml b/packages/CompanionDeviceManager/res/drawable-night/ic_glasses.xml
new file mode 100644
index 000000000000..97d201d625c8
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable-night/ic_glasses.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="@android:color/system_neutral1_200">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.85,15Q7.625,15 8.238,14.55Q8.85,14.1 9.1,13.375L9.475,12.225Q9.875,11.025 9.275,10.012Q8.675,9 7.55,9H4.025L4.5,12.925Q4.625,13.8 5.287,14.4Q5.95,15 6.85,15ZM17.15,15Q18.05,15 18.712,14.4Q19.375,13.8 19.5,12.925L19.975,9H16.475Q15.35,9 14.75,10.025Q14.15,11.05 14.55,12.25L14.9,13.375Q15.15,14.1 15.762,14.55Q16.375,15 17.15,15ZM6.85,17Q5.2,17 3.963,15.912Q2.725,14.825 2.525,13.175L2,9H1V7H7.55Q8.65,7 9.562,7.537Q10.475,8.075 11,9H13.025Q13.55,8.075 14.463,7.537Q15.375,7 16.475,7H23V9H22L21.475,13.175Q21.275,14.825 20.038,15.912Q18.8,17 17.15,17Q15.725,17 14.588,16.188Q13.45,15.375 13,14.025L12.625,12.9Q12.575,12.725 12.525,12.537Q12.475,12.35 12.425,12H11.575Q11.525,12.3 11.475,12.487Q11.425,12.675 11.375,12.85L11,14Q10.55,15.35 9.413,16.175Q8.275,17 6.85,17Z"/>
+</vector>
diff --git a/packages/CompanionDeviceManager/res/drawable-night/ic_permission_nearby_device_streaming.xml b/packages/CompanionDeviceManager/res/drawable-night/ic_permission_nearby_device_streaming.xml
new file mode 100644
index 000000000000..af4fe4d48b1b
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable-night/ic_permission_nearby_device_streaming.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="@android:color/system_accent1_200">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M16,23V21H17Q17,21 17,21Q17,21 17,21V6H7V12H5V3Q5,2.175 5.588,1.587Q6.175,1 7,1H17Q17.825,1 18.413,1.587Q19,2.175 19,3V21Q19,21.825 18.413,22.413Q17.825,23 17,23ZM5,23V21Q5.825,21 6.412,21.587Q7,22.175 7,23ZM9,23Q9,21.35 7.825,20.175Q6.65,19 5,19V17Q7.5,17 9.25,18.75Q11,20.5 11,23ZM13,23Q13,19.65 10.675,17.325Q8.35,15 5,15V13Q7.075,13 8.9,13.787Q10.725,14.575 12.075,15.925Q13.425,17.275 14.213,19.1Q15,20.925 15,23ZM7,4H17V3Q17,3 17,3Q17,3 17,3H7Q7,3 7,3Q7,3 7,3ZM7,4V3Q7,3 7,3Q7,3 7,3Q7,3 7,3Q7,3 7,3V4Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml b/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
index 5f8d566f986c..90655203fe93 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_glasses.xml
@@ -16,23 +16,12 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="24dp"
- android:width="24dp"
- android:viewportHeight="160"
- android:viewportWidth="160" >
- <path android:fillAlpha="0" android:fillColor="#000000"
- android:pathData="M69.48,83.33A26.97,24.46 0,0 1,42.92 107.8,26.97 24.46,0 0,1 15.56,84.07 26.97,24.46 0,0 1,41.29 58.9,26.97 24.46,0 0,1 69.43,81.86"
- android:strokeColor="#000000" android:strokeWidth="2.265"/>
- <path android:fillAlpha="0" android:fillColor="#000000"
- android:pathData="m143.73,83.58a26.97,24.46 0,0 1,-26.56 24.46,26.97 24.46,0 0,1 -27.36,-23.72 26.97,24.46 0,0 1,25.73 -25.18,26.97 24.46,0 0,1 28.14,22.96"
- android:strokeColor="#000000" android:strokeWidth="2.265"/>
- <path android:fillAlpha="0" android:fillColor="#000000"
- android:pathData="m69.42,82.98c20.37,-0.25 20.37,-0.25 20.37,-0.25"
- android:strokeColor="#000000" android:strokeWidth="2.265"/>
- <path android:fillAlpha="0" android:fillColor="#000000"
- android:pathData="M15.37,83.78 L1.9,56.83"
- android:strokeColor="#000000" android:strokeWidth="2.265"/>
- <path android:fillAlpha="0" android:fillColor="#000000"
- android:pathData="M143.67,82.75C154.48,57.9 154.48,58.04 154.48,58.04"
- android:strokeColor="#000000" android:strokeWidth="2.265"/>
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M6.85,15Q7.625,15 8.238,14.55Q8.85,14.1 9.1,13.375L9.475,12.225Q9.875,11.025 9.275,10.012Q8.675,9 7.55,9H4.025L4.5,12.925Q4.625,13.8 5.287,14.4Q5.95,15 6.85,15ZM17.15,15Q18.05,15 18.712,14.4Q19.375,13.8 19.5,12.925L19.975,9H16.475Q15.35,9 14.75,10.025Q14.15,11.05 14.55,12.25L14.9,13.375Q15.15,14.1 15.762,14.55Q16.375,15 17.15,15ZM6.85,17Q5.2,17 3.963,15.912Q2.725,14.825 2.525,13.175L2,9H1V7H7.55Q8.65,7 9.562,7.537Q10.475,8.075 11,9H13.025Q13.55,8.075 14.463,7.537Q15.375,7 16.475,7H23V9H22L21.475,13.175Q21.275,14.825 20.038,15.912Q18.8,17 17.15,17Q15.725,17 14.588,16.188Q13.45,15.375 13,14.025L12.625,12.9Q12.575,12.725 12.525,12.537Q12.475,12.35 12.425,12H11.575Q11.525,12.3 11.475,12.487Q11.425,12.675 11.375,12.85L11,14Q10.55,15.35 9.413,16.175Q8.275,17 6.85,17Z"/>
</vector>
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml b/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
index 7295e78b16cb..d890afd6535f 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_permission_nearby_device_streaming.xml
@@ -22,7 +22,6 @@
android:viewportHeight="24"
android:tint="@android:color/system_accent1_600">
<path
- android:pathData="M6.2529,18.5H16.2529V17.5H18.2529V21.5C18.2529,22.6 17.3529,23.5 16.2529,23.5H6.2529C5.1529,23.5 4.2529,22.6 4.2529,21.5V3.5C4.2529,2.4 5.1529,1.51 6.2529,1.51L16.2529,1.5C17.3529,1.5 18.2529,2.4 18.2529,3.5V7.5H16.2529V6.5H6.2529V18.5ZM16.2529,3.5H6.2529V4.5H16.2529V3.5ZM6.2529,21.5V20.5H16.2529V21.5H6.2529ZM12.6553,9.4049C12.6553,8.8526 13.103,8.4049 13.6553,8.4049H20.5254C21.0776,8.4049 21.5254,8.8526 21.5254,9.4049V14.6055C21.5254,15.1578 21.0776,15.6055 20.5254,15.6055H14.355L12.6553,17.0871V9.4049Z"
- android:fillColor="#3C4043"
- android:fillType="evenOdd"/>
+ android:fillColor="@android:color/white"
+ android:pathData="M16,23V21H17Q17,21 17,21Q17,21 17,21V6H7V12H5V3Q5,2.175 5.588,1.587Q6.175,1 7,1H17Q17.825,1 18.413,1.587Q19,2.175 19,3V21Q19,21.825 18.413,22.413Q17.825,23 17,23ZM5,23V21Q5.825,21 6.412,21.587Q7,22.175 7,23ZM9,23Q9,21.35 7.825,20.175Q6.65,19 5,19V17Q7.5,17 9.25,18.75Q11,20.5 11,23ZM13,23Q13,19.65 10.675,17.325Q8.35,15 5,15V13Q7.075,13 8.9,13.787Q10.725,14.575 12.075,15.925Q13.425,17.275 14.213,19.1Q15,20.925 15,23ZM7,4H17V3Q17,3 17,3Q17,3 17,3H7Q7,3 7,3Q7,3 7,3ZM7,4V3Q7,3 7,3Q7,3 7,3Q7,3 7,3Q7,3 7,3V4Z"/>
</vector> \ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index bf69ef4f5b7a..f64a4324a91d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -26,7 +26,6 @@ import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
-import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.runtime.Composable
@@ -35,6 +34,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.credentialmanager.common.Constants
import com.android.credentialmanager.common.DialogState
import com.android.credentialmanager.common.ProviderActivityResult
+import com.android.credentialmanager.common.StartBalIntentSenderForResultContract
import com.android.credentialmanager.createflow.CreateCredentialScreen
import com.android.credentialmanager.getflow.GetCredentialScreen
import com.android.credentialmanager.ui.theme.CredentialSelectorTheme
@@ -84,7 +84,7 @@ class CredentialSelectorActivity : ComponentActivity() {
CredentialSelectorViewModel(credManRepo, userConfigRepo)
}
val launcher = rememberLauncherForActivityResult(
- ActivityResultContracts.StartIntentSenderForResult()
+ StartBalIntentSenderForResultContract()
) {
viewModel.onProviderActivityResult(ProviderActivityResult(it.resultCode, it.data))
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/StartBalIntentSenderForResultContract.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/StartBalIntentSenderForResultContract.kt
new file mode 100644
index 000000000000..9952815ae4b2
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/StartBalIntentSenderForResultContract.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.common
+
+import android.app.ActivityOptions
+import android.content.Context
+import android.content.Intent
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.IntentSenderRequest
+import androidx.activity.result.contract.ActivityResultContract
+import androidx.activity.result.contract.ActivityResultContracts
+
+/**
+ * A custom StartIntentSenderForResult contract implementation that attaches an [ActivityOptions]
+ * that opts in for background activity launch.
+ */
+class StartBalIntentSenderForResultContract :
+ ActivityResultContract<IntentSenderRequest, ActivityResult>() {
+ override fun createIntent(context: Context, input: IntentSenderRequest): Intent {
+ val activityOptionBundle =
+ ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ ).toBundle()
+ return Intent(
+ ActivityResultContracts.StartIntentSenderForResult.ACTION_INTENT_SENDER_REQUEST
+ ).putExtra(
+ ActivityResultContracts.StartActivityForResult.EXTRA_ACTIVITY_OPTIONS_BUNDLE,
+ activityOptionBundle
+ ).putExtra(
+ ActivityResultContracts.StartIntentSenderForResult.EXTRA_INTENT_SENDER_REQUEST,
+ input
+ )
+ }
+
+ override fun parseResult(
+ resultCode: Int,
+ intent: Intent?
+ ): ActivityResult = ActivityResult(resultCode, intent)
+} \ No newline at end of file
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index 4344e9401fc9..95b49a8ef335 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -20,6 +20,9 @@ import android.annotation.Nullable;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupManagerMonitor;
+import android.app.backup.BackupRestoreEventLogger;
+import android.app.backup.BackupRestoreEventLogger.DataTypeResult;
import android.app.backup.BackupTransport;
import android.app.backup.RestoreDescription;
import android.app.backup.RestoreSet;
@@ -27,6 +30,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
+import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
@@ -100,6 +104,7 @@ public class LocalTransport extends BackupTransport {
private FileInputStream mCurFullRestoreStream;
private byte[] mFullRestoreBuffer;
private final LocalTransportParameters mParameters;
+ private final BackupManagerMonitor mMonitor = new TestBackupManagerMonitor();
private void makeDataDirs() {
mDataDir = mContext.getFilesDir();
@@ -887,4 +892,41 @@ public class LocalTransport extends BackupTransport {
public long getBackupQuota(String packageName, boolean isFullBackup) {
return isFullBackup ? FULL_BACKUP_SIZE_QUOTA : KEY_VALUE_BACKUP_SIZE_QUOTA;
}
+
+ @Override
+ public BackupManagerMonitor getBackupManagerMonitor() {
+ return mMonitor;
+ }
+
+ private class TestBackupManagerMonitor extends BackupManagerMonitor {
+ @Override
+ public void onEvent(Bundle event) {
+ if (event == null || !mParameters.logAgentResults()) {
+ return;
+ }
+
+ if (event.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID)
+ == BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS) {
+ Log.i(TAG, "agent_logging_results {");
+ ArrayList<DataTypeResult> results = event.getParcelableArrayList(
+ BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS,
+ DataTypeResult.class);
+ for (DataTypeResult result : results) {
+ Log.i(TAG, "\tdataType: " + result.getDataType());
+ Log.i(TAG, "\tsuccessCount: " + result.getSuccessCount());
+ Log.i(TAG, "\tfailCount: " + result.getFailCount());
+
+ if (!result.getErrors().isEmpty()) {
+ Log.i(TAG, "\terrors {");
+ for (String error : result.getErrors().keySet()) {
+ Log.i(TAG, "\t\t" + error + ": " + result.getErrors().get(error));
+ }
+ Log.i(TAG, "\t}");
+ }
+
+ Log.i(TAG, "}");
+ }
+ }
+ }
+ }
}
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index 1ba1bc6bfec7..aaa18bf755bc 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -29,11 +29,13 @@ public class LocalTransportParameters extends KeyValueSettingObserver {
private static final String KEY_NON_INCREMENTAL_ONLY = "non_incremental_only";
private static final String KEY_IS_DEVICE_TRANSFER = "is_device_transfer";
private static final String KEY_IS_ENCRYPTED = "is_encrypted";
+ private static final String KEY_LOG_AGENT_RESULTS = "log_agent_results";
private boolean mFakeEncryptionFlag;
private boolean mIsNonIncrementalOnly;
private boolean mIsDeviceTransfer;
private boolean mIsEncrypted;
+ private boolean mLogAgentResults;
public LocalTransportParameters(Handler handler, ContentResolver resolver) {
super(handler, resolver, Settings.Secure.getUriFor(SETTING));
@@ -55,6 +57,10 @@ public class LocalTransportParameters extends KeyValueSettingObserver {
return mIsEncrypted;
}
+ boolean logAgentResults() {
+ return mLogAgentResults;
+ }
+
public String getSettingValue(ContentResolver resolver) {
return Settings.Secure.getString(resolver, SETTING);
}
@@ -64,5 +70,6 @@ public class LocalTransportParameters extends KeyValueSettingObserver {
mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false);
mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false);
mIsEncrypted = parser.getBoolean(KEY_IS_ENCRYPTED, false);
+ mLogAgentResults = parser.getBoolean(KEY_LOG_AGENT_RESULTS, /* def */ false);
}
}
diff --git a/packages/SettingsLib/Spa/build.gradle b/packages/SettingsLib/Spa/build.gradle
index 9117524a3e88..42af9992f774 100644
--- a/packages/SettingsLib/Spa/build.gradle
+++ b/packages/SettingsLib/Spa/build.gradle
@@ -19,7 +19,7 @@ buildscript {
BUILD_TOOLS_VERSION = "30.0.3"
MIN_SDK = 21
TARGET_SDK = 33
- jetpack_compose_version = '1.4.0-alpha05'
+ jetpack_compose_version = '1.4.0-beta01'
jetpack_compose_compiler_version = '1.4.0'
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt
index 08e645230774..5f251b1b14dd 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemListPage.kt
@@ -64,7 +64,7 @@ object ItemListPageProvider : SettingsPageProvider {
return SettingsEntryBuilder.createInject(
owner = createSettingsPage(arguments),
- displayName = "ItemList_$opParam",
+ label = "ItemList_$opParam",
).setUiLayoutFn {
Preference(
object : PreferenceModel {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt
index 8179356e33ef..98b27b7b2dc3 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/itemList/ItemOperatePage.kt
@@ -99,7 +99,7 @@ object ItemOperatePageProvider : SettingsPageProvider {
return SettingsEntryBuilder.createInject(
owner = createSettingsPage(arguments),
- displayName = "ItemOp_$opParam",
+ label = "ItemOp_$opParam",
).setUiLayoutFn {
// Item name is a runtime parameter, which needs to be read inside UiLayoutFn
val itemName = parameter.getStringArg(ITEM_NAME_PARAM_NAME, it) ?: "NULL"
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
index eca47b6f67eb..f01ff3849701 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
@@ -87,7 +87,7 @@ object ArgumentPageProvider : SettingsPageProvider {
return SettingsEntryBuilder.createInject(
owner = createSettingsPage(arguments),
- displayName = "${name}_$stringParam",
+ label = "${name}_$stringParam",
)
.setSearchDataFn { ArgumentPageModel.genInjectSearchData() }
.setUiLayoutFn {
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
index 6bf20bedecba..f513830f26a8 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_landscape_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
index fa01348108a5..73f2407be5ad 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/phone/light_portrait_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
index 7e579583051a..6e860d319108 100644
--- a/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
+++ b/packages/SettingsLib/Spa/screenshot/assets/tablet/dark_portrait_progressBar.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index 6f1b41c69ff0..640aa01f307f 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -69,18 +69,16 @@ android {
}
dependencies {
- String jetpack_lifecycle_version = "2.6.0-alpha03"
-
- api "androidx.appcompat:appcompat:1.7.0-alpha01"
+ api "androidx.appcompat:appcompat:1.7.0-alpha02"
api "androidx.slice:slice-builders:1.1.0-alpha02"
api "androidx.slice:slice-core:1.1.0-alpha02"
api "androidx.slice:slice-view:1.1.0-alpha02"
- api "androidx.compose.material3:material3:1.1.0-alpha05"
+ api "androidx.compose.material3:material3:1.1.0-alpha06"
api "androidx.compose.material:material-icons-extended:$jetpack_compose_version"
- api "androidx.compose.runtime:runtime-livedata:1.4.0-alpha04"
+ api "androidx.compose.runtime:runtime-livedata:$jetpack_compose_version"
api "androidx.compose.ui:ui-tooling-preview:$jetpack_compose_version"
- api "androidx.lifecycle:lifecycle-livedata-ktx:$jetpack_lifecycle_version"
- api "androidx.lifecycle:lifecycle-runtime-compose:$jetpack_lifecycle_version"
+ api "androidx.lifecycle:lifecycle-livedata-ktx"
+ api "androidx.lifecycle:lifecycle-runtime-compose"
api "androidx.navigation:navigation-compose:2.6.0-alpha04"
api "com.github.PhilJay:MPAndroidChart:v3.1.0-alpha"
api "com.google.android.material:material:1.7.0-alpha03"
@@ -108,7 +106,6 @@ task coverageReport(type: JacocoReport, dependsOn: "connectedDebugAndroidTest")
// Excludes files forked from Accompanist.
"com/android/settingslib/spa/framework/compose/DrawablePainter*",
- "com/android/settingslib/spa/framework/compose/Pager*",
// Excludes inline functions, which is not covered in Jacoco reports.
"com/android/settingslib/spa/framework/util/Collections*",
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
index d95ed05e560d..444a3f0fd634 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugFormat.kt
@@ -50,22 +50,22 @@ fun SettingsPage.debugBrief(): String {
}
fun SettingsEntry.debugBrief(): String {
- return "${owner.displayName}:$displayName"
+ return "${owner.displayName}:$label"
}
fun SettingsEntry.debugContent(entryRepository: SettingsEntryRepository): String {
val searchData = getSearchData()
val statusData = getStatusData()
- val entryPathWithName = entryRepository.getEntryPathWithDisplayName(id)
+ val entryPathWithLabel = entryRepository.getEntryPathWithLabel(id)
val entryPathWithTitle = entryRepository.getEntryPathWithTitle(id,
- searchData?.title ?: displayName)
+ searchData?.title ?: label)
val content = listOf(
"------ STATIC ------",
"id = $id",
"owner = ${owner.debugBrief()} ${owner.debugArguments()}",
"linkFrom = ${fromPage?.debugBrief()} ${fromPage?.debugArguments()}",
"linkTo = ${toPage?.debugBrief()} ${toPage?.debugArguments()}",
- "hierarchy_path = $entryPathWithName",
+ "hierarchy_path = $entryPathWithLabel",
"------ ATTRIBUTION ------",
"allowSearch = $isAllowSearch",
"isSearchDynamic = $isSearchDataDynamic",
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
index 494e3cc81df6..1fcc8885aaf3 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
@@ -173,12 +173,12 @@ class DebugProvider : ContentProvider() {
val intent = entry.createIntent(SESSION_SEARCH) ?: Intent()
cursor.newRow()
.add(ColumnEnum.ENTRY_ID.id, entry.id)
- .add(ColumnEnum.ENTRY_NAME.id, entry.displayName)
+ .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
.add(ColumnEnum.ENTRY_ROUTE.id, entry.containerPage().buildRoute())
.add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(URI_INTENT_SCHEME))
.add(
ColumnEnum.ENTRY_HIERARCHY_PATH.id,
- entryRepository.getEntryPathWithDisplayName(entry.id)
+ entryRepository.getEntryPathWithLabel(entry.id)
)
}
return cursor
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt
index fc6160e96070..9b46ec298650 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/ProviderColumn.kt
@@ -33,7 +33,7 @@ enum class ColumnEnum(val id: String) {
// Columns related to entry
ENTRY_ID("entryId"),
- ENTRY_NAME("entryName"),
+ ENTRY_LABEL("entryLabel"),
ENTRY_ROUTE("entryRoute"),
ENTRY_INTENT_URI("entryIntent"),
ENTRY_HIERARCHY_PATH("entryPath"),
@@ -76,7 +76,7 @@ enum class QueryEnum(
"entry_info", 200,
listOf(
ColumnEnum.ENTRY_ID,
- ColumnEnum.ENTRY_NAME,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.ENTRY_ROUTE,
ColumnEnum.ENTRY_INTENT_URI,
ColumnEnum.ENTRY_HIERARCHY_PATH,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index b92729dab7c0..90581b99160d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -51,11 +51,13 @@ data class SettingsEntry(
// The unique id of this entry, which is computed by name + owner + fromPage + toPage.
val id: String,
- // The name of the page, which is used to compute the unique id, and need to be stable.
+ // The name of the entry, which is used to compute the unique id, and need to be stable.
private val name: String,
- // The display name of the page, for better readability.
- val displayName: String,
+ // The label of the entry, for better readability.
+ // For migration mapping, this should match the android:key field in the old architecture
+ // if applicable.
+ val label: String,
// The owner page of this entry.
val owner: SettingsPage,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
index 67f9ea52a40d..97d8de3c5fcf 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
@@ -21,14 +21,14 @@ import android.os.Bundle
import androidx.compose.runtime.remember
import com.android.settingslib.spa.framework.util.genEntryId
-private const val INJECT_ENTRY_NAME = "INJECT"
-private const val ROOT_ENTRY_NAME = "ROOT"
+private const val INJECT_ENTRY_LABEL = "INJECT"
+private const val ROOT_ENTRY_LABEL = "ROOT"
/**
* The helper to build a Settings Entry instance.
*/
class SettingsEntryBuilder(private val name: String, private val owner: SettingsPage) {
- private var displayName = name
+ private var label = name
private var fromPage: SettingsPage? = null
private var toPage: SettingsPage? = null
@@ -51,7 +51,7 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
id = genEntryId(name, owner, fromPage, toPage),
name = name,
owner = owner,
- displayName = displayName,
+ label = label,
// linking data
fromPage = fromPage,
@@ -72,8 +72,8 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
)
}
- fun setDisplayName(displayName: String): SettingsEntryBuilder {
- this.displayName = displayName
+ fun setLabel(label: String): SettingsEntryBuilder {
+ this.label = label
return this
}
@@ -147,19 +147,19 @@ class SettingsEntryBuilder(private val name: String, private val owner: Settings
return create(entryName, owner).setLink(toPage = owner)
}
- fun create(owner: SettingsPage, entryName: String, displayName: String? = null):
+ fun create(owner: SettingsPage, entryName: String, label: String? = null):
SettingsEntryBuilder {
- return SettingsEntryBuilder(entryName, owner).setDisplayName(displayName ?: entryName)
+ return SettingsEntryBuilder(entryName, owner).setLabel(label ?: entryName)
}
- fun createInject(owner: SettingsPage, displayName: String? = null): SettingsEntryBuilder {
- val name = displayName ?: "${INJECT_ENTRY_NAME}_${owner.displayName}"
- return createLinkTo(INJECT_ENTRY_NAME, owner).setDisplayName(name)
+ fun createInject(owner: SettingsPage, label: String? = null): SettingsEntryBuilder {
+ val label = label ?: "${INJECT_ENTRY_LABEL}_${owner.displayName}"
+ return createLinkTo(INJECT_ENTRY_LABEL, owner).setLabel(label)
}
- fun createRoot(owner: SettingsPage, displayName: String? = null): SettingsEntryBuilder {
- val name = displayName ?: "${ROOT_ENTRY_NAME}_${owner.displayName}"
- return createLinkTo(ROOT_ENTRY_NAME, owner).setDisplayName(name)
+ fun createRoot(owner: SettingsPage, label: String? = null): SettingsEntryBuilder {
+ val label = label ?: "${ROOT_ENTRY_LABEL}_${owner.displayName}"
+ return createLinkTo(ROOT_ENTRY_LABEL, owner).setLabel(label)
}
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
index 429f97bb38d0..8811b9465321 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
@@ -111,9 +111,9 @@ class SettingsEntryRepository(sppRepository: SettingsPageProviderRepository) {
return entryPath
}
- fun getEntryPathWithDisplayName(entryId: String): List<String> {
+ fun getEntryPathWithLabel(entryId: String): List<String> {
val entryPath = getEntryPath(entryId)
- return entryPath.map { it.displayName }
+ return entryPath.map { it.label }
}
fun getEntryPathWithTitle(entryId: String, defaultTitle: String): List<String> {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
deleted file mode 100644
index 392089ae7989..000000000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework.compose
-
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.wrapContentSize
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.LazyRow
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.snapshotFlow
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.Velocity
-import androidx.compose.ui.unit.dp
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.drop
-import kotlinx.coroutines.flow.filter
-
-/**
- * *************************************************************************************************
- * This file was forked from
- * https://github.com/google/accompanist/blob/main/pager/src/main/java/com/google/accompanist/pager/Pager.kt
- * and will be removed once it lands in AndroidX.
- */
-
-/**
- * A horizontally scrolling layout that allows users to flip between items to the left and right.
- *
- * @sample com.google.accompanist.sample.pager.HorizontalPagerSample
- *
- * @param count the number of pages.
- * @param modifier the modifier to apply to this layout.
- * @param state the state object to be used to control or observe the pager's state.
- * @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be
- * composed from the end to the start and [PagerState.currentPage] == 0 will mean
- * the first item is located at the end.
- * @param itemSpacing horizontal spacing to add between items.
- * @param key the scroll position will be maintained based on the key, which means if you
- * add/remove items before the current visible item the item with the given key will be kept as the
- * first visible one.
- * @param content a block which describes the content. Inside this block you can reference
- * [PagerScope.currentPage] and other properties in [PagerScope].
- */
-@Composable
-fun HorizontalPager(
- count: Int,
- modifier: Modifier = Modifier,
- state: PagerState = rememberPagerState(),
- reverseLayout: Boolean = false,
- itemSpacing: Dp = 0.dp,
- contentPadding: PaddingValues = PaddingValues(0.dp),
- verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
- key: ((page: Int) -> Any)? = null,
- content: @Composable PagerScope.(page: Int) -> Unit,
-) {
- Pager(
- count = count,
- state = state,
- modifier = modifier,
- isVertical = false,
- reverseLayout = reverseLayout,
- itemSpacing = itemSpacing,
- verticalAlignment = verticalAlignment,
- key = key,
- contentPadding = contentPadding,
- content = content
- )
-}
-
-/**
- * A vertically scrolling layout that allows users to flip between items to the top and bottom.
- *
- * @sample com.google.accompanist.sample.pager.VerticalPagerSample
- *
- * @param count the number of pages.
- * @param modifier the modifier to apply to this layout.
- * @param state the state object to be used to control or observe the pager's state.
- * @param reverseLayout reverse the direction of scrolling and layout, when `true` items will be
- * composed from the bottom to the top and [PagerState.currentPage] == 0 will mean
- * the first item is located at the bottom.
- * @param itemSpacing vertical spacing to add between items.
- * @param key the scroll position will be maintained based on the key, which means if you
- * add/remove items before the current visible item the item with the given key will be kept as the
- * first visible one.
- * @param content a block which describes the content. Inside this block you can reference
- * [PagerScope.currentPage] and other properties in [PagerScope].
- */
-@Composable
-fun VerticalPager(
- count: Int,
- modifier: Modifier = Modifier,
- state: PagerState = rememberPagerState(),
- reverseLayout: Boolean = false,
- itemSpacing: Dp = 0.dp,
- contentPadding: PaddingValues = PaddingValues(0.dp),
- horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
- key: ((page: Int) -> Any)? = null,
- content: @Composable PagerScope.(page: Int) -> Unit,
-) {
- Pager(
- count = count,
- state = state,
- modifier = modifier,
- isVertical = true,
- reverseLayout = reverseLayout,
- itemSpacing = itemSpacing,
- horizontalAlignment = horizontalAlignment,
- key = key,
- contentPadding = contentPadding,
- content = content
- )
-}
-
-@Composable
-internal fun Pager(
- count: Int,
- modifier: Modifier,
- state: PagerState,
- reverseLayout: Boolean,
- itemSpacing: Dp,
- isVertical: Boolean,
- key: ((page: Int) -> Any)?,
- contentPadding: PaddingValues,
- verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
- horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
- content: @Composable PagerScope.(page: Int) -> Unit,
-) {
- require(count >= 0) { "pageCount must be >= 0" }
-
- LaunchedEffect(count) {
- state.currentPage = minOf(count - 1, state.currentPage).coerceAtLeast(0)
- }
-
- // Once a fling (scroll) has finished, notify the state
- LaunchedEffect(state) {
- // When a 'scroll' has finished, notify the state
- snapshotFlow { state.isScrollInProgress }
- .filter { !it }
- // initially isScrollInProgress is false as well and we want to start receiving
- // the events only after the real scroll happens.
- .drop(1)
- .collect { state.onScrollFinished() }
- }
- LaunchedEffect(state) {
- snapshotFlow { state.mostVisiblePageLayoutInfo?.index }
- .distinctUntilChanged()
- .collect { state.updateCurrentPageBasedOnLazyListState() }
- }
- val density = LocalDensity.current
- LaunchedEffect(density, state, itemSpacing) {
- with(density) { state.itemSpacing = itemSpacing.roundToPx() }
- }
-
- val pagerScope = remember(state) { PagerScopeImpl(state) }
-
- // We only consume nested flings in the main-axis, allowing cross-axis flings to propagate
- // as normal
- val consumeFlingNestedScrollConnection = remember(isVertical) {
- ConsumeFlingNestedScrollConnection(
- consumeHorizontal = !isVertical,
- consumeVertical = isVertical,
- pagerState = state,
- )
- }
-
- if (isVertical) {
- LazyColumn(
- state = state.lazyListState,
- verticalArrangement = Arrangement.spacedBy(itemSpacing, verticalAlignment),
- horizontalAlignment = horizontalAlignment,
- reverseLayout = reverseLayout,
- contentPadding = contentPadding,
- userScrollEnabled = false,
- modifier = modifier,
- ) {
- items(
- count = count,
- key = key,
- ) { page ->
- Box(
- Modifier
- // We don't any nested flings to continue in the pager, so we add a
- // connection which consumes them.
- // See: https://github.com/google/accompanist/issues/347
- .nestedScroll(connection = consumeFlingNestedScrollConnection)
- // Constraint the content height to be <= than the height of the pager.
- .fillParentMaxHeight()
- .wrapContentSize()
- ) {
- pagerScope.content(page)
- }
- }
- }
- } else {
- LazyRow(
- state = state.lazyListState,
- verticalAlignment = verticalAlignment,
- horizontalArrangement = Arrangement.spacedBy(itemSpacing, horizontalAlignment),
- reverseLayout = reverseLayout,
- contentPadding = contentPadding,
- userScrollEnabled = false,
- modifier = modifier,
- ) {
- items(
- count = count,
- key = key,
- ) { page ->
- Box(
- Modifier
- // We don't any nested flings to continue in the pager, so we add a
- // connection which consumes them.
- // See: https://github.com/google/accompanist/issues/347
- .nestedScroll(connection = consumeFlingNestedScrollConnection)
- // Constraint the content width to be <= than the width of the pager.
- .fillParentMaxWidth()
- .wrapContentSize()
- ) {
- pagerScope.content(page)
- }
- }
- }
- }
-}
-
-private class ConsumeFlingNestedScrollConnection(
- private val consumeHorizontal: Boolean,
- private val consumeVertical: Boolean,
- private val pagerState: PagerState,
-) : NestedScrollConnection {
- override fun onPostScroll(
- consumed: Offset,
- available: Offset,
- source: NestedScrollSource
- ): Offset = when (source) {
- // We can consume all resting fling scrolls so that they don't propagate up to the
- // Pager
- NestedScrollSource.Fling -> available.consume(consumeHorizontal, consumeVertical)
- else -> Offset.Zero
- }
-
- override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
- return if (pagerState.currentPageOffset != 0f) {
- // The Pager is already scrolling. This means that a nested scroll child was
- // scrolled to end, and the Pager can use this fling
- Velocity.Zero
- } else {
- // A nested scroll child is still scrolling. We can consume all post fling
- // velocity on the main-axis so that it doesn't propagate up to the Pager
- available.consume(consumeHorizontal, consumeVertical)
- }
- }
-}
-
-private fun Offset.consume(
- consumeHorizontal: Boolean,
- consumeVertical: Boolean,
-): Offset = Offset(
- x = if (consumeHorizontal) this.x else 0f,
- y = if (consumeVertical) this.y else 0f,
-)
-
-private fun Velocity.consume(
- consumeHorizontal: Boolean,
- consumeVertical: Boolean,
-): Velocity = Velocity(
- x = if (consumeHorizontal) this.x else 0f,
- y = if (consumeVertical) this.y else 0f,
-)
-
-/**
- * Scope for [HorizontalPager] content.
- */
-@Stable
-interface PagerScope {
- /**
- * Returns the current selected page
- */
- val currentPage: Int
-
- /**
- * The current offset from the start of [currentPage], as a ratio of the page width.
- */
- val currentPageOffset: Float
-}
-
-private class PagerScopeImpl(
- private val state: PagerState,
-) : PagerScope {
- override val currentPage: Int get() = state.currentPage
- override val currentPageOffset: Float get() = state.currentPageOffset
-}
-
-/**
- * Calculate the offset for the given [page] from the current scroll position. This is useful
- * when using the scroll position to apply effects or animations to items.
- *
- * The returned offset can positive or negative, depending on whether which direction the [page] is
- * compared to the current scroll position.
- *
- * @sample com.google.accompanist.sample.pager.HorizontalPagerWithOffsetTransition
- */
-fun PagerScope.calculateCurrentOffsetForPage(page: Int): Float {
- return (currentPage - page) + currentPageOffset
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt
deleted file mode 100644
index 480335dacd36..000000000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework.compose
-
-import androidx.annotation.FloatRange
-import androidx.annotation.IntRange
-import androidx.compose.foundation.MutatePriority
-import androidx.compose.foundation.gestures.ScrollScope
-import androidx.compose.foundation.gestures.ScrollableState
-import androidx.compose.foundation.interaction.InteractionSource
-import androidx.compose.foundation.lazy.LazyListItemInfo
-import androidx.compose.foundation.lazy.LazyListState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.Saver
-import androidx.compose.runtime.saveable.listSaver
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import kotlin.math.abs
-import kotlin.math.absoluteValue
-import kotlin.math.roundToInt
-
-/**
- * *************************************************************************************************
- * This file was forked from
- * https://github.com/google/accompanist/blob/main/pager/src/main/java/com/google/accompanist/pager/PagerState.kt
- * and will be removed once it lands in AndroidX.
- */
-
-/**
- * Creates a [PagerState] that is remembered across compositions.
- *
- * Changes to the provided values for [initialPage] will **not** result in the state being
- * recreated or changed in any way if it has already
- * been created.
- *
- * @param initialPage the initial value for [PagerState.currentPage]
- */
-@Composable
-fun rememberPagerState(
- @IntRange(from = 0) initialPage: Int = 0,
-): PagerState = rememberSaveable(saver = PagerState.Saver) {
- PagerState(
- currentPage = initialPage,
- )
-}
-
-/**
- * A state object that can be hoisted to control and observe scrolling for [HorizontalPager].
- *
- * In most cases, this will be created via [rememberPagerState].
- *
- * @param currentPage the initial value for [PagerState.currentPage]
- */
-@Stable
-class PagerState(
- @IntRange(from = 0) currentPage: Int = 0,
-) : ScrollableState {
- // Should this be public?
- internal val lazyListState = LazyListState(firstVisibleItemIndex = currentPage)
-
- private var _currentPage by mutableStateOf(currentPage)
-
- // finds the page which has larger visible area within the viewport not including paddings
- internal val mostVisiblePageLayoutInfo: LazyListItemInfo?
- get() {
- val layoutInfo = lazyListState.layoutInfo
- return layoutInfo.visibleItemsInfo.maxByOrNull {
- val start = maxOf(it.offset, 0)
- val end = minOf(
- it.offset + it.size,
- layoutInfo.viewportEndOffset - layoutInfo.afterContentPadding
- )
- end - start
- }
- }
-
- internal var itemSpacing by mutableStateOf(0)
-
- private val currentPageLayoutInfo: LazyListItemInfo?
- get() = lazyListState.layoutInfo.visibleItemsInfo.lastOrNull {
- it.index == currentPage
- }
-
- /**
- * [InteractionSource] that will be used to dispatch drag events when this
- * list is being dragged. If you want to know whether the fling (or animated scroll) is in
- * progress, use [isScrollInProgress].
- */
- val interactionSource: InteractionSource
- get() = lazyListState.interactionSource
-
- /**
- * The number of pages to display.
- */
- @get:IntRange(from = 0)
- val pageCount: Int by derivedStateOf {
- lazyListState.layoutInfo.totalItemsCount
- }
-
- /**
- * The index of the currently selected page. This may not be the page which is
- * currently displayed on screen.
- *
- * To update the scroll position, use [scrollToPage] or [animateScrollToPage].
- */
- @get:IntRange(from = 0)
- var currentPage: Int
- get() = _currentPage
- internal set(value) {
- if (value != _currentPage) {
- _currentPage = value
- }
- }
-
- /**
- * The current offset from the start of [currentPage], as a ratio of the page width.
- *
- * To update the scroll position, use [scrollToPage] or [animateScrollToPage].
- */
- val currentPageOffset: Float by derivedStateOf {
- currentPageLayoutInfo?.let {
- (-it.offset / (it.size + itemSpacing).toFloat()).coerceIn(-0.5f, 0.5f)
- } ?: 0f
- }
-
- /**
- * The target page for any on-going animations.
- */
- private var animationTargetPage: Int? by mutableStateOf(null)
-
- /**
- * Animate (smooth scroll) to the given page to the middle of the viewport.
- *
- * Cancels the currently running scroll, if any, and suspends until the cancellation is
- * complete.
- *
- * @param page the page to animate to. Must be >= 0.
- * @param pageOffset the percentage of the page size to offset, from the start of [page].
- * Must be in the range -1f..1f.
- */
- suspend fun animateScrollToPage(
- @IntRange(from = 0) page: Int,
- @FloatRange(from = -1.0, to = 1.0) pageOffset: Float = 0f,
- ) {
- requireCurrentPage(page, "page")
- requireCurrentPageOffset(pageOffset, "pageOffset")
- try {
- animationTargetPage = page
-
- // pre-jump to nearby item for long jumps as an optimization
- // the same trick is done in ViewPager2
- val oldPage = lazyListState.firstVisibleItemIndex
- if (abs(page - oldPage) > 3) {
- lazyListState.scrollToItem(if (page > oldPage) page - 3 else page + 3)
- }
-
- if (pageOffset.absoluteValue <= 0.005f) {
- // If the offset is (close to) zero, just call animateScrollToItem and we're done
- lazyListState.animateScrollToItem(index = page)
- } else {
- // Else we need to figure out what the offset is in pixels...
- lazyListState.scroll { } // this will await for the first layout.
- val layoutInfo = lazyListState.layoutInfo
- var target = layoutInfo.visibleItemsInfo
- .firstOrNull { it.index == page }
-
- if (target != null) {
- // If we have access to the target page layout, we can calculate the pixel
- // offset from the size
- lazyListState.animateScrollToItem(
- index = page,
- scrollOffset = ((target.size + itemSpacing) * pageOffset).roundToInt()
- )
- } else if (layoutInfo.visibleItemsInfo.isNotEmpty()) {
- // If we don't, we use the current page size as a guide
- val currentSize = layoutInfo.visibleItemsInfo.first().size + itemSpacing
- lazyListState.animateScrollToItem(
- index = page,
- scrollOffset = (currentSize * pageOffset).roundToInt()
- )
-
- // The target should be visible now
- target = layoutInfo.visibleItemsInfo.firstOrNull { it.index == page }
-
- if (target != null && target.size + itemSpacing != currentSize) {
- // If the size we used for calculating the offset differs from the actual
- // target page size, we need to scroll again. This doesn't look great,
- // but there's not much else we can do.
- lazyListState.animateScrollToItem(
- index = page,
- scrollOffset = ((target.size + itemSpacing) * pageOffset).roundToInt()
- )
- }
- }
- }
- } finally {
- // We need to manually call this, as the `animateScrollToItem` call above will happen
- // in 1 frame, which is usually too fast for the LaunchedEffect in Pager to detect
- // the change. This is especially true when running unit tests.
- onScrollFinished()
- }
- }
-
- /**
- * Instantly brings the item at [page] to the middle of the viewport.
- *
- * Cancels the currently running scroll, if any, and suspends until the cancellation is
- * complete.
- *
- * @param page the page to snap to. Must be >= 0.
- * @param pageOffset the percentage of the page size to offset, from the start of [page].
- * Must be in the range -1f..1f.
- */
- suspend fun scrollToPage(
- @IntRange(from = 0) page: Int,
- @FloatRange(from = -1.0, to = 1.0) pageOffset: Float = 0f,
- ) {
- requireCurrentPage(page, "page")
- requireCurrentPageOffset(pageOffset, "pageOffset")
- try {
- animationTargetPage = page
-
- // First scroll to the given page. It will now be laid out at offset 0
- lazyListState.scrollToItem(index = page)
- updateCurrentPageBasedOnLazyListState()
-
- // If we have a start spacing, we need to offset (scroll) by that too
- if (pageOffset.absoluteValue > 0.0001f) {
- currentPageLayoutInfo?.let {
- scroll {
- scrollBy((it.size + itemSpacing) * pageOffset)
- }
- }
- }
- } finally {
- // We need to manually call this, as the `scroll` call above will happen in 1 frame,
- // which is usually too fast for the LaunchedEffect in Pager to detect the change.
- // This is especially true when running unit tests.
- onScrollFinished()
- }
- }
-
- internal fun updateCurrentPageBasedOnLazyListState() {
- // Then update the current page to our layout page
- mostVisiblePageLayoutInfo?.let {
- currentPage = it.index
- }
- }
-
- internal fun onScrollFinished() {
- // Clear the animation target page
- animationTargetPage = null
- }
-
- override suspend fun scroll(
- scrollPriority: MutatePriority,
- block: suspend ScrollScope.() -> Unit
- ) = lazyListState.scroll(scrollPriority, block)
-
- override fun dispatchRawDelta(delta: Float): Float {
- return lazyListState.dispatchRawDelta(delta)
- }
-
- override val isScrollInProgress: Boolean
- get() = lazyListState.isScrollInProgress
-
- override fun toString(): String = "PagerState(" +
- "pageCount=$pageCount, " +
- "currentPage=$currentPage, " +
- "currentPageOffset=$currentPageOffset" +
- ")"
-
- private fun requireCurrentPage(value: Int, name: String) {
- require(value >= 0) { "$name[$value] must be >= 0" }
- }
-
- private fun requireCurrentPageOffset(value: Float, name: String) {
- require(value in -1f..1f) { "$name must be >= -1 and <= 1" }
- }
-
- companion object {
- /**
- * The default [Saver] implementation for [PagerState].
- */
- val Saver: Saver<PagerState, *> = listSaver(
- save = {
- listOf<Any>(
- it.currentPage,
- )
- },
- restore = {
- PagerState(
- currentPage = it[0] as Int,
- )
- }
- )
- }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
index e6fa74e34cc8..26372b6bfd32 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
@@ -17,6 +17,9 @@
package com.android.settingslib.spa.framework.theme
import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material.ripple.LocalRippleTheme
+import androidx.compose.material.ripple.RippleAlpha
+import androidx.compose.material.ripple.RippleTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@@ -33,8 +36,11 @@ fun SettingsTheme(content: @Composable () -> Unit) {
background = settingsColorScheme.background,
)
- CompositionLocalProvider(LocalColorScheme provides settingsColorScheme(isDarkTheme)) {
- MaterialTheme(colorScheme = colorScheme, typography = rememberSettingsTypography()) {
+ MaterialTheme(colorScheme = colorScheme, typography = rememberSettingsTypography()) {
+ CompositionLocalProvider(
+ LocalColorScheme provides settingsColorScheme(isDarkTheme),
+ LocalRippleTheme provides SettingsRippleTheme,
+ ) {
content()
}
}
@@ -46,3 +52,19 @@ object SettingsTheme {
@ReadOnlyComposable
get() = LocalColorScheme.current
}
+
+private object SettingsRippleTheme : RippleTheme {
+ @Composable
+ override fun defaultColor() = MaterialTheme.colorScheme.onSurface
+
+ @Composable
+ override fun rippleAlpha() = RippleAlpha
+}
+
+/** Alpha levels for all content. */
+private val RippleAlpha = RippleAlpha(
+ pressedAlpha = 0.48f,
+ focusedAlpha = 0.48f,
+ draggedAlpha = 0.32f,
+ hoveredAlpha = 0.16f,
+)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
index 83dcd137fbd7..780933d3c9e2 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchContract.kt
@@ -43,6 +43,7 @@ const val SEARCH_DYNAMIC_ROW = "search_dynamic_row"
/** Enum to define all column names in provider. */
enum class ColumnEnum(val id: String) {
ENTRY_ID("entryId"),
+ ENTRY_LABEL("entryLabel"),
SEARCH_TITLE("searchTitle"),
SEARCH_KEYWORD("searchKw"),
SEARCH_PATH("searchPath"),
@@ -50,7 +51,6 @@ enum class ColumnEnum(val id: String) {
INTENT_TARGET_CLASS("intentTargetClass"),
INTENT_EXTRAS("intentExtras"),
SLICE_URI("sliceUri"),
- LEGACY_KEY("legacyKey"),
ENTRY_DISABLED("entryDisabled"),
}
@@ -64,6 +64,7 @@ enum class QueryEnum(
SEARCH_STATIC_DATA,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.SEARCH_TITLE,
ColumnEnum.SEARCH_KEYWORD,
ColumnEnum.SEARCH_PATH,
@@ -71,13 +72,13 @@ enum class QueryEnum(
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
ColumnEnum.SLICE_URI,
- ColumnEnum.LEGACY_KEY
)
),
SEARCH_DYNAMIC_DATA_QUERY(
SEARCH_DYNAMIC_DATA,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.SEARCH_TITLE,
ColumnEnum.SEARCH_KEYWORD,
ColumnEnum.SEARCH_PATH,
@@ -85,13 +86,13 @@ enum class QueryEnum(
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
ColumnEnum.SLICE_URI,
- ColumnEnum.LEGACY_KEY
)
),
SEARCH_IMMUTABLE_STATUS_DATA_QUERY(
SEARCH_IMMUTABLE_STATUS,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.ENTRY_DISABLED,
)
),
@@ -99,6 +100,7 @@ enum class QueryEnum(
SEARCH_MUTABLE_STATUS,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.ENTRY_DISABLED,
)
),
@@ -106,6 +108,7 @@ enum class QueryEnum(
SEARCH_STATIC_ROW,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.SEARCH_TITLE,
ColumnEnum.SEARCH_KEYWORD,
ColumnEnum.SEARCH_PATH,
@@ -113,7 +116,6 @@ enum class QueryEnum(
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
ColumnEnum.SLICE_URI,
- ColumnEnum.LEGACY_KEY,
ColumnEnum.ENTRY_DISABLED,
)
),
@@ -121,6 +123,7 @@ enum class QueryEnum(
SEARCH_DYNAMIC_ROW,
listOf(
ColumnEnum.ENTRY_ID,
+ ColumnEnum.ENTRY_LABEL,
ColumnEnum.SEARCH_TITLE,
ColumnEnum.SEARCH_KEYWORD,
ColumnEnum.SEARCH_PATH,
@@ -128,7 +131,6 @@ enum class QueryEnum(
ColumnEnum.INTENT_TARGET_CLASS,
ColumnEnum.INTENT_EXTRAS,
ColumnEnum.SLICE_URI,
- ColumnEnum.LEGACY_KEY,
ColumnEnum.ENTRY_DISABLED,
)
),
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
index 057f13f99928..eacb28c29bc3 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
@@ -42,7 +42,7 @@ private const val TAG = "SpaSearchProvider"
* One can query the provider result by:
* $ adb shell content query --uri content://<AuthorityPath>/<QueryPath>
* For gallery, AuthorityPath = com.android.spa.gallery.search.provider
- * For Settings, AuthorityPath = com.android.settings.spa.search.provider"
+ * For Settings, AuthorityPath = com.android.settings.spa.search.provider
* Some examples:
* $ adb shell content query --uri content://<AuthorityPath>/search_static_data
* $ adb shell content query --uri content://<AuthorityPath>/search_dynamic_data
@@ -205,6 +205,7 @@ class SpaSearchProvider : ContentProvider() {
val searchData = entry.getSearchData() ?: return
val intent = entry.createIntent(SESSION_SEARCH)
val row = cursor.newRow().add(ColumnEnum.ENTRY_ID.id, entry.id)
+ .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
.add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
.add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
.add(
@@ -221,7 +222,6 @@ class SpaSearchProvider : ContentProvider() {
ColumnEnum.SLICE_URI.id, Uri.Builder()
.fromEntry(entry, spaEnvironment.sliceProviderAuthorities)
)
- // TODO: support legacy key
}
private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) {
@@ -229,6 +229,7 @@ class SpaSearchProvider : ContentProvider() {
val statusData = entry.getStatusData() ?: return
cursor.newRow()
.add(ColumnEnum.ENTRY_ID.id, entry.id)
+ .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
.add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
}
@@ -239,6 +240,7 @@ class SpaSearchProvider : ContentProvider() {
val searchData = entry.getSearchData() ?: return
val intent = entry.createIntent(SESSION_SEARCH)
val row = cursor.newRow().add(ColumnEnum.ENTRY_ID.id, entry.id)
+ .add(ColumnEnum.ENTRY_LABEL.id, entry.label)
.add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
.add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
.add(
@@ -255,8 +257,6 @@ class SpaSearchProvider : ContentProvider() {
ColumnEnum.SLICE_URI.id, Uri.Builder()
.fromEntry(entry, spaEnvironment.sliceProviderAuthorities)
)
- // TODO: support legacy key
-
// Fetch status data. We can add runtime arguments later if necessary
val statusData = entry.getStatusData() ?: return
row.add(ColumnEnum.ENTRY_DISABLED.id, statusData.isDisabled)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt
index b8c59ad07cfd..7f7088a01aa2 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/ProgressBarPreference.kt
@@ -163,7 +163,7 @@ private fun TitleWithData(
Text(
text = data,
color = MaterialTheme.colorScheme.onSurfaceVariant,
- style = MaterialTheme.typography.titleMedium,
+ style = MaterialTheme.typography.titleSmall,
)
}
subTitle()
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
index e0e9b951065b..c6e13a14063f 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
@@ -16,19 +16,21 @@
package com.android.settingslib.spa.widget.scaffold
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.TabRow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import com.android.settingslib.spa.framework.compose.HorizontalPager
-import com.android.settingslib.spa.framework.compose.rememberPagerState
import com.android.settingslib.spa.framework.theme.SettingsDimension
import kotlin.math.absoluteValue
import kotlinx.coroutines.launch
+@OptIn(ExperimentalFoundationApi::class)
@Composable
fun SettingsPager(titles: List<String>, content: @Composable (page: Int) -> Unit) {
check(titles.isNotEmpty())
@@ -52,7 +54,7 @@ fun SettingsPager(titles: List<String>, content: @Composable (page: Int) -> Unit
SettingsTab(
title = title,
selected = pagerState.currentPage == page,
- currentPageOffset = pagerState.currentPageOffset.absoluteValue,
+ currentPageOffset = pagerState.currentPageOffsetFraction.absoluteValue,
onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(page)
@@ -62,7 +64,7 @@ fun SettingsPager(titles: List<String>, content: @Composable (page: Int) -> Unit
}
}
- HorizontalPager(count = titles.size, state = pagerState) { page ->
+ HorizontalPager(pageCount = titles.size, state = pagerState) { page ->
content(page)
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
index 64a9c7353f07..f0df9a6aa389 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
@@ -23,8 +23,8 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.outlined.ArrowDropDown
-import androidx.compose.material.icons.outlined.ArrowDropUp
+import androidx.compose.material.icons.outlined.ExpandLess
+import androidx.compose.material.icons.outlined.ExpandMore
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DropdownMenu
@@ -76,8 +76,8 @@ fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) ->
SpinnerText(options.find { it.id == selectedId })
Icon(
imageVector = when {
- expanded -> Icons.Outlined.ArrowDropUp
- else -> Icons.Outlined.ArrowDropDown
+ expanded -> Icons.Outlined.ExpandLess
+ else -> Icons.Outlined.ExpandMore
},
contentDescription = null,
)
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
index 379b9a7db09b..b139f2874a36 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
@@ -115,7 +115,7 @@ class SettingsEntryRepositoryTest {
fun testGetEntryPath() {
SpaEnvironmentFactory.reset(spaEnvironment)
assertThat(
- entryRepository.getEntryPathWithDisplayName(
+ entryRepository.getEntryPathWithLabel(
genEntryId("Layer2Entry1", SppLayer2.createSettingsPage())
)
).containsExactly("Layer2Entry1", "INJECT_SppLayer2", "INJECT_SppLayer1", "ROOT_SppHome")
@@ -129,7 +129,7 @@ class SettingsEntryRepositoryTest {
).containsExactly("entryTitle", "SppLayer2", "TitleLayer1", "TitleHome").inOrder()
assertThat(
- entryRepository.getEntryPathWithDisplayName(
+ entryRepository.getEntryPathWithLabel(
genEntryId(
"INJECT",
SppLayer1.createSettingsPage(),
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
index 5754c9bfbdfa..ce349795c8c6 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
@@ -68,7 +68,7 @@ class SettingsEntryTest {
val owner = createSettingsPage("mySpp")
val entry = SettingsEntryBuilder.create(owner, "myEntry").build()
assertThat(entry.id).isEqualTo(genEntryId("myEntry", owner))
- assertThat(entry.displayName).isEqualTo("myEntry")
+ assertThat(entry.label).isEqualTo("myEntry")
assertThat(entry.owner.sppName).isEqualTo("mySpp")
assertThat(entry.owner.displayName).isEqualTo("mySpp")
assertThat(entry.fromPage).isNull()
@@ -87,14 +87,14 @@ class SettingsEntryTest {
val entryFrom =
SettingsEntryBuilder.createLinkFrom("myEntry", owner).setLink(toPage = toPage).build()
assertThat(entryFrom.id).isEqualTo(genEntryId("myEntry", owner, owner, toPage))
- assertThat(entryFrom.displayName).isEqualTo("myEntry")
+ assertThat(entryFrom.label).isEqualTo("myEntry")
assertThat(entryFrom.fromPage!!.sppName).isEqualTo("mySpp")
assertThat(entryFrom.toPage!!.sppName).isEqualTo("toSpp")
val entryTo =
SettingsEntryBuilder.createLinkTo("myEntry", owner).setLink(fromPage = fromPage).build()
assertThat(entryTo.id).isEqualTo(genEntryId("myEntry", owner, fromPage, owner))
- assertThat(entryTo.displayName).isEqualTo("myEntry")
+ assertThat(entryTo.label).isEqualTo("myEntry")
assertThat(entryTo.fromPage!!.sppName).isEqualTo("fromSpp")
assertThat(entryTo.toPage!!.sppName).isEqualTo("mySpp")
}
@@ -108,7 +108,7 @@ class SettingsEntryTest {
INJECT_ENTRY_NAME_TEST, owner, toPage = owner
)
)
- assertThat(entryInject.displayName).isEqualTo("${INJECT_ENTRY_NAME_TEST}_mySpp")
+ assertThat(entryInject.label).isEqualTo("${INJECT_ENTRY_NAME_TEST}_mySpp")
assertThat(entryInject.fromPage).isNull()
assertThat(entryInject.toPage).isNotNull()
}
@@ -122,7 +122,7 @@ class SettingsEntryTest {
ROOT_ENTRY_NAME_TEST, owner, toPage = owner
)
)
- assertThat(entryInject.displayName).isEqualTo("myRootEntry")
+ assertThat(entryInject.label).isEqualTo("myRootEntry")
assertThat(entryInject.fromPage).isNull()
assertThat(entryInject.toPage).isNotNull()
}
@@ -133,14 +133,14 @@ class SettingsEntryTest {
val owner = createSettingsPage("SppHome")
val entryBuilder =
SettingsEntryBuilder.create(owner, "myEntry")
- .setDisplayName("myEntryDisplay")
+ .setLabel("myEntryDisplay")
.setIsSearchDataDynamic(false)
.setHasMutableStatus(true)
.setSearchDataFn { null }
.setSliceDataFn { _, _ -> null }
val entry = entryBuilder.build()
assertThat(entry.id).isEqualTo(genEntryId("myEntry", owner))
- assertThat(entry.displayName).isEqualTo("myEntryDisplay")
+ assertThat(entry.label).isEqualTo("myEntryDisplay")
assertThat(entry.fromPage).isNull()
assertThat(entry.toPage).isNull()
assertThat(entry.isAllowSearch).isTrue()
@@ -152,14 +152,14 @@ class SettingsEntryTest {
val ownerDisabled = createSettingsPage("SppDisabled")
val entryBuilderDisabled =
SettingsEntryBuilder.create(ownerDisabled, "myEntry")
- .setDisplayName("myEntryDisplay")
+ .setLabel("myEntryDisplay")
.setIsSearchDataDynamic(false)
.setHasMutableStatus(true)
.setSearchDataFn { null }
.setSliceDataFn { _, _ -> null }
val entryDisabled = entryBuilderDisabled.build()
assertThat(entryDisabled.id).isEqualTo(genEntryId("myEntry", ownerDisabled))
- assertThat(entryDisabled.displayName).isEqualTo("myEntryDisplay")
+ assertThat(entryDisabled.label).isEqualTo("myEntryDisplay")
assertThat(entryDisabled.fromPage).isNull()
assertThat(entryDisabled.toPage).isNull()
assertThat(entryDisabled.isAllowSearch).isFalse()
@@ -175,7 +175,7 @@ class SettingsEntryTest {
SpaEnvironmentFactory.reset()
val entry3 = entryBuilder.build()
assertThat(entry3.id).isEqualTo(genEntryId("myEntry", owner))
- assertThat(entry3.displayName).isEqualTo("myEntryDisplay")
+ assertThat(entry3.label).isEqualTo("myEntryDisplay")
assertThat(entry3.fromPage).isNull()
assertThat(entry3.toPage).isNull()
assertThat(entry3.isAllowSearch).isFalse()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
index 007d08b81547..00d23149b994 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
@@ -63,6 +63,11 @@ class SpaSearchProviderTest {
pageOwner.getEntryId("SearchDynamicWithImmutableStatus")
)
immutableStatus.checkValue(
+ QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithImmutableStatus")
+ )
+ immutableStatus.checkValue(
QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
)
@@ -75,6 +80,11 @@ class SpaSearchProviderTest {
pageOwner.getEntryId("SearchStaticWithMutableStatus")
)
mutableStatus.checkValue(
+ QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchStaticWithMutableStatus")
+ )
+ mutableStatus.checkValue(
QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY, ColumnEnum.ENTRY_DISABLED, false.toString()
)
@@ -85,6 +95,11 @@ class SpaSearchProviderTest {
pageOwner.getEntryId("SearchDynamicWithMutableStatus")
)
mutableStatus.checkValue(
+ QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithMutableStatus")
+ )
+ mutableStatus.checkValue(
QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
)
}
@@ -102,6 +117,11 @@ class SpaSearchProviderTest {
pageOwner.getEntryId("SearchStaticWithNoStatus")
)
staticData.checkValue(
+ QueryEnum.SEARCH_STATIC_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchStaticWithNoStatus")
+ )
+ staticData.checkValue(
QueryEnum.SEARCH_STATIC_DATA_QUERY, ColumnEnum.SEARCH_TITLE, "SearchStaticWithNoStatus"
)
staticData.checkValue(
@@ -139,6 +159,11 @@ class SpaSearchProviderTest {
ColumnEnum.ENTRY_ID,
pageOwner.getEntryId("SearchStaticWithMutableStatus")
)
+ staticData.checkValue(
+ QueryEnum.SEARCH_STATIC_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchStaticWithMutableStatus")
+ )
val dynamicData = searchProvider.querySearchDynamicData()
Truth.assertThat(dynamicData.count).isEqualTo(2)
@@ -148,6 +173,11 @@ class SpaSearchProviderTest {
ColumnEnum.ENTRY_ID,
pageOwner.getEntryId("SearchDynamicWithMutableStatus")
)
+ dynamicData.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithMutableStatus")
+ )
dynamicData.moveToNext()
dynamicData.checkValue(
@@ -157,6 +187,11 @@ class SpaSearchProviderTest {
)
dynamicData.checkValue(
QueryEnum.SEARCH_DYNAMIC_DATA_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithImmutableStatus")
+ )
+ dynamicData.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_DATA_QUERY,
ColumnEnum.SEARCH_KEYWORD,
listOf("kw1", "kw2").toString()
)
@@ -175,6 +210,11 @@ class SpaSearchProviderTest {
pageOwner.getEntryId("SearchStaticWithNoStatus")
)
staticRow.checkValue(
+ QueryEnum.SEARCH_STATIC_ROW_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchStaticWithNoStatus")
+ )
+ staticRow.checkValue(
QueryEnum.SEARCH_STATIC_ROW_QUERY, ColumnEnum.SEARCH_TITLE, "SearchStaticWithNoStatus"
)
staticRow.checkValue(
@@ -223,6 +263,11 @@ class SpaSearchProviderTest {
pageOwner.getEntryId("SearchStaticWithMutableStatus")
)
dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchStaticWithMutableStatus")
+ )
+ dynamicRow.checkValue(
QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, false.toString()
)
@@ -233,6 +278,11 @@ class SpaSearchProviderTest {
pageOwner.getEntryId("SearchDynamicWithMutableStatus")
)
dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithMutableStatus")
+ )
+ dynamicRow.checkValue(
QueryEnum.SEARCH_DYNAMIC_ROW_QUERY, ColumnEnum.ENTRY_DISABLED, true.toString()
)
@@ -245,6 +295,11 @@ class SpaSearchProviderTest {
)
dynamicRow.checkValue(
QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
+ ColumnEnum.ENTRY_LABEL,
+ pageOwner.getEntryLabel("SearchDynamicWithImmutableStatus")
+ )
+ dynamicRow.checkValue(
+ QueryEnum.SEARCH_DYNAMIC_ROW_QUERY,
ColumnEnum.SEARCH_KEYWORD,
listOf("kw1", "kw2").toString()
)
@@ -271,3 +326,7 @@ private fun Cursor.getExtras(query: QueryEnum, column: ColumnEnum): Bundle? {
private fun SettingsPage.getEntryId(name: String): String {
return SettingsEntryBuilder.create(this, name).build().id
}
+
+private fun SettingsPage.getEntryLabel(name: String): String {
+ return SettingsEntryBuilder.create(this, name).build().label
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
index 14cb698f7d04..e37288ab3a71 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
@@ -81,7 +81,7 @@ class TogglePermissionAppInfoPageTest {
val entryList = appInfoPageProvider.buildEntry(null)
assertThat(entryList).hasSize(1)
- assertThat(entryList[0].displayName).isEqualTo("AllowControl")
+ assertThat(entryList[0].label).isEqualTo("AllowControl")
}
@Test
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 00a58f2fa5d4..7306a1f32789 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -116,6 +116,36 @@
<item>full</item>
</string-array>
+ <!-- Titles for Bluetooth HCI Snoop Filtered Logging -->
+ <string-array name="bt_hci_snoop_log_filters_entries">
+ <item>Headers Filtered</item>
+ <item>A2DP Media Packets Filtered</item>
+ <item>RFCOMM Channel Filtered</item>
+ </string-array>
+
+ <!-- Values for Bluetooth HCI Snoop Filtered Logging -->
+ <string-array name="bt_hci_snoop_log_filters_values" translatable="false">
+ <item>headers</item>
+ <item>profiles.a2dp</item>
+ <item>profiles.rfcomm</item>
+ </string-array>
+
+ <!-- Titles for Bluetooth HCI Snoop Filtered Logging -->
+ <string-array name="bt_hci_snoop_log_profile_filter_entries">
+ <item>Disabled</item>
+ <item>Magic</item>
+ <item>Header</item>
+ <item>Full Filter</item>
+ </string-array>
+
+ <!-- Values for Bluetooth HCI Snoop Filtered Logging -->
+ <string-array name="bt_hci_snoop_log_profile_filter_values" translatable="false">
+ <item>disabled</item>
+ <item>magic</item>
+ <item>header</item>
+ <item>fullfilter</item>
+ </string-array>
+
<!-- Titles for Bluetooth AVRCP Versions -->
<string-array name="bluetooth_avrcp_versions">
<item>AVRCP 1.5 (Default)</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 6641db1e6449..91b852ab9f67 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -235,7 +235,7 @@ public class A2dpProfile implements LocalBluetoothProfile {
/**
* @return whether high quality audio is enabled or not
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
if (bluetoothDevice == null) {
@@ -287,7 +287,7 @@ public class A2dpProfile implements LocalBluetoothProfile {
* @param device to get codec label from
* @return the label associated with the device codec
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index f83ebaacb8e6..720d6dda24b2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -26,16 +26,23 @@ import android.content.AttributionSource;
import android.content.IContentProvider;
import android.os.Binder;
import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.provider.DeviceConfig;
+import android.provider.DeviceConfigShellCommandHandler;
import android.provider.Settings;
import android.provider.Settings.Config.SyncDisabledMode;
+import android.provider.UpdatableDeviceConfigServiceReadiness;
+
+import com.android.internal.util.FastPrintWriter;
import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -56,8 +63,32 @@ public final class DeviceConfigService extends Binder {
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
- String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
- (new MyShellCommand(mProvider)).exec(this, in, out, err, args, callback, resultReceiver);
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver)
+ throws RemoteException {
+ if (UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
+ callUpdableDeviceConfigShellCommandHandler(in, out, err, args, resultReceiver);
+ } else {
+ (new MyShellCommand(mProvider))
+ .exec(this, in, out, err, args, callback, resultReceiver);
+ }
+ }
+
+ private void callUpdableDeviceConfigShellCommandHandler(FileDescriptor in, FileDescriptor out,
+ FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
+ int result = -1;
+ try (
+ ParcelFileDescriptor inPfd = ParcelFileDescriptor.dup(in);
+ ParcelFileDescriptor outPfd = ParcelFileDescriptor.dup(out);
+ ParcelFileDescriptor errPfd = ParcelFileDescriptor.dup(err)) {
+ result = DeviceConfigShellCommandHandler.handleShellCommand(inPfd, outPfd, errPfd,
+ args);
+ } catch (IOException e) {
+ PrintWriter pw = new FastPrintWriter(new FileOutputStream(err));
+ pw.println("dup() failed: " + e.getMessage());
+ pw.flush();
+ } finally {
+ resultReceiver.send(result, null);
+ }
}
static final class MyShellCommand extends ShellCommand {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f1413e54f16d..7abace03aa83 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -97,7 +97,6 @@ import android.provider.Settings.Config.SyncDisabledMode;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.provider.Settings.SetAllResult;
-import android.provider.UpdatableDeviceConfigServiceReadiness;
import android.provider.settings.validators.SystemSettingsValidators;
import android.provider.settings.validators.Validator;
import android.text.TextUtils;
@@ -419,16 +418,10 @@ public class SettingsProvider extends ContentProvider {
startWatchingUserRestrictionChanges();
});
ServiceManager.addService("settings", new SettingsService(this));
- addDeviceConfigServiceIfNeeded();
+ ServiceManager.addService("device_config", new DeviceConfigService(this));
return true;
}
- private void addDeviceConfigServiceIfNeeded() {
- if (!UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
- ServiceManager.addService("device_config", new DeviceConfigService(this));
- }
- }
-
@Override
public Bundle call(String method, String name, Bundle args) {
final int requestingUserId = getRequestingUserId(args);
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index fdab7490e476..a08b59829de2 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -23,6 +23,7 @@ import android.animation.ValueAnimator
import android.graphics.Canvas
import android.graphics.Typeface
import android.graphics.fonts.Font
+import android.graphics.fonts.FontVariationAxis
import android.text.Layout
import android.util.SparseArray
@@ -215,13 +216,40 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
textInterpolator.targetPaint.textSize = textSize
}
if (weight >= 0) {
- // Paint#setFontVariationSettings creates Typeface instance from scratch. To reduce the
- // memory impact, cache the typeface result.
- textInterpolator.targetPaint.typeface =
- typefaceCache.getOrElse(weight) {
- textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
- textInterpolator.targetPaint.typeface
+ val fontVariationArray =
+ FontVariationAxis.fromFontVariationSettings(
+ textInterpolator.targetPaint.fontVariationSettings
+ )
+ if (fontVariationArray.isNullOrEmpty()) {
+ textInterpolator.targetPaint.typeface =
+ typefaceCache.getOrElse(weight) {
+ textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
+ textInterpolator.targetPaint.typeface
+ }
+ } else {
+ val idx = fontVariationArray.indexOfFirst { it.tag == "$TAG_WGHT" }
+ if (idx == -1) {
+ val updatedFontVariation =
+ textInterpolator.targetPaint.fontVariationSettings + ",'$TAG_WGHT' $weight"
+ textInterpolator.targetPaint.typeface =
+ typefaceCache.getOrElse(weight) {
+ textInterpolator.targetPaint.fontVariationSettings =
+ updatedFontVariation
+ textInterpolator.targetPaint.typeface
+ }
+ } else {
+ fontVariationArray[idx] = FontVariationAxis(
+ "$TAG_WGHT", weight.toFloat())
+ val updatedFontVariation =
+ FontVariationAxis.toFontVariationSettings(fontVariationArray)
+ textInterpolator.targetPaint.typeface =
+ typefaceCache.getOrElse(weight) {
+ textInterpolator.targetPaint.fontVariationSettings =
+ updatedFontVariation
+ textInterpolator.targetPaint.typeface
+ }
}
+ }
}
if (color != null) {
textInterpolator.targetPaint.color = color
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableImageView.kt
index 7bbfec7df9d8..a1d9d90523eb 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableImageView.kt
@@ -15,7 +15,7 @@
*
*/
-package com.android.systemui.common.ui.view
+package com.android.systemui.animation.view
import android.content.Context
import android.util.AttributeSet
@@ -23,6 +23,7 @@ import android.widget.ImageView
import com.android.systemui.animation.LaunchableView
import com.android.systemui.animation.LaunchableViewDelegate
+/** An [ImageView] that also implements [LaunchableView]. */
class LaunchableImageView : ImageView, LaunchableView {
private val delegate =
LaunchableViewDelegate(
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableLinearLayout.kt
index 2edac528b037..bce262291f87 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableLinearLayout.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.common.ui.view
+package com.android.systemui.animation.view
import android.content.Context
import android.util.AttributeSet
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableTextView.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableTextView.kt
new file mode 100644
index 000000000000..286996dcaeaa
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/view/LaunchableTextView.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.animation.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.TextView
+import com.android.systemui.animation.LaunchableView
+import com.android.systemui.animation.LaunchableViewDelegate
+
+/** A [TextView] that also implements [LaunchableView]. */
+class LaunchableTextView : TextView, LaunchableView {
+ private val delegate =
+ LaunchableViewDelegate(
+ this,
+ superSetVisibility = { super.setVisibility(it) },
+ )
+
+ constructor(context: Context?) : super(context)
+ constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context?,
+ attrs: AttributeSet?,
+ defStyleAttr: Int,
+ ) : super(context, attrs, defStyleAttr)
+
+ override fun setShouldBlockVisibilityChanges(block: Boolean) {
+ delegate.setShouldBlockVisibilityChanges(block)
+ }
+
+ override fun setVisibility(visibility: Int) {
+ delegate.setVisibility(visibility)
+ }
+}
diff --git a/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml b/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml
index fc18132d4dc3..6fe7d39f748a 100644
--- a/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml
+++ b/packages/SystemUI/res-keyguard/layout/footer_actions_text_button.xml
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.systemui.common.ui.view.LaunchableLinearLayout
+<com.android.systemui.animation.view.LaunchableLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
android:layout_height="@dimen/qs_security_footer_single_line_height"
@@ -63,4 +63,4 @@
android:src="@*android:drawable/ic_chevron_end"
android:autoMirrored="true"
android:tint="?android:attr/textColorSecondary" />
-</com.android.systemui.common.ui.view.LaunchableLinearLayout> \ No newline at end of file
+</com.android.systemui.animation.view.LaunchableLinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_progress_activity.xml b/packages/SystemUI/res/drawable/ic_progress_activity.xml
new file mode 100644
index 000000000000..abf0625d40d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_progress_activity.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M24,44Q19.8,44 16.15,42.45Q12.5,40.9 9.8,38.2Q7.1,35.5 5.55,31.85Q4,28.2 4,24Q4,19.8 5.55,16.15Q7.1,12.5 9.8,9.8Q12.5,7.1 16.15,5.55Q19.8,4 24,4Q24.6,4 25.05,4.45Q25.5,4.9 25.5,5.5Q25.5,6.1 25.05,6.55Q24.6,7 24,7Q16.95,7 11.975,11.975Q7,16.95 7,24Q7,31.05 11.975,36.025Q16.95,41 24,41Q31.05,41 36.025,36.025Q41,31.05 41,24Q41,23.4 41.45,22.95Q41.9,22.5 42.5,22.5Q43.1,22.5 43.55,22.95Q44,23.4 44,24Q44,28.2 42.45,31.85Q40.9,35.5 38.2,38.2Q35.5,40.9 31.85,42.45Q28.2,44 24,44Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml b/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml
new file mode 100644
index 000000000000..1b12e74141a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?android:attr/textColorSecondary">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M39.8,41.95 L26.65,28.8Q25.15,30.1 23.15,30.825Q21.15,31.55 18.9,31.55Q13.5,31.55 9.75,27.8Q6,24.05 6,18.75Q6,13.45 9.75,9.7Q13.5,5.95 18.85,5.95Q24.15,5.95 27.875,9.7Q31.6,13.45 31.6,18.75Q31.6,20.9 30.9,22.9Q30.2,24.9 28.8,26.65L42,39.75ZM18.85,28.55Q22.9,28.55 25.75,25.675Q28.6,22.8 28.6,18.75Q28.6,14.7 25.75,11.825Q22.9,8.95 18.85,8.95Q14.75,8.95 11.875,11.825Q9,14.7 9,18.75Q9,22.8 11.875,25.675Q14.75,28.55 18.85,28.55Z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_shortcutlist_search_button_cancel.xml b/packages/SystemUI/res/drawable/ic_shortcutlist_search_button_cancel.xml
new file mode 100644
index 000000000000..e3b1ab2d3e73
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_shortcutlist_search_button_cancel.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/textColorSecondary">
+ <path
+ android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
+ android:fillColor="@android:color/white"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_button_colored.xml b/packages/SystemUI/res/drawable/shortcut_button_colored.xml
new file mode 100644
index 000000000000..a21489cc47aa
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_button_colored.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <ripple
+ android:color="?android:attr/colorControlHighlight">
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="16dp"/>
+ <solid android:color="?androidprv:attr/colorSurface"/>
+ </shape>
+ </item>
+ </ripple>
+</inset> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml b/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml
new file mode 100644
index 000000000000..2ff32b6ee9b5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <ripple
+ android:color="?android:attr/colorControlHighlight">
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="16dp"/>
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+ </shape>
+ </item>
+ </ripple>
+</inset> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml b/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml
new file mode 100644
index 000000000000..6ce3eaecc147
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_dialog_bg.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="?android:attr/colorBackground"/>
+ <corners android:topLeftRadius="16dp"
+ android:topRightRadius="16dp"
+ android:bottomLeftRadius="0dp"
+ android:bottomRightRadius="0dp"/>
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/shortcut_search_background.xml b/packages/SystemUI/res/drawable/shortcut_search_background.xml
new file mode 100644
index 000000000000..66fc191cb736
--- /dev/null
+++ b/packages/SystemUI/res/drawable/shortcut_search_background.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface" />
+ <corners android:radius="24dp" />
+ </shape>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/chipbar.xml b/packages/SystemUI/res/layout/chipbar.xml
index 8cf4f4de27da..0ff944c2becf 100644
--- a/packages/SystemUI/res/layout/chipbar.xml
+++ b/packages/SystemUI/res/layout/chipbar.xml
@@ -60,14 +60,13 @@
/>
<!-- At most one of [loading, failure_icon, undo] will be visible at a time. -->
- <ProgressBar
+ <ImageView
android:id="@+id/loading"
- android:indeterminate="true"
android:layout_width="@dimen/media_ttt_status_icon_size"
android:layout_height="@dimen/media_ttt_status_icon_size"
android:layout_marginStart="@dimen/media_ttt_last_item_start_margin"
- android:indeterminateTint="?androidprv:attr/colorAccentPrimaryVariant"
- style="?android:attr/progressBarStyleSmall"
+ android:src="@drawable/ic_progress_activity"
+ android:tint="?androidprv:attr/colorAccentPrimaryVariant"
android:alpha="0.0"
/>
diff --git a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
index 446bb0122630..fb78b49dfcc2 100644
--- a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
@@ -20,7 +20,7 @@
android:layout_width="wrap_content"
android:paddingVertical="@dimen/dream_overlay_complication_home_controls_padding">
- <com.android.systemui.common.ui.view.LaunchableImageView
+ <com.android.systemui.animation.view.LaunchableImageView
android:id="@+id/home_controls_chip"
android:layout_height="@dimen/keyguard_affordance_fixed_height"
android:layout_width="@dimen/keyguard_affordance_fixed_width"
diff --git a/packages/SystemUI/res/layout/font_scaling_dialog.xml b/packages/SystemUI/res/layout/font_scaling_dialog.xml
new file mode 100644
index 000000000000..27c1e9d03df9
--- /dev/null
+++ b/packages/SystemUI/res/layout/font_scaling_dialog.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/font_scaling_slider"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ app:max="6"
+ app:progress="0"
+ app:iconStartContentDescription="@string/font_scaling_smaller"
+ app:iconEndContentDescription="@string/font_scaling_larger"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml
new file mode 100644
index 000000000000..530e46eb1c40
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_short_separator.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+ -->
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="0dp"
+ style="@style/ShortcutHorizontalDivider" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml
new file mode 100644
index 000000000000..a037cb284b5a
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_icon_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/ksh_item_padding"
+ android:layout_marginLeft="0dp"
+ android:layout_marginRight="0dp"
+ android:scaleType="fitXY"
+ android:tint="?android:attr/textColorPrimary"
+ style="@style/ShortcutItemBackground" /> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml
new file mode 100644
index 000000000000..12b4e150ee2d
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_new_view.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/ksh_item_padding"
+ android:layout_marginStart="@dimen/ksh_item_margin_start"
+ style="@style/ShortcutItemBackground"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="false"
+ android:gravity="center"
+ android:textSize="@dimen/ksh_item_text_size"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml
new file mode 100644
index 000000000000..727f2c15d5e5
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_plus_view.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/ksh_item_padding"
+ android:layout_marginLeft="0dp"
+ android:layout_marginRight="0dp"
+ android:text="+"
+ style="@style/ShortcutItemBackground"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"
+ android:gravity="center"
+ android:textSize="@dimen/ksh_item_text_size"
+ android:textAllCaps="true"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml
new file mode 100644
index 000000000000..00ef94784740
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_vertical_bar_view.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/ksh_item_padding"
+ android:layout_marginLeft="0dp"
+ android:layout_marginRight="0dp"
+ android:text="|"
+ style="@style/ShortcutItemBackground"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"
+ android:gravity="center"
+ android:textSize="@dimen/ksh_item_text_size"
+ android:textAllCaps="true"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
new file mode 100644
index 000000000000..8a66f50d13b1
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@drawable/shortcut_dialog_bg"
+ android:layout_width="@dimen/ksh_layout_width"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/shortcut_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="40dp"
+ android:layout_gravity="center_horizontal"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/keyboard_shortcut_search_list_title"/>
+
+ <FrameLayout android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <EditText
+ android:id="@+id/keyboard_shortcuts_search"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:layout_marginBottom="24dp"
+ android:layout_marginStart="49dp"
+ android:layout_marginEnd="49dp"
+ android:padding="16dp"
+ android:background="@drawable/shortcut_search_background"
+ android:drawableStart="@drawable/ic_shortcutlist_search"
+ android:drawablePadding="15dp"
+ android:singleLine="true"
+ android:textColor="?android:attr/textColorPrimary"
+ android:inputType="text"
+ android:textDirection="locale"
+ android:textAlignment="viewStart"
+ android:hint="@string/keyboard_shortcut_search_list_hint"
+ android:textColorHint="?android:attr/textColorTertiary" />
+
+ <ImageView
+ android:id="@+id/keyboard_shortcuts_search_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:layout_marginTop="24dp"
+ android:layout_marginBottom="24dp"
+ android:layout_marginEnd="49dp"
+ android:padding="16dp"
+ android:contentDescription="@string/keyboard_shortcut_clear_text"
+ android:src="@drawable/ic_shortcutlist_search_button_cancel" />
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <View
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginStart="37dp"/>
+
+ <Button
+ android:id="@+id/shortcut_system"
+ android:layout_width="120dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ style="@style/ShortCutButton"
+ android:text="@string/keyboard_shortcut_search_category_system"/>
+
+ <Button
+ android:id="@+id/shortcut_input"
+ android:layout_width="120dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ style="@style/ShortCutButton"
+ android:text="@string/keyboard_shortcut_search_category_input"/>
+
+ <Button
+ android:id="@+id/shortcut_open_apps"
+ android:layout_width="120dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ style="@style/ShortCutButton"
+ android:text="@string/keyboard_shortcut_search_category_open_apps"/>
+
+ <Button
+ android:id="@+id/shortcut_specific_app"
+ android:layout_width="120dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ style="@style/ShortCutButton"
+ android:text="@string/keyboard_shortcut_search_category_current_app"/>
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/shortcut_search_no_result"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="50dp"
+ android:layout_gravity="center_horizontal"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/keyboard_shortcut_search_list_no_result"/>
+
+ <ScrollView
+ android:id="@+id/keyboard_shortcuts_scroll_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginStart="25dp"
+ android:layout_marginEnd="25dp">
+ <LinearLayout
+ android:id="@+id/keyboard_shortcuts_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"/>
+ </ScrollView>
+ <!-- Required for stretching to full available height when the items in the scroll view
+ occupy less space then the full height -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 3f955154c875..2871cdf6f9f6 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -59,7 +59,7 @@
</LinearLayout>
- <com.android.systemui.common.ui.view.LaunchableImageView
+ <com.android.systemui.animation.view.LaunchableImageView
android:id="@+id/start_button"
android:layout_height="@dimen/keyguard_affordance_fixed_height"
android:layout_width="@dimen/keyguard_affordance_fixed_width"
@@ -72,7 +72,7 @@
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:visibility="gone" />
- <com.android.systemui.common.ui.view.LaunchableImageView
+ <com.android.systemui.animation.view.LaunchableImageView
android:id="@+id/end_button"
android:layout_height="@dimen/keyguard_affordance_fixed_height"
android:layout_width="@dimen/keyguard_affordance_fixed_width"
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index f2e114b511bc..9d914197c05a 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -106,7 +106,7 @@
app:layout_constrainedWidth="true"
app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
app:layout_constraintHeight_min="@dimen/min_clickable_item_size">
- <com.android.systemui.common.ui.view.LaunchableLinearLayout
+ <com.android.systemui.animation.view.LaunchableLinearLayout
android:id="@+id/media_seamless_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -135,7 +135,7 @@
android:textDirection="locale"
android:textSize="12sp"
android:lineHeight="16sp" />
- </com.android.systemui.common.ui.view.LaunchableLinearLayout>
+ </com.android.systemui.animation.view.LaunchableLinearLayout>
</LinearLayout>
<!-- Song name -->
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml
index 18d231c5d32f..238fc8438331 100644
--- a/packages/SystemUI/res/layout/ongoing_call_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml
@@ -23,7 +23,7 @@
android:layout_gravity="center_vertical|start"
android:layout_marginStart="5dp"
>
- <com.android.systemui.common.ui.view.LaunchableLinearLayout
+ <com.android.systemui.animation.view.LaunchableLinearLayout
android:id="@+id/ongoing_call_chip_background"
android:layout_width="wrap_content"
android:layout_height="@dimen/ongoing_appops_chip_height"
@@ -55,5 +55,5 @@
android:textColor="?android:attr/colorPrimary"
/>
- </com.android.systemui.common.ui.view.LaunchableLinearLayout>
+ </com.android.systemui.animation.view.LaunchableLinearLayout>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml b/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml
index f20b5821722f..52d1d4fa9bf9 100644
--- a/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml
+++ b/packages/SystemUI/res/layout/seekbar_with_icon_buttons.xml
@@ -1,41 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
+ Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/seekbar_frame"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- tools:parentTag="android.widget.LinearLayout">
+ android:id="@+id/seekbar_frame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ tools:parentTag="android.widget.LinearLayout">
- <ImageView
- android:id="@+id/icon_start"
- android:layout_width="@dimen/magnification_setting_seekbar_icon_size"
- android:layout_height="@dimen/magnification_setting_seekbar_icon_size"
- android:layout_gravity="center"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:adjustViewBounds="true"
- android:focusable="true"
- android:src="@drawable/ic_remove"
- android:tint="?android:attr/textColorPrimary"
- android:tintMode="src_in" />
+ <FrameLayout
+ android:id="@+id/icon_start_frame"
+ android:layout_width="@dimen/min_clickable_item_size"
+ android:layout_height="@dimen/min_clickable_item_size"
+ android:clipChildren="false"
+ android:focusable="true" >
+ <ImageView
+ android:id="@+id/icon_start"
+ android:layout_width="@dimen/seekbar_icon_size"
+ android:layout_height="@dimen/seekbar_icon_size"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:adjustViewBounds="true"
+ android:focusable="false"
+ android:src="@drawable/ic_remove"
+ android:tint="?android:attr/textColorPrimary"
+ android:tintMode="src_in" />
+ </FrameLayout>
<SeekBar
android:id="@+id/seekbar"
@@ -45,16 +51,23 @@
android:layout_gravity="center_vertical"
android:layout_weight="1" />
- <ImageView
- android:id="@+id/icon_end"
- android:layout_width="@dimen/magnification_setting_seekbar_icon_size"
- android:layout_height="@dimen/magnification_setting_seekbar_icon_size"
- android:layout_gravity="center"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:adjustViewBounds="true"
- android:focusable="true"
- android:src="@drawable/ic_add"
- android:tint="?android:attr/textColorPrimary"
- android:tintMode="src_in" />
+ <FrameLayout
+ android:id="@+id/icon_end_frame"
+ android:layout_width="@dimen/min_clickable_item_size"
+ android:layout_height="@dimen/min_clickable_item_size"
+ android:clipChildren="false"
+ android:focusable="true" >
+ <ImageView
+ android:id="@+id/icon_end"
+ android:layout_width="@dimen/seekbar_icon_size"
+ android:layout_height="@dimen/seekbar_icon_size"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:adjustViewBounds="true"
+ android:focusable="false"
+ android:src="@drawable/ic_add"
+ android:tint="?android:attr/textColorPrimary"
+ android:tintMode="src_in" />
+ </FrameLayout>
</merge>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e2fdf1677a33..c6cc0bc01116 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -118,6 +118,7 @@
<color name="ksh_application_group_color">#fff44336</color>
<color name="ksh_key_item_color">@color/material_grey_600</color>
<color name="ksh_key_item_background">@color/material_grey_100</color>
+ <color name="ksh_key_item_new_background">@color/transparent</color>
<color name="instant_apps_color">#ff4d5a64</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 7716fa9a9cdb..12e5f19f3494 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -659,7 +659,7 @@
<item>26</item> <!-- MOUTH_COVERING_DETECTED -->
</integer-array>
- <!-- Which device wake-ups will trigger face auth. These values correspond with
+ <!-- Which device wake-ups will trigger passive auth. These values correspond with
PowerManager#WakeReason. -->
<integer-array name="config_face_auth_wake_up_triggers">
<item>1</item> <!-- WAKE_REASON_POWER_BUTTON -->
@@ -668,6 +668,7 @@
<item>7</item> <!-- WAKE_REASON_WAKE_MOTION -->
<item>9</item> <!-- WAKE_REASON_LID -->
<item>10</item> <!-- WAKE_REASON_DISPLAY_GROUP_ADDED -->
+ <item>12</item> <!-- WAKE_REASON_UNFOLD_DEVICE -->
<item>15</item> <!-- WAKE_REASON_TAP -->
<item>16</item> <!-- WAKE_REASON_LIFT -->
<item>17</item> <!-- WAKE_REASON_BIOMETRIC -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 36172ca498b0..4afe9d52d596 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1183,8 +1183,9 @@
<dimen name="magnification_setting_image_button_padding_horizontal">24dp</dimen>
<dimen name="magnification_setting_image_button_open_in_full_padding_vertical">16dp</dimen>
<dimen name="magnification_setting_image_button_open_in_full_padding_horizontal">28dp</dimen>
- <dimen name="magnification_setting_seekbar_icon_size">24dp</dimen>
+ <!-- Seekbar with icon buttons -->
+ <dimen name="seekbar_icon_size">24dp</dimen>
<!-- How far from the right edge of the screen you need to drag the window before the button
repositions to the other side. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 85edbec37285..435a8669af9b 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1700,34 +1700,105 @@
<string name="keyboard_shortcut_group_system">System</string>
<!-- User visible title for the keyboard shortcut that takes the user to the home screen. -->
<string name="keyboard_shortcut_group_system_home">Home</string>
- <!-- User visible title for the the keyboard shortcut that takes the user to the recents screen. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the recents screen. -->
<string name="keyboard_shortcut_group_system_recents">Recents</string>
- <!-- User visible title for the the keyboard shortcut that triggers the back action. -->
+ <!-- User visible title for the keyboard shortcut that triggers the back action. -->
<string name="keyboard_shortcut_group_system_back">Back</string>
- <!-- User visible title for the the keyboard shortcut that triggers the notification shade. -->
+ <!-- User visible title for the keyboard shortcut that triggers the notification shade. -->
<string name="keyboard_shortcut_group_system_notifications">Notifications</string>
- <!-- User visible title for the the keyboard shortcut that triggers the keyboard shortcuts helper. -->
+ <!-- User visible title for the keyboard shortcut that triggers the keyboard shortcuts helper. -->
<string name="keyboard_shortcut_group_system_shortcuts_helper">Keyboard Shortcuts</string>
- <!-- User visible title for the the keyboard shortcut that switches to the next hardware keyboard layout. [CHAR LIMIT=30] -->
+ <!-- User visible title for the keyboard shortcut that switches to the next hardware keyboard layout. -->
<string name="keyboard_shortcut_group_system_switch_input">Switch keyboard layout</string>
- <!-- User visible title for the system-wide applications keyboard shortcuts list. -->
+ <!-- Content description for the clear text button in shortcut search list. [CHAR LIMIT=NONE] -->
+ <string name="keyboard_shortcut_clear_text">Clear text</string>
+ <!-- The title for keyboard shortcut search list [CHAR LIMIT=25] -->
+ <string name="keyboard_shortcut_search_list_title">Shortcuts</string>
+ <!-- The hint for keyboard shortcut search list [CHAR LIMIT=25] -->
+ <string name="keyboard_shortcut_search_list_hint">Search shortcuts</string>
+ <!-- The description for no shortcuts results [CHAR LIMIT=25] -->
+ <string name="keyboard_shortcut_search_list_no_result">No shortcuts found</string>
+ <!-- The title of system category in shortcut search list. [CHAR LIMIT=15] -->
+ <string name="keyboard_shortcut_search_category_system">System</string>
+ <!-- The title of input category in shortcut search list. [CHAR LIMIT=15] -->
+ <string name="keyboard_shortcut_search_category_input">Input</string>
+ <!-- The title of open apps category in shortcut search list. [CHAR LIMIT=15] -->
+ <string name="keyboard_shortcut_search_category_open_apps">Open apps</string>
+ <!-- The title of current app category in shortcut search list. [CHAR LIMIT=15] -->
+ <string name="keyboard_shortcut_search_category_current_app">Current app</string>
+
+ <!-- User visible title for the keyboard shortcut that triggers the notification shade. [CHAR LIMIT=70] -->
+ <string name="group_system_access_notification_shade">Access notification shade</string>
+ <!-- User visible title for the keyboard shortcut that takes a full screenshot. [CHAR LIMIT=70] -->
+ <string name="group_system_full_screenshot">Take a full screenshot</string>
+ <!-- User visible title for the keyboard shortcut that access list of system / apps shortcuts. [CHAR LIMIT=70] -->
+ <string name="group_system_access_system_app_shortcuts">Access list of system / apps shortcuts</string>
+ <!-- User visible title for the keyboard shortcut that goes back to previous state. [CHAR LIMIT=70] -->
+ <string name="group_system_go_back">Back: go back to previous state (back button)</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the home screen. [CHAR LIMIT=70] -->
+ <string name="group_system_access_home_screen">Access home screen</string>
+ <!-- User visible title for the keyboard shortcut that triggers overview of open apps. [CHAR LIMIT=70] -->
+ <string name="group_system_overview_open_apps">Overview of open apps</string>
+ <!-- User visible title for the keyboard shortcut that cycles through recent apps (forward). [CHAR LIMIT=70] -->
+ <string name="group_system_cycle_forward">Cycle through recent apps (forward)</string>
+ <!-- User visible title for the keyboard shortcut that cycles through recent apps (back). [CHAR LIMIT=70] -->
+ <string name="group_system_cycle_back">Cycle through recent apps (back)</string>
+ <!-- User visible title for the keyboard shortcut that accesses list of all apps and search. [CHAR LIMIT=70] -->
+ <string name="group_system_access_all_apps_search">Access list of all apps and search (i.e. Search/Launcher)</string>
+ <!-- User visible title for the keyboard shortcut that hides and (re)showes taskbar. [CHAR LIMIT=70] -->
+ <string name="group_system_hide_reshow_taskbar">Hide and (re)show taskbar</string>
+ <!-- User visible title for the keyboard shortcut that accesses system settings. [CHAR LIMIT=70] -->
+ <string name="group_system_access_system_settings">Access system settings</string>
+ <!-- User visible title for the keyboard shortcut that accesses Google Assistant. [CHAR LIMIT=70] -->
+ <string name="group_system_access_google_assistant">Access Google Assistant</string>
+ <!-- User visible title for the keyboard shortcut that locks screen. [CHAR LIMIT=70] -->
+ <string name="group_system_lock_screen">Lock screen</string>
+ <!-- User visible title for the keyboard shortcut that pulls up Notes app for quick memo. [CHAR LIMIT=70] -->
+ <string name="group_system_quick_memo">Pull up Notes app for quick memo</string>
+
+ <!-- User visible title for the system multitasking keyboard shortcuts list. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_system_multitasking">System multitasking</string>
+ <!-- User visible title for the keyboard shortcut that enters split screen with current app to RHS [CHAR LIMIT=70] -->
+ <string name="system_multitasking_rhs">Enter Split screen with current app to RHS</string>
+ <!-- User visible title for the keyboard shortcut that enters split screen with current app to LHS [CHAR LIMIT=70] -->
+ <string name="system_multitasking_lhs">Enter Split screen with current app to LHS</string>
+ <!-- User visible title for the keyboard shortcut that switches from split screen to full screen [CHAR LIMIT=70] -->
+ <string name="system_multitasking_full_screen">Switch from Split screen to full screen</string>
+ <!-- User visible title for the keyboard shortcut that replaces an app from one to another during split screen [CHAR LIMIT=70] -->
+ <string name="system_multitasking_replace">During Split screen: replace an app from one to another</string>
+
+ <!-- User visible title for the input keyboard shortcuts list. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_input">Input</string>
+ <!-- User visible title for the keyboard shortcut that switches input language (next language). [CHAR LIMIT=70] -->
+ <string name="input_switch_input_language_next">Switch input language (next language)</string>
+ <!-- User visible title for the keyboard shortcut that switches input language (previous language). [CHAR LIMIT=70] -->
+ <string name="input_switch_input_language_previous">Switch input language (previous language)</string>
+ <!-- User visible title for the keyboard shortcut that accesses emoji. [CHAR LIMIT=70] -->
+ <string name="input_access_emoji">Access emoji</string>
+ <!-- User visible title for the keyboard shortcut that accesses voice typing. [CHAR LIMIT=70] -->
+ <string name="input_access_voice_typing">Access voice typing</string>
+
+ <!-- User visible title for the system-wide applications keyboard shortcuts list. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications">Applications</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the assist app. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the assist app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_assist">Assist</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the browser app. -->
- <string name="keyboard_shortcut_group_applications_browser">Browser</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the browser app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_browser">Browser (Chrome as default)</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the contacts app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_contacts">Contacts</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the email app. -->
- <string name="keyboard_shortcut_group_applications_email">Email</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the SMS messaging app. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the email app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_email">Email (Gmail as default)</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the SMS messaging app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_sms">SMS</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the music app. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the music app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_music">Music</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the YouTube app. -->
- <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. -->
+ <!-- User visible title for the keyboard shortcut that takes the user to the calendar app. [CHAR LIMIT=70] -->
<string name="keyboard_shortcut_group_applications_calendar">Calendar</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the calculator app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_calculator">Calculator</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the maps app. [CHAR LIMIT=70] -->
+ <string name="keyboard_shortcut_group_applications_maps">Maps</string>
<!-- SysUI Tuner: Label for screen about do not disturb settings [CHAR LIMIT=60] -->
<string name="volume_and_do_not_disturb">Do Not Disturb</string>
@@ -2233,6 +2304,14 @@
<!-- Title of the overlay warning the user to interact with the device or it will go to sleep. [CHAR LIMIT=25] -->
<string name="inattentive_sleep_warning_title">Standby</string>
+ <!-- Font scaling -->
+ <!-- Font scaling: Quick Settings dialog title [CHAR LIMIT=30] -->
+ <string name="font_scaling_dialog_title">Font Size</string>
+ <!-- Content Description for the icon button to make fonts smaller. [CHAR LIMIT=30] -->
+ <string name="font_scaling_smaller">Make smaller</string>
+ <!-- Content Description for the icon button to make fonts larger. [CHAR LIMIT=30] -->
+ <string name="font_scaling_larger">Make larger</string>
+
<!-- Window Magnification strings -->
<!-- Title for Magnification Window [CHAR LIMIT=NONE] -->
<string name="magnification_window_title">Magnification Window</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9398c8953a57..2cd217395588 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1375,4 +1375,23 @@
<item name="android:lineHeight">@dimen/magnification_setting_button_line_height</item>
<item name="android:textAlignment">center</item>
</style>
+
+ <style name="ShortCutButton" parent="@android:style/Widget.Material.Button">
+ <item name="android:background">@drawable/shortcut_button_colored</item>
+ <item name="android:stateListAnimator">@null</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:padding">4dp</item>
+ <item name="android:textColor">?androidprv:attr/textColorSecondary</item>
+ </style>
+
+ <style name="ShortcutHorizontalDivider">
+ <item name="android:layout_width">120dp</item>
+ <item name="android:layout_height">1dp</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:background">?android:attr/dividerHorizontal</item>
+ </style>
+
+ <style name="ShortcutItemBackground">
+ <item name="android:background">@color/ksh_key_item_new_background</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
index 30156a0cd6f1..5e71bbecf55c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
@@ -75,7 +75,7 @@ public class SurfaceViewRequestReceiver {
DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
mSurfaceControlViewHost = new SurfaceControlViewHost(context,
dm.getDisplay(SurfaceViewRequestUtils.getDisplayId(bundle)),
- windowlessWindowManager);
+ windowlessWindowManager, "SurfaceViewRequestReceiver");
WindowManager.LayoutParams layoutParams =
new WindowManager.LayoutParams(
viewSize.getWidth(),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index 1051de358f98..61394035d731 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -202,11 +202,8 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
mKeyguardSecurityContainerController.onPause();
}
- /**
- * Reinflate the view flipper child view.
- */
- public void reinflateViewFlipper() {
- mKeyguardSecurityContainerController.reinflateViewFlipper();
+ public void resetSecurityContainer() {
+ mKeyguardSecurityContainerController.reset();
}
/**
@@ -235,19 +232,23 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
/**
* Starts the animation when the Keyguard gets shown.
*/
- public void appear() {
+ public void appear(int statusBarHeight) {
// We might still be collapsed and the view didn't have time to layout yet or still
// be small, let's wait on the predraw to do the animation in that case.
- mView.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- mView.getViewTreeObserver().removeOnPreDrawListener(this);
- mKeyguardSecurityContainerController.startAppearAnimation();
- return true;
- }
- });
- mView.requestLayout();
+ if (mView.getHeight() != 0 && mView.getHeight() != statusBarHeight) {
+ mKeyguardSecurityContainerController.startAppearAnimation();
+ } else {
+ mView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ mView.getViewTreeObserver().removeOnPreDrawListener(this);
+ mKeyguardSecurityContainerController.startAppearAnimation();
+ return true;
+ }
+ });
+ mView.requestLayout();
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 8281c8b4290a..20baa81b5d83 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -744,20 +744,17 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
private void reloadColors() {
- reinflateViewFlipper();
+ resetViewFlipper();
mView.reloadColors();
}
/** Handles density or font scale changes. */
private void onDensityOrFontScaleChanged() {
- reinflateViewFlipper();
+ resetViewFlipper();
mView.onDensityOrFontScaleChanged();
}
- /**
- * Reinflate the view flipper child view.
- */
- public void reinflateViewFlipper() {
+ private void resetViewFlipper() {
mSecurityViewFlipperController.clearViews();
mSecurityViewFlipperController.getSecurityView(mCurrentSecurityMode,
mKeyguardSecurityCallback);
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index 5135eed519a9..b30a0e010e4b 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -51,6 +51,7 @@ class NumPadAnimator {
private float mStartRadius;
private float mEndRadius;
private int mHeight;
+ private boolean mInitialized;
private static final int EXPAND_ANIMATION_MS = 100;
private static final int EXPAND_COLOR_ANIMATION_MS = 50;
@@ -97,6 +98,11 @@ class NumPadAnimator {
mEndRadius = height / 4f;
mExpandAnimator.setFloatValues(mStartRadius, mEndRadius);
mContractAnimator.setFloatValues(mEndRadius, mStartRadius);
+ // Set initial corner radius.
+ if (!mInitialized) {
+ mBackground.setCornerRadius(mStartRadius);
+ mInitialized = true;
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
new file mode 100644
index 000000000000..54f933ae6d09
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.accessibility.fontscaling
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.res.Configuration
+import android.os.Bundle
+import android.provider.Settings
+import android.view.LayoutInflater
+import android.widget.Button
+import android.widget.SeekBar
+import android.widget.SeekBar.OnSeekBarChangeListener
+import android.widget.TextView
+import com.android.systemui.R
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.settings.SystemSettings
+
+/** The Dialog that contains a seekbar for changing the font size. */
+class FontScalingDialog(context: Context, private val systemSettings: SystemSettings) :
+ SystemUIDialog(context) {
+ private val strEntryValues: Array<String> =
+ context.resources.getStringArray(com.android.settingslib.R.array.entryvalues_font_size)
+ private lateinit var title: TextView
+ private lateinit var doneButton: Button
+ private lateinit var seekBarWithIconButtonsView: SeekBarWithIconButtonsView
+
+ private val configuration: Configuration =
+ Configuration(context.getResources().getConfiguration())
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setTitle(R.string.font_scaling_dialog_title)
+ setView(LayoutInflater.from(context).inflate(R.layout.font_scaling_dialog, null))
+ setPositiveButton(
+ R.string.quick_settings_done,
+ /* onClick = */ null,
+ /* dismissOnClick = */ true
+ )
+ super.onCreate(savedInstanceState)
+
+ title = requireViewById(com.android.internal.R.id.alertTitle)
+ doneButton = requireViewById(com.android.internal.R.id.button1)
+ seekBarWithIconButtonsView = requireViewById(R.id.font_scaling_slider)
+
+ seekBarWithIconButtonsView.setMax((strEntryValues).size - 1)
+
+ val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, 1.0f)
+ seekBarWithIconButtonsView.setProgress(fontSizeValueToIndex(currentScale))
+
+ seekBarWithIconButtonsView.setOnSeekBarChangeListener(
+ object : OnSeekBarChangeListener {
+ override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ systemSettings.putString(Settings.System.FONT_SCALE, strEntryValues[progress])
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar) {
+ // Do nothing
+ }
+
+ override fun onStopTrackingTouch(seekBar: SeekBar) {
+ // Do nothing
+ }
+ }
+ )
+ doneButton.setOnClickListener { dismiss() }
+ }
+
+ private fun fontSizeValueToIndex(value: Float): Int {
+ var lastValue = strEntryValues[0].toFloat()
+ for (i in 1 until strEntryValues.size) {
+ val thisValue = strEntryValues[i].toFloat()
+ if (value < lastValue + (thisValue - lastValue) * .5f) {
+ return i - 1
+ }
+ lastValue = thisValue
+ }
+ return strEntryValues.size - 1
+ }
+
+ override fun onConfigurationChanged(configuration: Configuration) {
+ super.onConfigurationChanged(configuration)
+
+ val configDiff = configuration.diff(this.configuration)
+ this.configuration.setTo(configuration)
+
+ if (configDiff and ActivityInfo.CONFIG_FONT_SCALE != 0) {
+ title.post {
+ title.setTextAppearance(R.style.TextAppearance_Dialog_Title)
+ doneButton.setTextAppearance(R.style.Widget_Dialog_Button)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
index ae6a08f84a2a..a2077a3ae96a 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
@@ -22,6 +22,7 @@ import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
@@ -37,6 +38,8 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
private static final int DEFAULT_SEEKBAR_MAX = 6;
private static final int DEFAULT_SEEKBAR_PROGRESS = 0;
+ private ViewGroup mIconStartFrame;
+ private ViewGroup mIconEndFrame;
private ImageView mIconStart;
private ImageView mIconEnd;
private SeekBar mSeekbar;
@@ -62,6 +65,8 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
LayoutInflater.from(context).inflate(
R.layout.seekbar_with_icon_buttons, this, /* attachToRoot= */ true);
+ mIconStartFrame = findViewById(R.id.icon_start_frame);
+ mIconEndFrame = findViewById(R.id.icon_end_frame);
mIconStart = findViewById(R.id.icon_start);
mIconEnd = findViewById(R.id.icon_end);
mSeekbar = findViewById(R.id.seekbar);
@@ -80,24 +85,22 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
mSeekbar.setMax(max);
setProgress(progress);
- int iconStartContentDescriptionId = typedArray.getResourceId(
+ int iconStartFrameContentDescriptionId = typedArray.getResourceId(
R.styleable.SeekBarWithIconButtonsView_Layout_iconStartContentDescription,
/* defValue= */ 0);
- int iconEndContentDescriptionId = typedArray.getResourceId(
+ int iconEndFrameContentDescriptionId = typedArray.getResourceId(
R.styleable.SeekBarWithIconButtonsView_Layout_iconEndContentDescription,
/* defValue= */ 0);
- if (iconStartContentDescriptionId != 0) {
+ if (iconStartFrameContentDescriptionId != 0) {
final String contentDescription =
- context.getString(iconStartContentDescriptionId);
- mIconStart.setContentDescription(contentDescription);
+ context.getString(iconStartFrameContentDescriptionId);
+ mIconStartFrame.setContentDescription(contentDescription);
}
- if (iconEndContentDescriptionId != 0) {
+ if (iconEndFrameContentDescriptionId != 0) {
final String contentDescription =
- context.getString(iconEndContentDescriptionId);
- mIconEnd.setContentDescription(contentDescription);
+ context.getString(iconEndFrameContentDescriptionId);
+ mIconEndFrame.setContentDescription(contentDescription);
}
-
- typedArray.recycle();
} else {
mSeekbar.setMax(DEFAULT_SEEKBAR_MAX);
setProgress(DEFAULT_SEEKBAR_PROGRESS);
@@ -109,7 +112,7 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
final int progress = mSeekbar.getProgress();
if (progress > 0) {
mSeekbar.setProgress(progress - 1);
- setIconViewEnabled(mIconStart, mSeekbar.getProgress() > 0);
+ setIconViewAndFrameEnabled(mIconStart, mSeekbar.getProgress() > 0);
}
});
@@ -117,13 +120,15 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
final int progress = mSeekbar.getProgress();
if (progress < mSeekbar.getMax()) {
mSeekbar.setProgress(progress + 1);
- setIconViewEnabled(mIconEnd, mSeekbar.getProgress() < mSeekbar.getMax());
+ setIconViewAndFrameEnabled(mIconEnd, mSeekbar.getProgress() < mSeekbar.getMax());
}
});
}
- private static void setIconViewEnabled(View iconView, boolean enabled) {
+ private static void setIconViewAndFrameEnabled(View iconView, boolean enabled) {
iconView.setEnabled(enabled);
+ final ViewGroup iconFrame = (ViewGroup) iconView.getParent();
+ iconFrame.setEnabled(enabled);
}
/**
@@ -141,12 +146,22 @@ public class SeekBarWithIconButtonsView extends LinearLayout {
* Icon End will need to be enabled when the seekbar progress is less than Max.
*/
private void updateIconViewIfNeeded(int progress) {
- setIconViewEnabled(mIconStart, progress > 0);
- setIconViewEnabled(mIconEnd, progress < mSeekbar.getMax());
+ setIconViewAndFrameEnabled(mIconStart, progress > 0);
+ setIconViewAndFrameEnabled(mIconEnd, progress < mSeekbar.getMax());
+ }
+
+ /**
+ * Sets max to the seekbar in the layout.
+ */
+ public void setMax(int max) {
+ mSeekbar.setMax(max);
}
/**
* Sets progress to the seekbar in the layout.
+ * If the progress is smaller than or equals to 0, the IconStart will be disabled. If the
+ * progress is larger than or equals to Max, the IconEnd will be disabled. The seekbar progress
+ * will be constrained in {@link SeekBar}.
*/
public void setProgress(int progress) {
mSeekbar.setProgress(progress);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index d0c5007c36eb..fadabb4b8fb3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -47,6 +47,7 @@ import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeControllerImpl;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.KeyboardShortcutsModule;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -100,7 +101,8 @@ import dagger.Provides;
QSModule.class,
ReferenceScreenshotModule.class,
StartCentralSurfacesModule.class,
- VolumeModule.class
+ VolumeModule.class,
+ KeyboardShortcutsModule.class
})
public abstract class ReferenceSystemUIModule {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index cbeff2be9782..cd5f149b2b91 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -70,6 +70,7 @@ import com.android.systemui.smartspace.dagger.SmartspaceModule;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
@@ -266,6 +267,7 @@ public abstract class SystemUIModule {
NotifPipeline notifPipeline,
SysUiState sysUiState,
FeatureFlags featureFlags,
+ NotifPipelineFlags notifPipelineFlags,
@Main Executor sysuiMainExecutor) {
return Optional.ofNullable(BubblesManager.create(context,
bubblesOptional,
@@ -283,6 +285,7 @@ public abstract class SystemUIModule {
notifPipeline,
sysUiState,
featureFlags,
+ notifPipelineFlags,
sysuiMainExecutor));
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index d5634e3b239c..b75b6d852a89 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -514,9 +514,7 @@ object Flags {
@JvmField val SCREENSHOT_APP_CLIPS = releasedFlag(1304, "screenshot_app_clips")
// TODO(b/268484562): Tracking bug
- @JvmField
- val SCREENSHOT_METADATA_REFACTOR =
- unreleasedFlag(1305, "screenshot_metadata_refactor", teamfood = true)
+ @JvmField val SCREENSHOT_METADATA_REFACTOR = releasedFlag(1305, "screenshot_metadata_refactor")
// 1400 - columbus
// TODO(b/254512756): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
index bb0d260f8b7a..9f09d53c99f3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBouncerViewBinder.kt
@@ -22,6 +22,7 @@ import android.view.ViewGroup
import android.window.OnBackAnimationCallback
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.internal.policy.SystemBarUtils
import com.android.keyguard.KeyguardHostViewController
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardUpdateMonitor
@@ -97,14 +98,14 @@ object KeyguardBouncerViewBinder {
viewModel.setBouncerViewDelegate(delegate)
launch {
viewModel.show.collect {
- // Reset Security Container entirely.
- hostViewController.reinflateViewFlipper()
hostViewController.showPromptReason(it.promptReason)
it.errorMessage?.let { errorMessage ->
hostViewController.showErrorMessage(errorMessage)
}
hostViewController.showPrimarySecurityScreen()
- hostViewController.appear()
+ hostViewController.appear(
+ SystemBarUtils.getStatusBarHeight(view.context)
+ )
hostViewController.onResume()
}
}
@@ -113,6 +114,7 @@ object KeyguardBouncerViewBinder {
viewModel.hide.collect {
hostViewController.cancelDismissAction()
hostViewController.cleanUp()
+ hostViewController.resetSecurityContainer()
}
}
@@ -158,6 +160,15 @@ object KeyguardBouncerViewBinder {
}
launch {
+ viewModel.isBouncerVisible
+ .filter { !it }
+ .collect {
+ // Remove existing input for security reasons.
+ hostViewController.resetSecurityContainer()
+ }
+ }
+
+ launch {
viewModel.keyguardPosition.collect { position ->
hostViewController.updateKeyguardPosition(position)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 403576cd1ec0..d977f911187b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -97,6 +97,7 @@ constructor(
context,
displayManager.getDisplay(bundle.getInt(KEY_DISPLAY_ID)),
hostToken,
+ "KeyguardPreviewRenderer"
)
disposables.add(DisposableHandle { host.release() })
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index 4d8f89edd969..b9cd535b9765 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -19,8 +19,12 @@ import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.view.View
+import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.MetricsLogger
import com.android.systemui.R
+import com.android.systemui.accessibility.fontscaling.FontScalingDialog
+import com.android.systemui.animation.DialogCuj
+import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
@@ -30,6 +34,8 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.settings.SystemSettings
import javax.inject.Inject
class FontScalingTile
@@ -42,7 +48,9 @@ constructor(
metricsLogger: MetricsLogger,
statusBarStateController: StatusBarStateController,
activityStarter: ActivityStarter,
- qsLogger: QSLogger
+ qsLogger: QSLogger,
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val systemSettings: SystemSettings
) :
QSTileImpl<QSTile.State?>(
host,
@@ -54,7 +62,7 @@ constructor(
activityStarter,
qsLogger
) {
- private val mIcon = ResourceIcon.get(R.drawable.ic_qs_font_scaling)
+ private val icon = ResourceIcon.get(R.drawable.ic_qs_font_scaling)
override fun isAvailable(): Boolean {
return false
@@ -66,11 +74,24 @@ constructor(
return state
}
- override fun handleClick(view: View?) {}
+ override fun handleClick(view: View?) {
+ mUiHandler.post {
+ val dialog: SystemUIDialog = FontScalingDialog(mContext, systemSettings)
+ if (view != null) {
+ dialogLaunchAnimator.showFromView(
+ dialog,
+ view,
+ DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG)
+ )
+ } else {
+ dialog.show()
+ }
+ }
+ }
override fun handleUpdateState(state: QSTile.State?, arg: Any?) {
state?.label = mContext.getString(R.string.quick_settings_font_scaling_label)
- state?.icon = mIcon
+ state?.icon = icon
}
override fun getLongClickIntent(): Intent? {
@@ -80,4 +101,8 @@ constructor(
override fun getTileLabel(): CharSequence {
return mContext.getString(R.string.quick_settings_font_scaling_label)
}
+
+ companion object {
+ private const val INTERACTION_JANK_TAG = "font_scaling"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
new file mode 100644
index 000000000000..01e042bf5e15
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -0,0 +1,1382 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.view.ContextThemeWrapper;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.WindowManager.KeyboardShortcutsReceiver;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.AssistUtils;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
+import com.google.android.material.bottomsheet.BottomSheetDialog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Contains functionality for handling keyboard shortcuts.
+ */
+public final class KeyboardShortcutListSearch {
+ private static final String TAG = KeyboardShortcutListSearch.class.getSimpleName();
+ private static final Object sLock = new Object();
+ @VisibleForTesting static KeyboardShortcutListSearch sInstance;
+
+ private static int SHORTCUT_SYSTEM_INDEX = 0;
+ private static int SHORTCUT_INPUT_INDEX = 1;
+ private static int SHORTCUT_OPENAPPS_INDEX = 2;
+ private static int SHORTCUT_SPECIFICAPP_INDEX = 3;
+
+ private WindowManager mWindowManager;
+ private EditText mSearchEditText;
+ private String mQueryString;
+ private int mCurrentCategoryIndex = 0;
+ private Map<Integer, Boolean> mKeySearchResultMap = new HashMap<>();
+
+ private List<List<KeyboardShortcutMultiMappingGroup>> mFullShortsGroup = new ArrayList<>();
+ private List<KeyboardShortcutMultiMappingGroup> mSpecificAppGroup = new ArrayList<>();
+ private List<KeyboardShortcutMultiMappingGroup> mSystemGroup = new ArrayList<>();
+ private List<KeyboardShortcutMultiMappingGroup> mInputGroup = new ArrayList<>();
+ private List<KeyboardShortcutMultiMappingGroup> mOpenAppsGroup = new ArrayList<>();
+
+ private ArrayList<Button> mFullButtonList = new ArrayList<>();
+ private Button mButtonSystem;
+ private Button mButtonInput;
+ private Button mButtonOpenApps;
+ private Button mButtonSpecificApp;
+ private ImageView mEditTextCancel;
+ private TextView mNoSearchResults;
+
+ private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
+ private final SparseArray<String> mModifierNames = new SparseArray<>();
+ private final SparseArray<Drawable> mSpecialCharacterDrawables = new SparseArray<>();
+ private final SparseArray<Drawable> mModifierDrawables = new SparseArray<>();
+ // Ordered list of modifiers that are supported. All values in this array must exist in
+ // mModifierNames.
+ private final int[] mModifierList = new int[] {
+ KeyEvent.META_META_ON, KeyEvent.META_CTRL_ON, KeyEvent.META_ALT_ON,
+ KeyEvent.META_SHIFT_ON, KeyEvent.META_SYM_ON, KeyEvent.META_FUNCTION_ON
+ };
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ @VisibleForTesting Context mContext;
+ private final IPackageManager mPackageManager;
+
+ @VisibleForTesting BottomSheetDialog mKeyboardShortcutsBottomSheetDialog;
+ private KeyCharacterMap mKeyCharacterMap;
+ private KeyCharacterMap mBackupKeyCharacterMap;
+
+ @VisibleForTesting
+ KeyboardShortcutListSearch(Context context, WindowManager windowManager) {
+ this.mContext = new ContextThemeWrapper(
+ context, android.R.style.Theme_DeviceDefault_Settings);
+ this.mPackageManager = AppGlobals.getPackageManager();
+ if (windowManager != null) {
+ this.mWindowManager = windowManager;
+ } else {
+ this.mWindowManager = mContext.getSystemService(WindowManager.class);
+ }
+ loadResources(context);
+ createHardcodedShortcuts();
+ }
+
+ private static KeyboardShortcutListSearch getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new KeyboardShortcutListSearch(context, null);
+ }
+ return sInstance;
+ }
+
+ public static void show(Context context, int deviceId) {
+ MetricsLogger.visible(context,
+ MetricsProto.MetricsEvent.KEYBOARD_SHORTCUTS_HELPER);
+ synchronized (sLock) {
+ if (sInstance != null && !sInstance.mContext.equals(context)) {
+ dismiss();
+ }
+ getInstance(context).showKeyboardShortcuts(deviceId);
+ }
+ }
+
+ public static void toggle(Context context, int deviceId) {
+ synchronized (sLock) {
+ if (isShowing()) {
+ dismiss();
+ } else {
+ show(context, deviceId);
+ }
+ }
+ }
+
+ public static void dismiss() {
+ synchronized (sLock) {
+ if (sInstance != null) {
+ MetricsLogger.hidden(sInstance.mContext,
+ MetricsProto.MetricsEvent.KEYBOARD_SHORTCUTS_HELPER);
+ sInstance.dismissKeyboardShortcuts();
+ sInstance = null;
+ }
+ }
+ }
+
+ private static boolean isShowing() {
+ return sInstance != null && sInstance.mKeyboardShortcutsBottomSheetDialog != null
+ && sInstance.mKeyboardShortcutsBottomSheetDialog.isShowing();
+ }
+
+ private void loadResources(Context context) {
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_HOME, context.getString(R.string.keyboard_key_home));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_BACK, context.getString(R.string.keyboard_key_back));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DPAD_UP, context.getString(R.string.keyboard_key_dpad_up));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DPAD_DOWN, context.getString(R.string.keyboard_key_dpad_down));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DPAD_LEFT, context.getString(R.string.keyboard_key_dpad_left));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DPAD_RIGHT, context.getString(R.string.keyboard_key_dpad_right));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DPAD_CENTER, context.getString(R.string.keyboard_key_dpad_center));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_PERIOD, ".");
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_TAB, context.getString(R.string.keyboard_key_tab));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_SPACE, context.getString(R.string.keyboard_key_space));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_ENTER, context.getString(R.string.keyboard_key_enter));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_DEL, context.getString(R.string.keyboard_key_backspace));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
+ context.getString(R.string.keyboard_key_media_play_pause));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_MEDIA_STOP, context.getString(R.string.keyboard_key_media_stop));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_MEDIA_NEXT, context.getString(R.string.keyboard_key_media_next));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS,
+ context.getString(R.string.keyboard_key_media_previous));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_REWIND,
+ context.getString(R.string.keyboard_key_media_rewind));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD,
+ context.getString(R.string.keyboard_key_media_fast_forward));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_PAGE_UP, context.getString(R.string.keyboard_key_page_up));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_PAGE_DOWN, context.getString(R.string.keyboard_key_page_down));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_A,
+ context.getString(R.string.keyboard_key_button_template, "A"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_B,
+ context.getString(R.string.keyboard_key_button_template, "B"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_C,
+ context.getString(R.string.keyboard_key_button_template, "C"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_X,
+ context.getString(R.string.keyboard_key_button_template, "X"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_Y,
+ context.getString(R.string.keyboard_key_button_template, "Y"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_Z,
+ context.getString(R.string.keyboard_key_button_template, "Z"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_L1,
+ context.getString(R.string.keyboard_key_button_template, "L1"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_R1,
+ context.getString(R.string.keyboard_key_button_template, "R1"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_L2,
+ context.getString(R.string.keyboard_key_button_template, "L2"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_R2,
+ context.getString(R.string.keyboard_key_button_template, "R2"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_START,
+ context.getString(R.string.keyboard_key_button_template, "Start"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_SELECT,
+ context.getString(R.string.keyboard_key_button_template, "Select"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BUTTON_MODE,
+ context.getString(R.string.keyboard_key_button_template, "Mode"));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_FORWARD_DEL, context.getString(R.string.keyboard_key_forward_del));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_ESCAPE, "Esc");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_SYSRQ, "SysRq");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_BREAK, "Break");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_SCROLL_LOCK, "Scroll Lock");
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_MOVE_HOME, context.getString(R.string.keyboard_key_move_home));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_MOVE_END, context.getString(R.string.keyboard_key_move_end));
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_INSERT, context.getString(R.string.keyboard_key_insert));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F1, "F1");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F2, "F2");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F3, "F3");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F4, "F4");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F5, "F5");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F6, "F6");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F7, "F7");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F8, "F8");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F9, "F9");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F10, "F10");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F11, "F11");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_F12, "F12");
+ mSpecialCharacterNames.put(
+ KeyEvent.KEYCODE_NUM_LOCK, context.getString(R.string.keyboard_key_num_lock));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MINUS, "-");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_GRAVE, "~");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_EQUALS, "=");
+
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_0,
+ context.getString(R.string.keyboard_key_numpad_template, "0"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_1,
+ context.getString(R.string.keyboard_key_numpad_template, "1"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_2,
+ context.getString(R.string.keyboard_key_numpad_template, "2"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_3,
+ context.getString(R.string.keyboard_key_numpad_template, "3"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_4,
+ context.getString(R.string.keyboard_key_numpad_template, "4"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_5,
+ context.getString(R.string.keyboard_key_numpad_template, "5"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_6,
+ context.getString(R.string.keyboard_key_numpad_template, "6"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_7,
+ context.getString(R.string.keyboard_key_numpad_template, "7"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_8,
+ context.getString(R.string.keyboard_key_numpad_template, "8"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_9,
+ context.getString(R.string.keyboard_key_numpad_template, "9"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_DIVIDE,
+ context.getString(R.string.keyboard_key_numpad_template, "/"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_MULTIPLY,
+ context.getString(R.string.keyboard_key_numpad_template, "*"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_SUBTRACT,
+ context.getString(R.string.keyboard_key_numpad_template, "-"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_ADD,
+ context.getString(R.string.keyboard_key_numpad_template, "+"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_DOT,
+ context.getString(R.string.keyboard_key_numpad_template, "."));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_COMMA,
+ context.getString(R.string.keyboard_key_numpad_template, ","));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_ENTER,
+ context.getString(R.string.keyboard_key_numpad_template,
+ context.getString(R.string.keyboard_key_enter)));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_EQUALS,
+ context.getString(R.string.keyboard_key_numpad_template, "="));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_LEFT_PAREN,
+ context.getString(R.string.keyboard_key_numpad_template, "("));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_NUMPAD_RIGHT_PAREN,
+ context.getString(R.string.keyboard_key_numpad_template, ")"));
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_ZENKAKU_HANKAKU, "半角/全角");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_EISU, "英数");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_MUHENKAN, "無変換");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_HENKAN, "変換");
+ mSpecialCharacterNames.put(KeyEvent.KEYCODE_KATAKANA_HIRAGANA, "かな");
+
+ mModifierNames.put(KeyEvent.META_META_ON, "Meta");
+ mModifierNames.put(KeyEvent.META_CTRL_ON, "Ctrl");
+ mModifierNames.put(KeyEvent.META_ALT_ON, "Alt");
+ mModifierNames.put(KeyEvent.META_SHIFT_ON, "Shift");
+ mModifierNames.put(KeyEvent.META_SYM_ON, "Sym");
+ mModifierNames.put(KeyEvent.META_FUNCTION_ON, "Fn");
+
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_DEL, context.getDrawable(R.drawable.ic_ksh_key_backspace));
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_ENTER, context.getDrawable(R.drawable.ic_ksh_key_enter));
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_DPAD_UP, context.getDrawable(R.drawable.ic_ksh_key_up));
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_DPAD_RIGHT, context.getDrawable(R.drawable.ic_ksh_key_right));
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_DPAD_DOWN, context.getDrawable(R.drawable.ic_ksh_key_down));
+ mSpecialCharacterDrawables.put(
+ KeyEvent.KEYCODE_DPAD_LEFT, context.getDrawable(R.drawable.ic_ksh_key_left));
+
+ mModifierDrawables.put(
+ KeyEvent.META_META_ON, context.getDrawable(R.drawable.ic_ksh_key_meta));
+ }
+
+ private void createHardcodedShortcuts() {
+ // Add system shortcuts
+ mKeySearchResultMap.put(SHORTCUT_SYSTEM_INDEX, true);
+ mSystemGroup.add(getMultiMappingSystemShortcuts(mContext));
+ mSystemGroup.add(getSystemMultitaskingShortcuts(mContext));
+ // Add input shortcuts
+ mKeySearchResultMap.put(SHORTCUT_INPUT_INDEX, true);
+ mInputGroup.add(getMultiMappingInputShortcuts(mContext));
+ // Add open apps shortcuts
+ final List<KeyboardShortcutMultiMappingGroup> appShortcuts =
+ Arrays.asList(getDefaultMultiMappingApplicationShortcuts());
+ if (appShortcuts != null && !appShortcuts.isEmpty()) {
+ mOpenAppsGroup = appShortcuts;
+ mKeySearchResultMap.put(SHORTCUT_OPENAPPS_INDEX, true);
+ } else {
+ mKeySearchResultMap.put(SHORTCUT_OPENAPPS_INDEX, false);
+ }
+ }
+
+ /**
+ * Retrieves a {@link KeyCharacterMap} and assigns it to mKeyCharacterMap. If the given id is an
+ * existing device, that device's map is used. Otherwise, it checks first all available devices
+ * and if there is a full keyboard it uses that map, otherwise falls back to the Virtual
+ * Keyboard with its default map.
+ */
+ private void retrieveKeyCharacterMap(int deviceId) {
+ final InputManager inputManager = InputManager.getInstance();
+ mBackupKeyCharacterMap = inputManager.getInputDevice(-1).getKeyCharacterMap();
+ if (deviceId != -1) {
+ final InputDevice inputDevice = inputManager.getInputDevice(deviceId);
+ if (inputDevice != null) {
+ mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+ return;
+ }
+ }
+ final int[] deviceIds = inputManager.getInputDeviceIds();
+ for (int id : deviceIds) {
+ final InputDevice inputDevice = inputManager.getInputDevice(id);
+ // -1 is the Virtual Keyboard, with the default key map. Use that one only as last
+ // resort.
+ if (inputDevice.getId() != -1 && inputDevice.isFullKeyboard()) {
+ mKeyCharacterMap = inputDevice.getKeyCharacterMap();
+ return;
+ }
+ }
+ // Fall back to -1, the virtual keyboard.
+ mKeyCharacterMap = mBackupKeyCharacterMap;
+ }
+
+ @VisibleForTesting
+ void showKeyboardShortcuts(int deviceId) {
+ retrieveKeyCharacterMap(deviceId);
+ mWindowManager.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() {
+ @Override
+ public void onKeyboardShortcutsReceived(
+ final List<KeyboardShortcutGroup> result) {
+ // Add specific app shortcuts
+ if (result.isEmpty()) {
+ mKeySearchResultMap.put(SHORTCUT_SPECIFICAPP_INDEX, false);
+ } else {
+ mSpecificAppGroup = reMapToKeyboardShortcutMultiMappingGroup(result);
+ mKeySearchResultMap.put(SHORTCUT_SPECIFICAPP_INDEX, true);
+ }
+ mFullShortsGroup.add(SHORTCUT_SYSTEM_INDEX, mSystemGroup);
+ mFullShortsGroup.add(SHORTCUT_INPUT_INDEX, mInputGroup);
+ mFullShortsGroup.add(SHORTCUT_OPENAPPS_INDEX, mOpenAppsGroup);
+ mFullShortsGroup.add(SHORTCUT_SPECIFICAPP_INDEX, mSpecificAppGroup);
+ showKeyboardShortcutSearchList(mFullShortsGroup);
+ }
+ }, deviceId);
+ }
+
+ // The original data structure is only for 1-to-1 shortcut mapping, so remap the old
+ // data structure to the new data structure for handling the N-to-1 key mapping and other
+ // complex case.
+ private List<KeyboardShortcutMultiMappingGroup> reMapToKeyboardShortcutMultiMappingGroup(
+ List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+ List<KeyboardShortcutMultiMappingGroup> keyboardShortcutMultiMappingGroups =
+ new ArrayList<>();
+ for (KeyboardShortcutGroup group : keyboardShortcutGroups) {
+ CharSequence categoryTitle = group.getLabel();
+ List<ShortcutMultiMappingInfo> shortcutMultiMappingInfos = new ArrayList<>();
+ for (KeyboardShortcutInfo info : group.getItems()) {
+ shortcutMultiMappingInfos.add(new ShortcutMultiMappingInfo(info));
+ }
+ keyboardShortcutMultiMappingGroups.add(
+ new KeyboardShortcutMultiMappingGroup(
+ categoryTitle, shortcutMultiMappingInfos));
+ }
+ return keyboardShortcutMultiMappingGroups;
+ }
+
+ private void dismissKeyboardShortcuts() {
+ if (mKeyboardShortcutsBottomSheetDialog != null) {
+ mKeyboardShortcutsBottomSheetDialog.dismiss();
+ mKeyboardShortcutsBottomSheetDialog = null;
+ }
+ }
+
+ private KeyboardShortcutMultiMappingGroup getMultiMappingSystemShortcuts(Context context) {
+ KeyboardShortcutMultiMappingGroup systemGroup =
+ new KeyboardShortcutMultiMappingGroup(
+ context.getString(R.string.keyboard_shortcut_group_system),
+ new ArrayList<>());
+ List<ShortcutKeyGroupMultiMappingInfo> infoList = Arrays.asList(
+ /* Access notification shade: Meta + N */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_notification_shade),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_N, KeyEvent.META_META_ON))),
+ /* Take a full screenshot: Meta + Ctrl + S */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_full_screenshot),
+ Arrays.asList(
+ Pair.create(
+ KeyEvent.KEYCODE_S,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON))),
+ /* Access list of system / apps shortcuts: Meta + / */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_system_app_shortcuts),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_SLASH, KeyEvent.META_META_ON))),
+ /* Back: go back to previous state (back button) */
+ /* Meta + ~, Meta + backspace, Meta + left arrow */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_go_back),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_GRAVE, KeyEvent.META_META_ON),
+ Pair.create(KeyEvent.KEYCODE_DEL, KeyEvent.META_META_ON),
+ Pair.create(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.META_META_ON))),
+ /* Access home screen: Meta + H, Meta + Enter */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_home_screen),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_H, KeyEvent.META_META_ON),
+ Pair.create(KeyEvent.KEYCODE_ENTER, KeyEvent.META_META_ON))),
+ /* Overview of open apps: Meta + Tab */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_overview_open_apps),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_TAB, KeyEvent.META_META_ON))),
+ /* Cycle through recent apps (forward): Alt + Tab */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_cycle_forward),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON))),
+ /* Cycle through recent apps (back): Shift + Alt + Tab */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_cycle_back),
+ Arrays.asList(
+ Pair.create(
+ KeyEvent.KEYCODE_TAB,
+ KeyEvent.META_SHIFT_ON | KeyEvent.META_ALT_ON))),
+ /* Access list of all apps and search (i.e. Search/Launcher): Meta */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_all_apps_search),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_UNKNOWN, KeyEvent.META_META_ON))),
+ /* Hide and (re)show taskbar: Meta + T */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_hide_reshow_taskbar),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_T, KeyEvent.META_META_ON))),
+ /* Access system settings: Meta + I */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_system_settings),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_I, KeyEvent.META_META_ON))),
+ /* Access Google Assistant: Meta + A */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_access_google_assistant),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_A, KeyEvent.META_META_ON))),
+ /* Lock screen: Meta + L */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_lock_screen),
+ Arrays.asList(
+ Pair.create(KeyEvent.KEYCODE_L, KeyEvent.META_META_ON))),
+ /* Pull up Notes app for quick memo: Meta + Ctrl + N */
+ new ShortcutKeyGroupMultiMappingInfo(
+ context.getString(R.string.group_system_quick_memo),
+ Arrays.asList(
+ Pair.create(
+ KeyEvent.KEYCODE_N,
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON)))
+ );
+ for (ShortcutKeyGroupMultiMappingInfo info : infoList) {
+ systemGroup.addItem(info.getShortcutMultiMappingInfo());
+ }
+ return systemGroup;
+ }
+
+ private static class ShortcutKeyGroupMultiMappingInfo {
+ private String mLabel;
+ private List<Pair<Integer, Integer>> mKeycodeGroupList;
+
+ ShortcutKeyGroupMultiMappingInfo(
+ String label, List<Pair<Integer, Integer>> keycodeGroupList) {
+ mLabel = label;
+ mKeycodeGroupList = keycodeGroupList;
+ }
+
+ ShortcutMultiMappingInfo getShortcutMultiMappingInfo() {
+ List<ShortcutKeyGroup> shortcutKeyGroups = new ArrayList<>();
+ for (Pair<Integer, Integer> keycodeGroup : mKeycodeGroupList) {
+ shortcutKeyGroups.add(new ShortcutKeyGroup(
+ new KeyboardShortcutInfo(
+ mLabel,
+ keycodeGroup.first /* keycode */,
+ keycodeGroup.second /* modifiers*/),
+ null));
+ }
+ ShortcutMultiMappingInfo shortcutMultiMappingInfo =
+ new ShortcutMultiMappingInfo(mLabel, null, shortcutKeyGroups);
+ return shortcutMultiMappingInfo;
+ }
+ }
+
+ private static KeyboardShortcutMultiMappingGroup getSystemMultitaskingShortcuts(
+ Context context) {
+ KeyboardShortcutMultiMappingGroup systemMultitaskingGroup =
+ new KeyboardShortcutMultiMappingGroup(
+ context.getString(R.string.keyboard_shortcut_group_system_multitasking),
+ new ArrayList<>());
+
+ // System multitasking shortcuts:
+ // Enter Split screen with current app to RHS: Meta + Ctrl + Right arrow
+ // Enter Split screen with current app to LHS: Meta + Ctrl + Left arrow
+ // Switch from Split screen to full screen: Meta + Ctrl + Up arrow
+ // During Split screen: replace an app from one to another: Meta + Ctrl + Down arrow
+ String[] shortcutLabels = {
+ context.getString(R.string.system_multitasking_rhs),
+ context.getString(R.string.system_multitasking_lhs),
+ context.getString(R.string.system_multitasking_full_screen),
+ context.getString(R.string.system_multitasking_replace)
+ };
+ int[] keyCodes = {
+ KeyEvent.KEYCODE_DPAD_RIGHT,
+ KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.KEYCODE_DPAD_UP,
+ KeyEvent.KEYCODE_DPAD_DOWN
+ };
+
+ for (int i = 0; i < shortcutLabels.length; i++) {
+ List<ShortcutKeyGroup> shortcutKeyGroups = Arrays.asList(new ShortcutKeyGroup(
+ new KeyboardShortcutInfo(
+ shortcutLabels[i],
+ keyCodes[i],
+ KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON),
+ null));
+ ShortcutMultiMappingInfo shortcutMultiMappingInfo =
+ new ShortcutMultiMappingInfo(
+ shortcutLabels[i],
+ null,
+ shortcutKeyGroups);
+ systemMultitaskingGroup.addItem(shortcutMultiMappingInfo);
+ }
+ return systemMultitaskingGroup;
+ }
+
+ private static KeyboardShortcutMultiMappingGroup getMultiMappingInputShortcuts(
+ Context context) {
+ List<ShortcutMultiMappingInfo> shortcutMultiMappingInfoList = Arrays.asList(
+ /* Switch input language (next language): Ctrl + Space or Meta + Space */
+ new ShortcutMultiMappingInfo(
+ context.getString(R.string.input_switch_input_language_next),
+ null,
+ Arrays.asList(
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(
+ R.string.input_switch_input_language_next),
+ KeyEvent.KEYCODE_SPACE, KeyEvent.META_CTRL_ON),
+ null),
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(
+ R.string.input_switch_input_language_next),
+ KeyEvent.KEYCODE_SPACE, KeyEvent.META_META_ON),
+ null))),
+ /* Switch input language (previous language): */
+ /* Ctrl + Shift + Space or Meta + Shift + Space */
+ new ShortcutMultiMappingInfo(
+ context.getString(R.string.input_switch_input_language_previous),
+ null,
+ Arrays.asList(
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(
+ R.string.input_switch_input_language_previous),
+ KeyEvent.KEYCODE_SPACE,
+ KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON),
+ null),
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(
+ R.string.input_switch_input_language_previous),
+ KeyEvent.KEYCODE_SPACE,
+ KeyEvent.META_META_ON | KeyEvent.META_SHIFT_ON),
+ null))),
+ /* Access emoji: Meta + . */
+ new ShortcutMultiMappingInfo(
+ context.getString(R.string.input_access_emoji),
+ null,
+ Arrays.asList(
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(R.string.input_access_emoji),
+ KeyEvent.KEYCODE_PERIOD,
+ KeyEvent.META_META_ON),
+ null))),
+ /* Access voice typing: Meta + V */
+ new ShortcutMultiMappingInfo(
+ context.getString(R.string.input_access_voice_typing),
+ null,
+ Arrays.asList(
+ new ShortcutKeyGroup(new KeyboardShortcutInfo(
+ context.getString(R.string.input_access_voice_typing),
+ KeyEvent.KEYCODE_V, KeyEvent.META_META_ON),
+ null)))
+ );
+ return new KeyboardShortcutMultiMappingGroup(
+ context.getString(R.string.keyboard_shortcut_group_input),
+ shortcutMultiMappingInfoList);
+ }
+
+ private KeyboardShortcutMultiMappingGroup getDefaultMultiMappingApplicationShortcuts() {
+ final int userId = mContext.getUserId();
+ PackageInfo assistPackageInfo = getAssistPackageInfo(mContext, mPackageManager, userId);
+ CharSequence categoryTitle =
+ mContext.getString(R.string.keyboard_shortcut_group_applications);
+ List<ShortcutMultiMappingInfo> shortcutMultiMappingInfos = new ArrayList<>();
+
+ String[] intentCategories = {
+ Intent.CATEGORY_APP_BROWSER,
+ Intent.CATEGORY_APP_CONTACTS,
+ Intent.CATEGORY_APP_EMAIL,
+ Intent.CATEGORY_APP_CALENDAR,
+ Intent.CATEGORY_APP_MAPS,
+ Intent.CATEGORY_APP_MUSIC,
+ Intent.CATEGORY_APP_MESSAGING,
+ Intent.CATEGORY_APP_CALCULATOR,
+
+ };
+ String[] shortcutLabels = {
+ mContext.getString(R.string.keyboard_shortcut_group_applications_browser),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_contacts),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_email),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_calendar),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_maps),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_music),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_sms),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_calculator)
+ };
+ int[] keyCodes = {
+ KeyEvent.KEYCODE_B,
+ KeyEvent.KEYCODE_C,
+ KeyEvent.KEYCODE_E,
+ KeyEvent.KEYCODE_K,
+ KeyEvent.KEYCODE_M,
+ KeyEvent.KEYCODE_P,
+ KeyEvent.KEYCODE_S,
+ KeyEvent.KEYCODE_U,
+ };
+
+ // Assist.
+ if (assistPackageInfo != null) {
+ if (assistPackageInfo != null) {
+ final Icon assistIcon = Icon.createWithResource(
+ assistPackageInfo.applicationInfo.packageName,
+ assistPackageInfo.applicationInfo.icon);
+ CharSequence assistLabel =
+ mContext.getString(R.string.keyboard_shortcut_group_applications_assist);
+ KeyboardShortcutInfo assistShortcutInfo = new KeyboardShortcutInfo(
+ assistLabel,
+ assistIcon,
+ KeyEvent.KEYCODE_A,
+ KeyEvent.META_META_ON);
+ shortcutMultiMappingInfos.add(
+ new ShortcutMultiMappingInfo(
+ assistLabel,
+ assistIcon,
+ Arrays.asList(new ShortcutKeyGroup(assistShortcutInfo, null))));
+ }
+ }
+
+ // Browser (Chrome as default): Meta + B
+ // Contacts: Meta + C
+ // Email (Gmail as default): Meta + E
+ // Gmail: Meta + G
+ // Calendar: Meta + K
+ // Maps: Meta + M
+ // Music: Meta + P
+ // SMS: Meta + S
+ // Calculator: Meta + U
+ for (int i = 0; i < shortcutLabels.length; i++) {
+ final Icon icon = getIconForIntentCategory(intentCategories[i], userId);
+ if (icon != null) {
+ CharSequence label =
+ shortcutLabels[i];
+ KeyboardShortcutInfo keyboardShortcutInfo = new KeyboardShortcutInfo(
+ label,
+ icon,
+ keyCodes[i],
+ KeyEvent.META_META_ON);
+ List<ShortcutKeyGroup> shortcutKeyGroups =
+ Arrays.asList(new ShortcutKeyGroup(keyboardShortcutInfo, null));
+ shortcutMultiMappingInfos.add(
+ new ShortcutMultiMappingInfo(label, icon, shortcutKeyGroups));
+ }
+ }
+
+ Comparator<ShortcutMultiMappingInfo> applicationItemsComparator =
+ new Comparator<ShortcutMultiMappingInfo>() {
+ @Override
+ public int compare(
+ ShortcutMultiMappingInfo ksh1, ShortcutMultiMappingInfo ksh2) {
+ boolean ksh1ShouldBeLast = ksh1.getLabel() == null
+ || ksh1.getLabel().toString().isEmpty();
+ boolean ksh2ShouldBeLast = ksh2.getLabel() == null
+ || ksh2.getLabel().toString().isEmpty();
+ if (ksh1ShouldBeLast && ksh2ShouldBeLast) {
+ return 0;
+ }
+ if (ksh1ShouldBeLast) {
+ return 1;
+ }
+ if (ksh2ShouldBeLast) {
+ return -1;
+ }
+ return (ksh1.getLabel().toString()).compareToIgnoreCase(
+ ksh2.getLabel().toString());
+ }
+ };
+ // Sorts by label, case insensitive with nulls and/or empty labels last.
+ Collections.sort(shortcutMultiMappingInfos, applicationItemsComparator);
+ return new KeyboardShortcutMultiMappingGroup(categoryTitle, shortcutMultiMappingInfos);
+ }
+
+ private Icon getIconForIntentCategory(String intentCategory, int userId) {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(intentCategory);
+
+ final PackageInfo packageInfo = getPackageInfoForIntent(intent, userId);
+ if (packageInfo != null && packageInfo.applicationInfo.icon != 0) {
+ return Icon.createWithResource(
+ packageInfo.applicationInfo.packageName,
+ packageInfo.applicationInfo.icon);
+ }
+ return null;
+ }
+
+ private PackageInfo getPackageInfoForIntent(Intent intent, int userId) {
+ try {
+ ResolveInfo handler;
+ handler = mPackageManager.resolveIntent(
+ intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), 0, userId);
+ if (handler == null || handler.activityInfo == null) {
+ return null;
+ }
+ return mPackageManager.getPackageInfo(handler.activityInfo.packageName, 0, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "PackageManagerService is dead", e);
+ return null;
+ }
+ }
+
+ private void showKeyboardShortcutSearchList(
+ List<List<KeyboardShortcutMultiMappingGroup>> keyboardShortcutMultiMappingGroupList) {
+ // Need to post on the main thread.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ handleShowKeyboardShortcutSearchList(keyboardShortcutMultiMappingGroupList);
+ }
+ });
+ }
+
+ private void handleShowKeyboardShortcutSearchList(
+ List<List<KeyboardShortcutMultiMappingGroup>> keyboardShortcutMultiMappingGroupList) {
+ mQueryString = null;
+ LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+ mKeyboardShortcutsBottomSheetDialog =
+ new BottomSheetDialog(mContext);
+ final View keyboardShortcutsView = inflater.inflate(
+ R.layout.keyboard_shortcuts_search_view, null);
+ mNoSearchResults = keyboardShortcutsView.findViewById(R.id.shortcut_search_no_result);
+ mKeyboardShortcutsBottomSheetDialog.setContentView(keyboardShortcutsView);
+ setButtonsDefaultStatus(keyboardShortcutsView);
+ populateKeyboardShortcutSearchList(
+ keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_container));
+
+ // Workaround for solve issue about dialog not full expanded when landscape.
+ FrameLayout bottomSheet = (FrameLayout)
+ mKeyboardShortcutsBottomSheetDialog.findViewById(
+ com.google.android.material.R.id.design_bottom_sheet);
+ if (bottomSheet != null) {
+ bottomSheet.setBackgroundResource(android.R.color.transparent);
+ }
+
+ BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
+ behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
+ behavior.setSkipCollapsed(true);
+
+ mKeyboardShortcutsBottomSheetDialog.setCanceledOnTouchOutside(true);
+ Window keyboardShortcutsWindow = mKeyboardShortcutsBottomSheetDialog.getWindow();
+ keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
+ synchronized (sLock) {
+ // show KeyboardShortcutsBottomSheetDialog only if it has not been dismissed already
+ if (sInstance != null) {
+ mKeyboardShortcutsBottomSheetDialog.show();
+ setDialogScreenSize();
+ keyboardShortcutsView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right,
+ int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ setDialogScreenSize();
+ }
+ });
+ }
+ }
+ mSearchEditText = keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_search);
+ mSearchEditText.addTextChangedListener(
+ new TextWatcher() {
+ @Override
+ public void afterTextChanged(Editable s) {
+ mQueryString = s.toString();
+ populateKeyboardShortcutSearchList(
+ keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container));
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ // Do nothing.
+ }
+ });
+ mEditTextCancel = keyboardShortcutsView.findViewById(R.id.keyboard_shortcuts_search_cancel);
+ mEditTextCancel.setOnClickListener(v -> mSearchEditText.setText(null));
+ }
+
+ private void populateKeyboardShortcutSearchList(LinearLayout keyboardShortcutsLayout) {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ TextView shortcutsKeyView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_view, keyboardShortcutsLayout, false);
+ shortcutsKeyView.measure(
+ View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ final int shortcutKeyTextItemMinWidth = shortcutsKeyView.getMeasuredHeight();
+ // Needed to be able to scale the image items to the same height as the text items.
+ final int shortcutKeyIconItemHeightWidth = shortcutsKeyView.getMeasuredHeight()
+ - shortcutsKeyView.getPaddingTop()
+ - shortcutsKeyView.getPaddingBottom();
+ keyboardShortcutsLayout.removeAllViews();
+
+ // Search if user's input is contained in any shortcut groups.
+ if (mQueryString != null) {
+ for (int i = 0; i < mFullShortsGroup.size(); i++) {
+ mKeySearchResultMap.put(i, false);
+ for (KeyboardShortcutMultiMappingGroup group : mFullShortsGroup.get(i)) {
+ for (ShortcutMultiMappingInfo info : group.getItems()) {
+ String itemLabel = info.getLabel().toString();
+ if (itemLabel.toUpperCase(Locale.getDefault()).contains(
+ mQueryString.toUpperCase(Locale.getDefault()))) {
+ mKeySearchResultMap.put(i, true);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Set default color for the non-focus categories.
+ for (int i = 0; i < mKeySearchResultMap.size(); i++) {
+ if (mKeySearchResultMap.get(i)) {
+ mFullButtonList.get(i).setVisibility(View.VISIBLE);
+ setButtonFocusColor(i, false);
+ } else {
+ mFullButtonList.get(i).setVisibility(View.GONE);
+ }
+ }
+
+ // Move the focus to the suitable category.
+ if (mFullButtonList.get(mCurrentCategoryIndex).getVisibility() == View.GONE) {
+ for (int i = 0; i < mKeySearchResultMap.size(); i++) {
+ if (mKeySearchResultMap.get(i)) {
+ setCurrentCategoryIndex(i);
+ break;
+ }
+ }
+ }
+
+ // Set color for the current focus category
+ setButtonFocusColor(mCurrentCategoryIndex, true);
+
+ // Load shortcuts for current focus category.
+ List<KeyboardShortcutMultiMappingGroup> keyboardShortcutMultiMappingGroups =
+ mFullShortsGroup.get(mCurrentCategoryIndex);
+
+ int keyboardShortcutGroupsSize = keyboardShortcutMultiMappingGroups.size();
+ List<Boolean> groupSearchResult = new ArrayList<>();
+ for (int i = 0; i < keyboardShortcutGroupsSize; i++) {
+ View separator = inflater.inflate(
+ R.layout.keyboard_shortcuts_category_short_separator,
+ keyboardShortcutsLayout,
+ false);
+
+ // If there are more than one category, add separators among categories.
+ if (i > 0) {
+ keyboardShortcutsLayout.addView(separator);
+ }
+
+ List<Boolean> itemSearchResult = new ArrayList<>();
+ KeyboardShortcutMultiMappingGroup categoryGroup =
+ keyboardShortcutMultiMappingGroups.get(i);
+ TextView categoryTitle = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_category_title, keyboardShortcutsLayout, false);
+ categoryTitle.setText(categoryGroup.getCategory());
+ keyboardShortcutsLayout.addView(categoryTitle);
+ LinearLayout shortcutContainer = (LinearLayout) inflater.inflate(
+ R.layout.keyboard_shortcuts_container, keyboardShortcutsLayout, false);
+ final int itemsSize = categoryGroup.getItems().size();
+ for (int j = 0; j < itemsSize; j++) {
+ ShortcutMultiMappingInfo keyGroupInfo = categoryGroup.getItems().get(j);
+
+ if (mQueryString != null) {
+ String shortcutLabel =
+ keyGroupInfo.getLabel().toString().toUpperCase(Locale.getDefault());
+ String queryString = mQueryString.toUpperCase(Locale.getDefault());
+ if (!shortcutLabel.contains(queryString)) {
+ itemSearchResult.add(j, false);
+ continue;
+ } else {
+ itemSearchResult.add(j, true);
+ }
+ }
+
+ View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item,
+ shortcutContainer, false);
+ TextView shortcutKeyword =
+ shortcutView.findViewById(R.id.keyboard_shortcuts_keyword);
+ shortcutKeyword.setText(keyGroupInfo.getLabel());
+
+ if (keyGroupInfo.getIcon() != null) {
+ ImageView shortcutIcon =
+ shortcutView.findViewById(R.id.keyboard_shortcuts_icon);
+ shortcutIcon.setImageIcon(keyGroupInfo.getIcon());
+ shortcutIcon.setVisibility(View.VISIBLE);
+ RelativeLayout.LayoutParams lp =
+ (RelativeLayout.LayoutParams) shortcutKeyword.getLayoutParams();
+ lp.removeRule(RelativeLayout.ALIGN_PARENT_START);
+ shortcutKeyword.setLayoutParams(lp);
+ }
+
+ ViewGroup shortcutItemsContainer =
+ shortcutView.findViewById(R.id.keyboard_shortcuts_item_container);
+ final int keyGroupItemsSize = keyGroupInfo.getShortcutKeyGroups().size();
+ for (int p = 0; p < keyGroupItemsSize; p++) {
+ KeyboardShortcutInfo keyboardShortcutInfo =
+ keyGroupInfo.getShortcutKeyGroups().get(p).getKeyboardShortcutInfo();
+ String complexCommand =
+ keyGroupInfo.getShortcutKeyGroups().get(p).getComplexCommand();
+
+ if (complexCommand == null) {
+ List<StringDrawableContainer> shortcutKeys =
+ getHumanReadableShortcutKeys(keyboardShortcutInfo);
+ if (shortcutKeys == null) {
+ // Ignore shortcuts we can't display keys for.
+ Log.w(TAG, "Keyboard Shortcut contains unsupported keys, skipping.");
+ continue;
+ }
+ final int shortcutKeysSize = shortcutKeys.size();
+ for (int k = 0; k < shortcutKeysSize; k++) {
+ StringDrawableContainer shortcutRepresentation = shortcutKeys.get(k);
+ if (shortcutRepresentation.mDrawable != null) {
+ ImageView shortcutKeyIconView = (ImageView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_new_icon_view,
+ shortcutItemsContainer,
+ false);
+ Bitmap bitmap = Bitmap.createBitmap(shortcutKeyIconItemHeightWidth,
+ shortcutKeyIconItemHeightWidth, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ shortcutRepresentation.mDrawable.setBounds(0, 0, canvas.getWidth(),
+ canvas.getHeight());
+ shortcutRepresentation.mDrawable.draw(canvas);
+ shortcutKeyIconView.setImageBitmap(bitmap);
+ shortcutKeyIconView.setImportantForAccessibility(
+ IMPORTANT_FOR_ACCESSIBILITY_YES);
+ shortcutKeyIconView.setAccessibilityDelegate(
+ new ShortcutKeyAccessibilityDelegate(
+ shortcutRepresentation.mString));
+ shortcutItemsContainer.addView(shortcutKeyIconView);
+ } else if (shortcutRepresentation.mString != null) {
+ TextView shortcutKeyTextView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_new_view,
+ shortcutItemsContainer,
+ false);
+ shortcutKeyTextView.setMinimumWidth(shortcutKeyTextItemMinWidth);
+ shortcutKeyTextView.setText(shortcutRepresentation.mString);
+ shortcutKeyTextView.setAccessibilityDelegate(
+ new ShortcutKeyAccessibilityDelegate(
+ shortcutRepresentation.mString));
+ shortcutItemsContainer.addView(shortcutKeyTextView);
+ }
+
+ if (k < shortcutKeysSize - 1) {
+ TextView shortcutKeyTextView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_plus_view,
+ shortcutItemsContainer,
+ false);
+ shortcutItemsContainer.addView(shortcutKeyTextView);
+ }
+ }
+ } else {
+ TextView shortcutKeyTextView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_new_view,
+ shortcutItemsContainer,
+ false);
+ shortcutKeyTextView.setMinimumWidth(shortcutKeyTextItemMinWidth);
+ shortcutKeyTextView.setText(complexCommand);
+ shortcutKeyTextView.setAccessibilityDelegate(
+ new ShortcutKeyAccessibilityDelegate(complexCommand));
+ shortcutItemsContainer.addView(shortcutKeyTextView);
+ }
+
+ if (p < keyGroupItemsSize - 1) {
+ TextView shortcutKeyTextView = (TextView) inflater.inflate(
+ R.layout.keyboard_shortcuts_key_vertical_bar_view,
+ shortcutItemsContainer,
+ false);
+ shortcutItemsContainer.addView(shortcutKeyTextView);
+ }
+ }
+ shortcutContainer.addView(shortcutView);
+ }
+
+ if (!groupSearchResult.isEmpty() && !groupSearchResult.get(i - 1)) {
+ keyboardShortcutsLayout.removeView(separator);
+ }
+
+ if (!itemSearchResult.isEmpty() && !itemSearchResult.contains(true)) {
+ // No results, so remove the category title and separator
+ keyboardShortcutsLayout.removeView(categoryTitle);
+ keyboardShortcutsLayout.removeView(separator);
+ groupSearchResult.add(false);
+ if (i == keyboardShortcutGroupsSize - 1 && !groupSearchResult.contains(true)) {
+ // show "No shortcut found"
+ mNoSearchResults.setVisibility(View.VISIBLE);
+ }
+ continue;
+ }
+ groupSearchResult.add(true);
+ mNoSearchResults.setVisibility(View.GONE);
+ keyboardShortcutsLayout.addView(shortcutContainer);
+ }
+ }
+
+ private List<StringDrawableContainer> getHumanReadableShortcutKeys(KeyboardShortcutInfo info) {
+ List<StringDrawableContainer> shortcutKeys = getHumanReadableModifiers(info);
+ if (shortcutKeys == null) {
+ return null;
+ }
+ String shortcutKeyString = null;
+ Drawable shortcutKeyDrawable = null;
+ if (info.getBaseCharacter() > Character.MIN_VALUE) {
+ shortcutKeyString = String.valueOf(info.getBaseCharacter());
+ } else if (mSpecialCharacterDrawables.get(info.getKeycode()) != null) {
+ shortcutKeyDrawable = mSpecialCharacterDrawables.get(info.getKeycode());
+ shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
+ } else if (mSpecialCharacterNames.get(info.getKeycode()) != null) {
+ shortcutKeyString = mSpecialCharacterNames.get(info.getKeycode());
+ } else {
+ // Special case for shortcuts with no base key or keycode.
+ if (info.getKeycode() == KeyEvent.KEYCODE_UNKNOWN) {
+ return shortcutKeys;
+ }
+ char displayLabel = mKeyCharacterMap.getDisplayLabel(info.getKeycode());
+ if (displayLabel != 0) {
+ shortcutKeyString = String.valueOf(displayLabel);
+ } else {
+ displayLabel = mBackupKeyCharacterMap.getDisplayLabel(info.getKeycode());
+ if (displayLabel != 0) {
+ shortcutKeyString = String.valueOf(displayLabel);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ if (shortcutKeyString != null) {
+ shortcutKeys.add(new StringDrawableContainer(shortcutKeyString, shortcutKeyDrawable));
+ } else {
+ Log.w(TAG, "Keyboard Shortcut does not have a text representation, skipping.");
+ }
+
+ return shortcutKeys;
+ }
+
+ private List<StringDrawableContainer> getHumanReadableModifiers(KeyboardShortcutInfo info) {
+ final List<StringDrawableContainer> shortcutKeys = new ArrayList<>();
+ int modifiers = info.getModifiers();
+ if (modifiers == 0) {
+ return shortcutKeys;
+ }
+ for (int supportedModifier : mModifierList) {
+ if ((modifiers & supportedModifier) != 0) {
+ shortcutKeys.add(new StringDrawableContainer(
+ mModifierNames.get(supportedModifier),
+ mModifierDrawables.get(supportedModifier)));
+ modifiers &= ~supportedModifier;
+ }
+ }
+ if (modifiers != 0) {
+ // Remaining unsupported modifiers, don't show anything.
+ return null;
+ }
+ return shortcutKeys;
+ }
+
+ private final class ShortcutKeyAccessibilityDelegate extends AccessibilityDelegate {
+ private String mContentDescription;
+
+ ShortcutKeyAccessibilityDelegate(String contentDescription) {
+ mContentDescription = contentDescription;
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ if (mContentDescription != null) {
+ info.setContentDescription(mContentDescription.toLowerCase(Locale.getDefault()));
+ }
+ }
+ }
+
+ private static final class StringDrawableContainer {
+ @NonNull
+ public String mString;
+ @Nullable
+ public Drawable mDrawable;
+
+ StringDrawableContainer(String string, Drawable drawable) {
+ mString = string;
+ mDrawable = drawable;
+ }
+ }
+
+ private void setDialogScreenSize() {
+ Window window = mKeyboardShortcutsBottomSheetDialog.getWindow();
+ Display display = mWindowManager.getDefaultDisplay();
+ WindowManager.LayoutParams lp =
+ mKeyboardShortcutsBottomSheetDialog.getWindow().getAttributes();
+ if (mContext.getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_PORTRAIT) {
+ lp.width = (int) (display.getWidth() * 0.8);
+ lp.height = (int) (display.getHeight() * 0.7);
+ } else {
+ lp.width = (int) (display.getWidth() * 0.7);
+ lp.height = (int) (display.getHeight() * 0.8);
+ }
+ window.setGravity(Gravity.BOTTOM);
+ window.setAttributes(lp);
+ }
+
+ private void setCurrentCategoryIndex(int index) {
+ mCurrentCategoryIndex = index;
+ }
+
+ private void setButtonsDefaultStatus(View keyboardShortcutsView) {
+ mButtonSystem = keyboardShortcutsView.findViewById(R.id.shortcut_system);
+ mButtonInput = keyboardShortcutsView.findViewById(R.id.shortcut_input);
+ mButtonOpenApps = keyboardShortcutsView.findViewById(R.id.shortcut_open_apps);
+ mButtonSpecificApp = keyboardShortcutsView.findViewById(R.id.shortcut_specific_app);
+
+ mButtonSystem.setOnClickListener(v -> {
+ setCurrentCategoryIndex(SHORTCUT_SYSTEM_INDEX);
+ populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container));
+ });
+
+ mButtonInput.setOnClickListener(v -> {
+ setCurrentCategoryIndex(SHORTCUT_INPUT_INDEX);
+ populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container));
+ });
+
+ mButtonOpenApps.setOnClickListener(v -> {
+ setCurrentCategoryIndex(SHORTCUT_OPENAPPS_INDEX);
+ populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container));
+ });
+
+ mButtonSpecificApp.setOnClickListener(v -> {
+ setCurrentCategoryIndex(SHORTCUT_SPECIFICAPP_INDEX);
+ populateKeyboardShortcutSearchList(keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container));
+ });
+
+ mFullButtonList.add(mButtonSystem);
+ mFullButtonList.add(mButtonInput);
+ mFullButtonList.add(mButtonOpenApps);
+ mFullButtonList.add(mButtonSpecificApp);
+ }
+
+ private void setButtonFocusColor(int i, boolean isFocused) {
+ if (isFocused) {
+ mFullButtonList.get(i).setTextColor(getColorOfTextColorOnAccent());
+ mFullButtonList.get(i).setBackground(
+ mContext.getDrawable(R.drawable.shortcut_button_focus_colored));
+ } else {
+ // Default color
+ mFullButtonList.get(i).setTextColor(getColorOfTextColorSecondary());
+ mFullButtonList.get(i).setBackground(
+ mContext.getDrawable(R.drawable.shortcut_button_colored));
+ }
+ }
+
+ private int getColorOfTextColorOnAccent() {
+ return Utils.getColorAttrDefaultColor(
+ mContext, com.android.internal.R.attr.textColorOnAccent);
+ }
+
+ private int getColorOfTextColorSecondary() {
+ return Utils.getColorAttrDefaultColor(
+ mContext, com.android.internal.R.attr.textColorSecondary);
+ }
+
+ // Create the new data structure for handling the N-to-1 key mapping and other complex case.
+ private static class KeyboardShortcutMultiMappingGroup {
+ private final CharSequence mCategory;
+ private List<ShortcutMultiMappingInfo> mItems;
+
+ KeyboardShortcutMultiMappingGroup(
+ CharSequence category, List<ShortcutMultiMappingInfo> items) {
+ mCategory = category;
+ mItems = items;
+ }
+
+ void addItem(ShortcutMultiMappingInfo item) {
+ mItems.add(item);
+ }
+
+ CharSequence getCategory() {
+ return mCategory;
+ }
+
+ List<ShortcutMultiMappingInfo> getItems() {
+ return mItems;
+ }
+ }
+
+ private static class ShortcutMultiMappingInfo {
+ private final CharSequence mLabel;
+ private final Icon mIcon;
+ private List<ShortcutKeyGroup> mShortcutKeyGroups;
+
+ ShortcutMultiMappingInfo(
+ CharSequence label, Icon icon, List<ShortcutKeyGroup> shortcutKeyGroups) {
+ mLabel = label;
+ mIcon = icon;
+ mShortcutKeyGroups = shortcutKeyGroups;
+ }
+
+ ShortcutMultiMappingInfo(KeyboardShortcutInfo info) {
+ mLabel = info.getLabel();
+ mIcon = info.getIcon();
+ mShortcutKeyGroups = Arrays.asList(new ShortcutKeyGroup(info, null));
+ }
+
+ CharSequence getLabel() {
+ return mLabel;
+ }
+
+ Icon getIcon() {
+ return mIcon;
+ }
+
+ List<ShortcutKeyGroup> getShortcutKeyGroups() {
+ return mShortcutKeyGroups;
+ }
+ }
+
+ private static class ShortcutKeyGroup {
+ private final KeyboardShortcutInfo mKeyboardShortcutInfo;
+ private final String mComplexCommand;
+
+ ShortcutKeyGroup(KeyboardShortcutInfo keyboardShortcutInfo, String complexCommand) {
+ mKeyboardShortcutInfo = keyboardShortcutInfo;
+ mComplexCommand = complexCommand;
+ }
+
+ // To be compatible with the original functions, keep KeyboardShortcutInfo in here.
+ KeyboardShortcutInfo getKeyboardShortcutInfo() {
+ return mKeyboardShortcutInfo;
+ }
+
+ // In some case, the shortcut is a complex description not a N-to-1 key mapping.
+ String getComplexCommand() {
+ return mComplexCommand;
+ }
+ }
+
+ private static PackageInfo getAssistPackageInfo(
+ Context context, IPackageManager packageManager, int userId) {
+ AssistUtils assistUtils = new AssistUtils(context);
+ ComponentName assistComponent = assistUtils.getAssistComponentForUser(userId);
+ // Not all devices have an assist component.
+ PackageInfo assistPackageInfo = null;
+ if (assistComponent != null) {
+ try {
+ assistPackageInfo = packageManager.getPackageInfo(
+ assistComponent.getPackageName(), 0, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "PackageManagerService is dead");
+ }
+ }
+ return assistPackageInfo;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 7e6ddcfea762..f20f929637cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -63,6 +63,7 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -80,7 +81,8 @@ import java.util.List;
public final class KeyboardShortcuts {
private static final String TAG = KeyboardShortcuts.class.getSimpleName();
private static final Object sLock = new Object();
- private static KeyboardShortcuts sInstance;
+ @VisibleForTesting static KeyboardShortcuts sInstance;
+ private WindowManager mWindowManager;
private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
private final SparseArray<String> mModifierNames = new SparseArray<>();
@@ -94,7 +96,7 @@ public final class KeyboardShortcuts {
};
private final Handler mHandler = new Handler(Looper.getMainLooper());
- private final Context mContext;
+ @VisibleForTesting Context mContext;
private final IPackageManager mPackageManager;
private final OnClickListener mDialogCloseListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
@@ -123,20 +125,26 @@ public final class KeyboardShortcuts {
}
};
- private Dialog mKeyboardShortcutsDialog;
+ @VisibleForTesting Dialog mKeyboardShortcutsDialog;
private KeyCharacterMap mKeyCharacterMap;
private KeyCharacterMap mBackupKeyCharacterMap;
- private KeyboardShortcuts(Context context) {
+ @VisibleForTesting
+ KeyboardShortcuts(Context context, WindowManager windowManager) {
this.mContext = new ContextThemeWrapper(
context, android.R.style.Theme_DeviceDefault_Settings);
this.mPackageManager = AppGlobals.getPackageManager();
+ if (windowManager != null) {
+ this.mWindowManager = windowManager;
+ } else {
+ this.mWindowManager = mContext.getSystemService(WindowManager.class);
+ }
loadResources(context);
}
private static KeyboardShortcuts getInstance(Context context) {
if (sInstance == null) {
- sInstance = new KeyboardShortcuts(context);
+ sInstance = new KeyboardShortcuts(context, null);
}
return sInstance;
}
@@ -371,10 +379,10 @@ public final class KeyboardShortcuts {
mKeyCharacterMap = mBackupKeyCharacterMap;
}
- private void showKeyboardShortcuts(int deviceId) {
+ @VisibleForTesting
+ void showKeyboardShortcuts(int deviceId) {
retrieveKeyCharacterMap(deviceId);
- WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- wm.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() {
+ mWindowManager.requestAppKeyboardShortcuts(new KeyboardShortcutsReceiver() {
@Override
public void onKeyboardShortcutsReceived(
final List<KeyboardShortcutGroup> result) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
index 8a5becead255..e9fac28395ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
@@ -19,16 +19,38 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+import javax.inject.Inject;
+
/**
* Receiver for the Keyboard Shortcuts Helper.
*/
public class KeyboardShortcutsReceiver extends BroadcastReceiver {
+
+ private boolean mIsShortcutListSearchEnabled;
+
+ @Inject
+ public KeyboardShortcutsReceiver(FeatureFlags featureFlags) {
+ mIsShortcutListSearchEnabled = featureFlags.isEnabled(Flags.SHORTCUT_LIST_SEARCH_LAYOUT);
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
- KeyboardShortcuts.show(context, -1 /* deviceId unknown */);
- } else if (Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
- KeyboardShortcuts.dismiss();
+ if (mIsShortcutListSearchEnabled && Utilities.isTablet(context)) {
+ if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+ KeyboardShortcutListSearch.show(context, -1 /* deviceId unknown */);
+ } else if (Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+ KeyboardShortcutListSearch.dismiss();
+ }
+ } else {
+ if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+ KeyboardShortcuts.show(context, -1 /* deviceId unknown */);
+ } else if (Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+ KeyboardShortcuts.dismiss();
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationDismissibilityProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationDismissibilityProviderImpl.kt
index 049321b3c821..b31825207132 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationDismissibilityProviderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationDismissibilityProviderImpl.kt
@@ -17,11 +17,10 @@
package com.android.systemui.statusbar.notification.collection.provider
import androidx.annotation.VisibleForTesting
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.ALLOW_DISMISS_ONGOING
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.util.asIndenting
import com.android.systemui.util.withIncreasedIndent
@@ -29,7 +28,9 @@ import java.io.PrintWriter
import javax.inject.Inject
@SysUISingleton
-class NotificationDismissibilityProviderImpl @Inject constructor(dumpManager: DumpManager) :
+class NotificationDismissibilityProviderImpl
+@Inject
+constructor(private val notifPipelineFlags: NotifPipelineFlags, dumpManager: DumpManager) :
NotificationDismissibilityProvider, Dumpable {
init {
@@ -42,8 +43,7 @@ class NotificationDismissibilityProviderImpl @Inject constructor(dumpManager: Du
private set
override fun isDismissable(entry: NotificationEntry): Boolean {
- // TODO(b/268380968): inject FlagResolver
- return if (SystemUiSystemPropertiesFlags.getResolver().isEnabled(ALLOW_DISMISS_ONGOING)) {
+ return if (notifPipelineFlags.allowDismissOngoing()) {
entry.key !in nonDismissableEntryKeys
} else {
entry.legacyIsDismissableRecursive()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
index 13b3aca2a88f..27fe747e6be8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
@@ -70,7 +70,15 @@ class NotificationInterruptLogger @Inject constructor(
buffer.log(TAG, DEBUG, {
str1 = entry.logKey
}, {
- "No alerting: snoozed package: $str1"
+ "No heads up: snoozed package: $str1"
+ })
+ }
+
+ fun logHeadsUpPackageSnoozeBypassedHasFsi(entry: NotificationEntry) {
+ buffer.log(TAG, DEBUG, {
+ str1 = entry.logKey
+ }, {
+ "Heads up: package snooze bypassed because notification has full-screen intent: $str1"
})
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 9bcf92d63b8f..afeb72fa9eeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.interruption;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD;
import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR;
+import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI;
import android.app.Notification;
import android.app.NotificationManager;
@@ -87,7 +88,10 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD(1236),
@UiEvent(doc = "HUN suppressed for old when")
- HUN_SUPPRESSED_OLD_WHEN(1237);
+ HUN_SUPPRESSED_OLD_WHEN(1237),
+
+ @UiEvent(doc = "HUN snooze bypassed for potentially suppressed FSI")
+ HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI(1269);
private final int mId;
@@ -409,7 +413,15 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
- if (isSnoozedPackage(sbn)) {
+ final boolean isSnoozedPackage = isSnoozedPackage(sbn);
+ final boolean fsiRequiresKeyguard = mFlags.fullScreenIntentRequiresKeyguard();
+ final boolean hasFsi = sbn.getNotification().fullScreenIntent != null;
+
+ // Assume any notification with an FSI is time-sensitive (like an alarm or incoming call)
+ // and ignore whether HUNs have been snoozed for the package.
+ final boolean shouldBypassSnooze = fsiRequiresKeyguard && hasFsi;
+
+ if (isSnoozedPackage && !shouldBypassSnooze) {
if (log) mLogger.logNoHeadsUpPackageSnoozed(entry);
return false;
}
@@ -447,6 +459,19 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
return false;
}
}
+
+ if (isSnoozedPackage) {
+ if (log) {
+ mLogger.logHeadsUpPackageSnoozeBypassedHasFsi(entry);
+ final int uid = entry.getSbn().getUid();
+ final String packageName = entry.getSbn().getPackageName();
+ mUiEventLogger.log(HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI, uid,
+ packageName);
+ }
+
+ return true;
+ }
+
if (log) mLogger.logHeadsUp(entry);
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 1966a6657acb..6a52a3342aa0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -186,11 +186,13 @@ import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CircleReveal;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.KeyboardShortcutListSearch;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LiftReveal;
@@ -299,6 +301,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
private CentralSurfacesCommandQueueCallbacks mCommandQueueCallbacks;
private float mTransitionToFullShadeProgress = 0f;
private NotificationListContainer mNotifListContainer;
+ private boolean mIsShortcutListSearchEnabled;
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
new KeyguardStateController.Callback() {
@@ -833,6 +836,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
mCameraLauncherLazy = cameraLauncherLazy;
mAlternateBouncerInteractor = alternateBouncerInteractor;
mUserTracker = userTracker;
+ mIsShortcutListSearchEnabled = featureFlags.isEnabled(Flags.SHORTCUT_LIST_SEARCH_LAYOUT);
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mStartingSurfaceOptional = startingSurfaceOptional;
@@ -2546,7 +2550,11 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
String action = intent.getAction();
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- KeyboardShortcuts.dismiss();
+ if (mIsShortcutListSearchEnabled && Utilities.isTablet(mContext)) {
+ KeyboardShortcutListSearch.dismiss();
+ } else {
+ KeyboardShortcuts.dismiss();
+ }
mRemoteInputManager.closeRemoteInputs();
if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) {
int flags = CommandQueue.FLAG_EXCLUDE_NONE;
@@ -3893,11 +3901,19 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
}
protected void toggleKeyboardShortcuts(int deviceId) {
- KeyboardShortcuts.toggle(mContext, deviceId);
+ if (mIsShortcutListSearchEnabled && Utilities.isTablet(mContext)) {
+ KeyboardShortcutListSearch.toggle(mContext, deviceId);
+ } else {
+ KeyboardShortcuts.toggle(mContext, deviceId);
+ }
}
protected void dismissKeyboardShortcuts() {
- KeyboardShortcuts.dismiss();
+ if (mIsShortcutListSearchEnabled && Utilities.isTablet(mContext)) {
+ KeyboardShortcutListSearch.dismiss();
+ } else {
+ KeyboardShortcuts.dismiss();
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
index 2d80edb8d2f4..270c592ae4fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
@@ -21,7 +21,7 @@ import android.util.AttributeSet
import android.widget.ImageView
import android.widget.TextView
import com.android.systemui.R
-import com.android.systemui.common.ui.view.LaunchableLinearLayout
+import com.android.systemui.animation.view.LaunchableLinearLayout
class StatusBarUserSwitcherContainer(
context: Context?,
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt
index dde2a80b05f7..27cafb10c07d 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerStartable.kt
@@ -74,6 +74,7 @@ constructor(
stylusUsiPowerUi.init()
stylusManager.registerCallback(this)
+ stylusManager.registerBatteryCallback(this)
stylusManager.startListener()
}
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
index 696134cde3c9..a20a5b2fdbbc 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
@@ -16,6 +16,8 @@
package com.android.systemui.temporarydisplay.chipbar
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Rect
import android.os.PowerManager
@@ -27,11 +29,14 @@ import android.view.View.ACCESSIBILITY_LIVE_REGION_NONE
import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
+import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.IdRes
+import androidx.annotation.VisibleForTesting
import com.android.internal.widget.CachingIconView
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
import com.android.systemui.common.shared.model.Text.Companion.loadText
@@ -101,6 +106,15 @@ constructor(
private lateinit var parent: ChipbarRootView
+ /** The current loading information, or null we're not currently loading. */
+ @VisibleForTesting
+ internal var loadingDetails: LoadingDetails? = null
+ private set(value) {
+ // Always cancel the old one before updating
+ field?.animator?.cancel()
+ field = value
+ }
+
override val windowLayoutParams =
commonWindowLayoutParams.apply { gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL) }
@@ -143,8 +157,22 @@ constructor(
// ---- End item ----
// Loading
- currentView.requireViewById<View>(R.id.loading).visibility =
- (newInfo.endItem == ChipbarEndItem.Loading).visibleIfTrue()
+ val isLoading = newInfo.endItem == ChipbarEndItem.Loading
+ val loadingView = currentView.requireViewById<ImageView>(R.id.loading)
+ loadingView.visibility = isLoading.visibleIfTrue()
+
+ if (isLoading) {
+ val currentLoadingDetails = loadingDetails
+ // Since there can be multiple chipbars, we need to check if the loading view is the
+ // same and possibly re-start the loading animation on the new view.
+ if (currentLoadingDetails == null || currentLoadingDetails.loadingView != loadingView) {
+ val newDetails = createLoadingDetails(loadingView)
+ newDetails.animator.start()
+ loadingDetails = newDetails
+ }
+ } else {
+ loadingDetails = null
+ }
// Error
currentView.requireViewById<View>(R.id.error).visibility =
@@ -223,12 +251,17 @@ constructor(
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
val innerView = view.getInnerView()
innerView.accessibilityLiveRegion = ACCESSIBILITY_LIVE_REGION_NONE
- val removed = chipbarAnimator.animateViewOut(innerView, onAnimationEnd)
+
+ val fullEndRunnable = Runnable {
+ loadingDetails = null
+ onAnimationEnd.run()
+ }
+ val removed = chipbarAnimator.animateViewOut(innerView, fullEndRunnable)
// If the view doesn't get animated, the [onAnimationEnd] runnable won't get run. So, just
// run it immediately.
if (!removed) {
logger.logAnimateOutFailure()
- onAnimationEnd.run()
+ fullEndRunnable.run()
}
updateGestureListening()
@@ -269,7 +302,7 @@ constructor(
}
private fun ViewGroup.getInnerView(): ViewGroup {
- return requireViewById(R.id.chipbar_inner)
+ return this.requireViewById(R.id.chipbar_inner)
}
override fun getTouchableRegion(view: View, outRect: Rect) {
@@ -283,8 +316,28 @@ constructor(
View.GONE
}
}
+
+ private fun createLoadingDetails(loadingView: View): LoadingDetails {
+ // Ideally, we would use a <ProgressBar> view, which would automatically handle the loading
+ // spinner rotation for us. However, due to b/243983980, the ProgressBar animation
+ // unexpectedly pauses when SysUI starts another window. ObjectAnimator is a workaround that
+ // won't pause.
+ val animator =
+ ObjectAnimator.ofFloat(loadingView, View.ROTATION, 0f, 360f).apply {
+ duration = LOADING_ANIMATION_DURATION_MS
+ repeatCount = ValueAnimator.INFINITE
+ interpolator = Interpolators.LINEAR
+ }
+ return LoadingDetails(loadingView, animator)
+ }
+
+ internal data class LoadingDetails(
+ val loadingView: View,
+ val animator: ObjectAnimator,
+ )
}
@IdRes private val INFO_TAG = R.id.tag_chipbar_info
private const val SWIPE_UP_GESTURE_REASON = "SWIPE_UP_GESTURE_DETECTED"
private const val TAG = "ChipbarCoordinator"
+private const val LOADING_ANIMATION_DURATION_MS = 1000L
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index 19a0866cd0a8..6ef828fbdfdb 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -166,7 +166,8 @@ constructor(
overlayAddReason = reason
- val newRoot = SurfaceControlViewHost(context, context.display!!, wwm)
+ val newRoot = SurfaceControlViewHost(context, context.display!!, wwm,
+ "UnfoldLightRevealOverlayAnimation")
val params = getLayoutParams()
val newView =
LightRevealScrim(
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
index 2b29885db682..f7c8bac1b478 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserModule.java
+++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
@@ -21,6 +21,7 @@ import android.os.UserHandle;
import com.android.settingslib.users.EditUserInfoController;
import com.android.systemui.user.data.repository.UserRepositoryModule;
+import com.android.systemui.user.domain.interactor.HeadlessSystemUserModeModule;
import com.android.systemui.user.ui.dialog.UserDialogModule;
import dagger.Binds;
@@ -36,6 +37,7 @@ import dagger.multibindings.IntoMap;
includes = {
UserDialogModule.class,
UserRepositoryModule.class,
+ HeadlessSystemUserModeModule.class,
}
)
public abstract class UserModule {
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
index 0a07439e1876..2f63f32557e9 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
@@ -148,7 +148,7 @@ constructor(
withContext(backgroundDispatcher) {
manager.getUserInfo(lastSelectedNonGuestUserHandle)
}
- if (info != null && info.isEnabled && info.supportsSwitchToByUser()) {
+ if (info != null && info.isEnabled && info.supportsSwitchTo()) {
newUserId = info.id
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserMode.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserMode.kt
new file mode 100644
index 000000000000..756e6a1a5b15
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserMode.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.user.domain.interactor
+
+import android.os.UserManager
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+interface HeadlessSystemUserMode {
+
+ fun isHeadlessSystemUserMode(): Boolean
+}
+
+@SysUISingleton
+class HeadlessSystemUserModeImpl @Inject constructor() : HeadlessSystemUserMode {
+ override fun isHeadlessSystemUserMode(): Boolean {
+ return UserManager.isHeadlessSystemUserMode()
+ }
+}
diff --git a/telephony/java/android/telephony/satellite/ISatelliteCapabilitiesConsumer.aidl b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeModule.kt
index f3ae2453ad2c..0efa2d8b6a36 100644
--- a/telephony/java/android/telephony/satellite/ISatelliteCapabilitiesConsumer.aidl
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/HeadlessSystemUserModeModule.kt
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package android.telephony.satellite;
+package com.android.systemui.user.domain.interactor
-import android.telephony.satellite.SatelliteCapabilities;
+import dagger.Binds
-/**
- * Consumer for a SatelliteCapabilities result from the satellite service.
- * @hide
- */
-oneway interface ISatelliteCapabilitiesConsumer {
- void accept(in SatelliteCapabilities result);
+@dagger.Module
+interface HeadlessSystemUserModeModule {
+
+ @Binds
+ fun bindIsHeadlessSystemUserMode(impl: HeadlessSystemUserModeImpl): HeadlessSystemUserMode
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index c8f98c35f589..433642b7366c 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -89,6 +89,7 @@ constructor(
private val keyguardInteractor: KeyguardInteractor,
private val featureFlags: FeatureFlags,
private val manager: UserManager,
+ private val headlessSystemUserMode: HeadlessSystemUserMode,
@Application private val applicationScope: CoroutineScope,
telephonyInteractor: TelephonyInteractor,
broadcastDispatcher: BroadcastDispatcher,
@@ -571,7 +572,10 @@ constructor(
actionType = action,
isRestricted = isRestricted,
isSwitchToEnabled =
- canSwitchUsers(selectedUserId) &&
+ canSwitchUsers(
+ selectedUserId = selectedUserId,
+ isAction = true,
+ ) &&
// If the user is auto-created is must not be currently resetting.
!(isGuestUserAutoCreated && isGuestUserResetting),
)
@@ -723,10 +727,32 @@ constructor(
}
}
- private suspend fun canSwitchUsers(selectedUserId: Int): Boolean {
- return withContext(backgroundDispatcher) {
- manager.getUserSwitchability(UserHandle.of(selectedUserId))
- } == UserManager.SWITCHABILITY_STATUS_OK
+ private suspend fun canSwitchUsers(
+ selectedUserId: Int,
+ isAction: Boolean = false,
+ ): Boolean {
+ val isHeadlessSystemUserMode =
+ withContext(backgroundDispatcher) { headlessSystemUserMode.isHeadlessSystemUserMode() }
+ // Whether menu item should be active. True if item is a user or if any user has
+ // signed in since reboot or in all cases for non-headless system user mode.
+ val isItemEnabled = !isAction || !isHeadlessSystemUserMode || isAnyUserUnlocked()
+ return isItemEnabled &&
+ withContext(backgroundDispatcher) {
+ manager.getUserSwitchability(UserHandle.of(selectedUserId))
+ } == UserManager.SWITCHABILITY_STATUS_OK
+ }
+
+ private suspend fun isAnyUserUnlocked(): Boolean {
+ return manager
+ .getUsers(
+ /* excludePartial= */ true,
+ /* excludeDying= */ true,
+ /* excludePreCreated= */ true
+ )
+ .any { user ->
+ user.id != UserHandle.USER_SYSTEM &&
+ withContext(backgroundDispatcher) { manager.isUserUnlocked(user.userHandle) }
+ }
}
@SuppressLint("UseCompatLoadingForDrawables")
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 0dae91819a94..9600fd88a2a3 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -25,7 +25,6 @@ import static android.service.notification.NotificationListenerService.REASON_GR
import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.ALLOW_DISMISS_ONGOING;
import static com.android.systemui.flags.Flags.WM_BUBBLE_BAR;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -51,7 +50,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.flags.FeatureFlags;
@@ -60,6 +58,7 @@ import com.android.systemui.shade.ShadeController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -106,6 +105,7 @@ public class BubblesManager {
private final NotificationLockscreenUserManager mNotifUserManager;
private final CommonNotifCollection mCommonNotifCollection;
private final NotifPipeline mNotifPipeline;
+ private final NotifPipelineFlags mNotifPipelineFlags;
private final Executor mSysuiMainExecutor;
private final Bubbles.SysuiProxy mSysuiProxy;
@@ -134,6 +134,7 @@ public class BubblesManager {
NotifPipeline notifPipeline,
SysUiState sysUiState,
FeatureFlags featureFlags,
+ NotifPipelineFlags notifPipelineFlags,
Executor sysuiMainExecutor) {
if (bubblesOptional.isPresent()) {
return new BubblesManager(context,
@@ -152,6 +153,7 @@ public class BubblesManager {
notifPipeline,
sysUiState,
featureFlags,
+ notifPipelineFlags,
sysuiMainExecutor);
} else {
return null;
@@ -175,6 +177,7 @@ public class BubblesManager {
NotifPipeline notifPipeline,
SysUiState sysUiState,
FeatureFlags featureFlags,
+ NotifPipelineFlags notifPipelineFlags,
Executor sysuiMainExecutor) {
mContext = context;
mBubbles = bubbles;
@@ -187,6 +190,7 @@ public class BubblesManager {
mNotifUserManager = notifUserManager;
mCommonNotifCollection = notifCollection;
mNotifPipeline = notifPipeline;
+ mNotifPipelineFlags = notifPipelineFlags;
mSysuiMainExecutor = sysuiMainExecutor;
mBarService = statusBarService == null
@@ -618,15 +622,15 @@ public class BubblesManager {
}
}
- static BubbleEntry notifToBubbleEntry(NotificationEntry e) {
+ @VisibleForTesting
+ BubbleEntry notifToBubbleEntry(NotificationEntry e) {
return new BubbleEntry(e.getSbn(), e.getRanking(), isDismissableFromBubbles(e),
e.shouldSuppressNotificationDot(), e.shouldSuppressNotificationList(),
e.shouldSuppressPeek());
}
- private static boolean isDismissableFromBubbles(NotificationEntry e) {
- // TODO(b/268380968): inject FlagResolver
- if (SystemUiSystemPropertiesFlags.getResolver().isEnabled(ALLOW_DISMISS_ONGOING)) {
+ private boolean isDismissableFromBubbles(NotificationEntry e) {
+ if (mNotifPipelineFlags.allowDismissOngoing()) {
// Bubbles are only accessible from the unlocked state,
// so we can calculate this from the Notification flags only.
return e.isDismissableForState(/*isLocked=*/ false);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index 7b0d091d3aee..0d65f124fb8c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -602,14 +602,6 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
any(KeyguardSecurityCallback.class));
}
- @Test
- public void testReinflateViewFlipper() {
- mKeyguardSecurityContainerController.reinflateViewFlipper();
- verify(mKeyguardSecurityViewFlipperController).clearViews();
- verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
- any(KeyguardSecurityCallback.class));
- }
-
private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() {
mKeyguardSecurityContainerController.onViewAttached();
verify(mView).setSwipeListener(mSwipeListenerArgumentCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt
new file mode 100644
index 000000000000..9fcb9c8f1662
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/NumPadAnimatorTest.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.keyguard
+
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class NumPadAnimatorTest : SysuiTestCase() {
+ @Mock lateinit var background: GradientDrawable
+ @Mock lateinit var buttonImage: Drawable
+ private lateinit var underTest: NumPadAnimator
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ underTest = NumPadAnimator(context, background, 0, buttonImage)
+ }
+
+ @Test
+ fun testOnLayout() {
+ underTest.onLayout(100)
+ verify(background).cornerRadius = 50f
+ reset(background)
+ underTest.onLayout(100)
+ verify(background, never()).cornerRadius = anyFloat()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
new file mode 100644
index 000000000000..777dd4e0b4a3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.accessibility.fontscaling
+
+import android.os.Handler
+import android.provider.Settings
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.widget.ImageView
+import android.widget.SeekBar
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
+import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.settings.SystemSettings
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for [FontScalingDialog]. */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class FontScalingDialogTest : SysuiTestCase() {
+ private lateinit var fontScalingDialog: FontScalingDialog
+ private lateinit var systemSettings: SystemSettings
+ private val fontSizeValueArray: Array<String> =
+ mContext
+ .getResources()
+ .getStringArray(com.android.settingslib.R.array.entryvalues_font_size)
+
+ @Before
+ fun setUp() {
+ val mainHandler = Handler(TestableLooper.get(this).getLooper())
+ systemSettings = FakeSettings()
+ fontScalingDialog = FontScalingDialog(mContext, systemSettings as FakeSettings)
+ }
+
+ @Test
+ fun showTheDialog_seekbarIsShowingCorrectProgress() {
+ fontScalingDialog.show()
+
+ val seekBar: SeekBar = fontScalingDialog.findViewById<SeekBar>(R.id.seekbar)!!
+ val progress: Int = seekBar.getProgress()
+ val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f)
+
+ assertThat(currentScale).isEqualTo(fontSizeValueArray[progress].toFloat())
+
+ fontScalingDialog.dismiss()
+ }
+
+ @Test
+ fun progressIsZero_clickIconEnd_seekBarProgressIncreaseOne_fontSizeScaled() {
+ fontScalingDialog.show()
+
+ val iconEnd: ImageView = fontScalingDialog.findViewById(R.id.icon_end)!!
+ val seekBarWithIconButtonsView: SeekBarWithIconButtonsView =
+ fontScalingDialog.findViewById(R.id.font_scaling_slider)!!
+ val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!!
+
+ seekBarWithIconButtonsView.setProgress(0)
+
+ iconEnd.performClick()
+
+ val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f)
+ assertThat(seekBar.getProgress()).isEqualTo(1)
+ assertThat(currentScale).isEqualTo(fontSizeValueArray[1].toFloat())
+
+ fontScalingDialog.dismiss()
+ }
+
+ @Test
+ fun progressIsMax_clickIconStart_seekBarProgressDecreaseOne_fontSizeScaled() {
+ fontScalingDialog.show()
+
+ val iconStart: ImageView = fontScalingDialog.findViewById(R.id.icon_start)!!
+ val seekBarWithIconButtonsView: SeekBarWithIconButtonsView =
+ fontScalingDialog.findViewById(R.id.font_scaling_slider)!!
+ val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!!
+
+ seekBarWithIconButtonsView.setProgress(fontSizeValueArray.size - 1)
+
+ iconStart.performClick()
+
+ val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def = */ 1.0f)
+ assertThat(seekBar.getProgress()).isEqualTo(fontSizeValueArray.size - 2)
+ assertThat(currentScale)
+ .isEqualTo(fontSizeValueArray[fontSizeValueArray.size - 2].toFloat())
+
+ fontScalingDialog.dismiss()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
index d7aa6e063d1e..b389558faa05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
@@ -19,6 +19,7 @@ package com.android.systemui.animation
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.graphics.Typeface
+import android.graphics.fonts.FontVariationAxis
import android.testing.AndroidTestingRunner
import android.text.Layout
import android.text.StaticLayout
@@ -179,4 +180,71 @@ class TextAnimatorTest : SysuiTestCase() {
assertThat(paint.typeface).isSameInstanceAs(prevTypeface)
}
+
+ @Test
+ fun testSetTextStyle_addWeight() {
+ testWeightChange("", 100, FontVariationAxis.fromFontVariationSettings("'wght' 100")!!)
+ }
+
+ @Test
+ fun testSetTextStyle_changeWeight() {
+ testWeightChange(
+ "'wght' 500",
+ 100,
+ FontVariationAxis.fromFontVariationSettings("'wght' 100")!!
+ )
+ }
+
+ @Test
+ fun testSetTextStyle_addWeightWithOtherAxis() {
+ testWeightChange(
+ "'wdth' 100",
+ 100,
+ FontVariationAxis.fromFontVariationSettings("'wght' 100, 'wdth' 100")!!
+ )
+ }
+
+ @Test
+ fun testSetTextStyle_changeWeightWithOtherAxis() {
+ testWeightChange(
+ "'wght' 500, 'wdth' 100",
+ 100,
+ FontVariationAxis.fromFontVariationSettings("'wght' 100, 'wdth' 100")!!
+ )
+ }
+
+ private fun testWeightChange(
+ initialFontVariationSettings: String,
+ weight: Int,
+ expectedFontVariationSettings: Array<FontVariationAxis>
+ ) {
+ val layout = makeLayout("Hello, World", PAINT)
+ val valueAnimator = mock(ValueAnimator::class.java)
+ val textInterpolator = mock(TextInterpolator::class.java)
+ val paint =
+ TextPaint().apply {
+ typeface = Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf")
+ fontVariationSettings = initialFontVariationSettings
+ }
+ `when`(textInterpolator.targetPaint).thenReturn(paint)
+
+ val textAnimator =
+ TextAnimator(layout, {}).apply {
+ this.textInterpolator = textInterpolator
+ this.animator = valueAnimator
+ }
+ textAnimator.setTextStyle(weight = weight, animate = false)
+
+ val resultFontVariationList =
+ FontVariationAxis.fromFontVariationSettings(
+ textInterpolator.targetPaint.fontVariationSettings
+ )
+ expectedFontVariationSettings.forEach { expectedAxis ->
+ val resultAxis = resultFontVariationList?.filter { it.tag == expectedAxis.tag }?.get(0)
+ assertThat(resultAxis).isNotNull()
+ if (resultAxis != null) {
+ assertThat(resultAxis.styleValue).isEqualTo(expectedAxis.styleValue)
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
index fc1d38b2c1fb..8534d4ff86ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
@@ -37,7 +37,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.common.ui.view.LaunchableImageView;
+import com.android.systemui.animation.view.LaunchableImageView;
import com.android.systemui.controls.ControlsServiceInfo;
import com.android.systemui.controls.controller.ControlsController;
import com.android.systemui.controls.controller.StructureInfo;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt
new file mode 100644
index 000000000000..57abae0889ca
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/FontScalingTileTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs.tiles.dialog
+
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.QSTileHost
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tiles.FontScalingTile
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class FontScalingTileTest : SysuiTestCase() {
+ @Mock private lateinit var qsHost: QSTileHost
+ @Mock private lateinit var metricsLogger: MetricsLogger
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var qsLogger: QSLogger
+ @Mock private lateinit var dialogLaunchAnimator: DialogLaunchAnimator
+
+ private lateinit var testableLooper: TestableLooper
+ private lateinit var fontScalingTile: FontScalingTile
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ testableLooper = TestableLooper.get(this)
+ `when`(qsHost.getContext()).thenReturn(mContext)
+ fontScalingTile =
+ FontScalingTile(
+ qsHost,
+ testableLooper.looper,
+ Handler(testableLooper.looper),
+ FalsingManagerFake(),
+ metricsLogger,
+ statusBarStateController,
+ activityStarter,
+ qsLogger,
+ dialogLaunchAnimator,
+ FakeSettings()
+ )
+ fontScalingTile.initialize()
+ }
+
+ @Test
+ fun isNotAvailable_whenNotSupportedDevice_returnsFalse() {
+ val isAvailable = fontScalingTile.isAvailable()
+
+ assertThat(isAvailable).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java
new file mode 100644
index 000000000000..109f185c625e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutListSearchTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+
+import com.google.android.material.bottomsheet.BottomSheetDialog;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutListSearchTest extends SysuiTestCase {
+
+ @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+ private static int DEVICE_ID = 1;
+ private KeyboardShortcutListSearch mKeyboardShortcutListSearch;
+
+ @Mock private BottomSheetDialog mBottomSheetDialog;
+ @Mock WindowManager mWindowManager;
+
+ @Before
+ public void setUp() {
+ mKeyboardShortcutListSearch = new KeyboardShortcutListSearch(mContext, mWindowManager);
+ mKeyboardShortcutListSearch.sInstance = mKeyboardShortcutListSearch;
+ mKeyboardShortcutListSearch.mKeyboardShortcutsBottomSheetDialog = mBottomSheetDialog;
+ mKeyboardShortcutListSearch.mContext = mContext;
+ }
+
+ @Test
+ public void toggle_isShowingTrue_instanceShouldBeNull() {
+ when(mBottomSheetDialog.isShowing()).thenReturn(true);
+
+ mKeyboardShortcutListSearch.toggle(mContext, DEVICE_ID);
+
+ assertThat(mKeyboardShortcutListSearch.sInstance).isNull();
+ }
+
+ @Test
+ public void toggle_isShowingFalse_showKeyboardShortcuts() {
+ when(mBottomSheetDialog.isShowing()).thenReturn(false);
+
+ mKeyboardShortcutListSearch.toggle(mContext, DEVICE_ID);
+
+ verify(mWindowManager).requestAppKeyboardShortcuts(any(), anyInt());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsReceiverTest.java
new file mode 100644
index 000000000000..bea2cfb8bb5c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsReceiverTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.Flags;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutsReceiverTest extends SysuiTestCase {
+
+ @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+ private KeyboardShortcutsReceiver mKeyboardShortcutsReceiver;
+ private Intent mIntent;
+ private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
+
+ @Mock private KeyboardShortcuts mKeyboardShortcuts;
+ @Mock private KeyboardShortcutListSearch mKeyboardShortcutListSearch;
+
+ @Before
+ public void setUp() {
+ mIntent = new Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS);
+ mKeyboardShortcuts.mContext = mContext;
+ mKeyboardShortcutListSearch.mContext = mContext;
+ KeyboardShortcuts.sInstance = mKeyboardShortcuts;
+ KeyboardShortcutListSearch.sInstance = mKeyboardShortcutListSearch;
+ }
+
+ @Test
+ public void onReceive_whenFlagOffDeviceIsTablet_showKeyboardShortcuts() {
+ MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Utilities.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
+ mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+ when(Utilities.isTablet(mContext)).thenReturn(true);
+
+ mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+ verify(mKeyboardShortcuts).showKeyboardShortcuts(anyInt());
+ verify(mKeyboardShortcutListSearch, never()).showKeyboardShortcuts(anyInt());
+ mockitoSession.finishMocking();
+ }
+
+ @Test
+ public void onReceive_whenFlagOffDeviceIsNotTablet_showKeyboardShortcuts() {
+ MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Utilities.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
+ mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+ when(Utilities.isTablet(mContext)).thenReturn(false);
+
+ mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+ verify(mKeyboardShortcuts).showKeyboardShortcuts(anyInt());
+ verify(mKeyboardShortcutListSearch, never()).showKeyboardShortcuts(anyInt());
+ mockitoSession.finishMocking();
+ }
+
+ @Test
+ public void onReceive_whenFlagOnDeviceIsTablet_showKeyboardShortcutListSearch() {
+ MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Utilities.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, true);
+ mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+ when(Utilities.isTablet(mContext)).thenReturn(true);
+
+ mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+ verify(mKeyboardShortcuts, never()).showKeyboardShortcuts(anyInt());
+ verify(mKeyboardShortcutListSearch).showKeyboardShortcuts(anyInt());
+ mockitoSession.finishMocking();
+ }
+
+ @Test
+ public void onReceive_whenFlagOnDeviceIsNotTablet_showKeyboardShortcuts() {
+ MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Utilities.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, true);
+ mKeyboardShortcutsReceiver = spy(new KeyboardShortcutsReceiver(mFeatureFlags));
+ when(Utilities.isTablet(mContext)).thenReturn(false);
+
+ mKeyboardShortcutsReceiver.onReceive(mContext, mIntent);
+
+ verify(mKeyboardShortcuts).showKeyboardShortcuts(anyInt());
+ verify(mKeyboardShortcutListSearch, never()).showKeyboardShortcuts(anyInt());
+ mockitoSession.finishMocking();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java
new file mode 100644
index 000000000000..ea822aa00429
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyboardShortcutsTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Dialog;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardShortcutsTest extends SysuiTestCase {
+
+ @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+ private static int DEVICE_ID = 1;
+ private KeyboardShortcuts mKeyboardShortcuts;
+
+ @Mock private Dialog mDialog;
+ @Mock WindowManager mWindowManager;
+
+ @Before
+ public void setUp() {
+ mKeyboardShortcuts = new KeyboardShortcuts(mContext, mWindowManager);
+ mKeyboardShortcuts.sInstance = mKeyboardShortcuts;
+ mKeyboardShortcuts.mKeyboardShortcutsDialog = mDialog;
+ mKeyboardShortcuts.mContext = mContext;
+ }
+
+ @Test
+ public void toggle_isShowingTrue_instanceShouldBeNull() {
+ when(mDialog.isShowing()).thenReturn(true);
+
+ mKeyboardShortcuts.toggle(mContext, DEVICE_ID);
+
+ assertThat(mKeyboardShortcuts.sInstance).isNull();
+ }
+
+ @Test
+ public void toggle_isShowingFalse_showKeyboardShortcuts() {
+ when(mDialog.isShowing()).thenReturn(false);
+
+ mKeyboardShortcuts.toggle(mContext, DEVICE_ID);
+
+ verify(mWindowManager).requestAppKeyboardShortcuts(any(), anyInt());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
index 55a79da8fab5..ed249471ed27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
@@ -19,10 +19,9 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.app.Notification
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -48,15 +47,14 @@ class DismissibilityCoordinatorTest : SysuiTestCase() {
private lateinit var onBeforeRenderListListener: OnBeforeRenderListListener
private val keyguardStateController: KeyguardStateController = mock()
private val pipeline: NotifPipeline = mock()
- private val flagResolver: SystemUiSystemPropertiesFlags.FlagResolver = mock()
+ private val flags: NotifPipelineFlags = mock()
private val dumpManager: DumpManager = mock()
@Before
fun setUp() {
- setTestFlagResolver(flagResolver)
- whenever(flagResolver.isEnabled(NotificationFlags.ALLOW_DISMISS_ONGOING)).thenReturn(true)
+ whenever(flags.allowDismissOngoing()).thenReturn(true)
- dismissibilityProvider = NotificationDismissibilityProviderImpl(dumpManager)
+ dismissibilityProvider = NotificationDismissibilityProviderImpl(flags, dumpManager)
coordinator = DismissibilityCoordinator(keyguardStateController, dismissibilityProvider)
coordinator.attach(pipeline)
onBeforeRenderListListener = withArgCaptor {
@@ -314,7 +312,7 @@ class DismissibilityCoordinatorTest : SysuiTestCase() {
@Test
fun testFeatureToggleOffNonDismissibleEntry() {
- whenever(flagResolver.isEnabled(NotificationFlags.ALLOW_DISMISS_ONGOING)).thenReturn(false)
+ whenever(flags.allowDismissOngoing()).thenReturn(false)
val entry =
NotificationEntryBuilder()
.setTag("entry")
@@ -331,7 +329,7 @@ class DismissibilityCoordinatorTest : SysuiTestCase() {
@Test
fun testFeatureToggleOffOngoingNotifWhenPhoneIsLocked() {
- whenever(flagResolver.isEnabled(NotificationFlags.ALLOW_DISMISS_ONGOING)).thenReturn(false)
+ whenever(flags.allowDismissOngoing()).thenReturn(false)
whenever(keyguardStateController.isUnlocked).thenReturn(false)
val entry =
NotificationEntryBuilder()
@@ -349,7 +347,7 @@ class DismissibilityCoordinatorTest : SysuiTestCase() {
@Test
fun testFeatureToggleOffOngoingNotifWhenPhoneIsUnLocked() {
- whenever(flagResolver.isEnabled(NotificationFlags.ALLOW_DISMISS_ONGOING)).thenReturn(false)
+ whenever(flags.allowDismissOngoing()).thenReturn(false)
whenever(keyguardStateController.isUnlocked).thenReturn(true)
val entry =
NotificationEntryBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 831d07f3829e..07d0dbd65afb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -741,7 +741,7 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
}
@Test
- public void testShouldFullScreen_snoozed_occluding_withStrictRules() throws Exception {
+ public void testShouldNotFullScreen_snoozed_occluding_withStrictRules() throws Exception {
when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
@@ -753,16 +753,41 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mKeyguardStateController.isOccluded()).thenReturn(true);
assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
- .isEqualTo(FullScreenIntentDecision.FSI_KEYGUARD_OCCLUDED);
+ .isEqualTo(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
- .isTrue();
- verify(mLogger, never()).logNoFullscreen(any(), any());
+ .isFalse();
+ verify(mLogger).logNoFullscreen(entry, "Expected to HUN");
verify(mLogger, never()).logNoFullscreenWarning(any(), any());
- verify(mLogger).logFullscreen(entry, "Expected not to HUN while keyguard occluded");
+ verify(mLogger, never()).logFullscreen(any(), any());
}
@Test
- public void testShouldFullScreen_snoozed_lockedShade_withStrictRules() throws Exception {
+ public void testShouldHeadsUp_snoozed_occluding_withStrictRules() throws Exception {
+ when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+ when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ when(mKeyguardStateController.isOccluded()).thenReturn(true);
+
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+
+ verify(mLogger).logHeadsUpPackageSnoozeBypassedHasFsi(entry);
+ verify(mLogger, never()).logHeadsUp(any());
+
+ assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1);
+ UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0);
+ assertThat(fakeUiEvent.eventId).isEqualTo(
+ NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI.getId());
+ assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid());
+ assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName());
+ }
+
+ @Test
+ public void testShouldNotFullScreen_snoozed_lockedShade_withStrictRules() throws Exception {
when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
@@ -774,12 +799,37 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mKeyguardStateController.isOccluded()).thenReturn(false);
assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
- .isEqualTo(FullScreenIntentDecision.FSI_LOCKED_SHADE);
+ .isEqualTo(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
- .isTrue();
- verify(mLogger, never()).logNoFullscreen(any(), any());
+ .isFalse();
+ verify(mLogger).logNoFullscreen(entry, "Expected to HUN");
verify(mLogger, never()).logNoFullscreenWarning(any(), any());
- verify(mLogger).logFullscreen(entry, "Keyguard is showing and not occluded");
+ verify(mLogger, never()).logFullscreen(any(), any());
+ }
+
+ @Test
+ public void testShouldHeadsUp_snoozed_lockedShade_withStrictRules() throws Exception {
+ when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE_LOCKED);
+ when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ when(mKeyguardStateController.isOccluded()).thenReturn(false);
+
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+
+ verify(mLogger).logHeadsUpPackageSnoozeBypassedHasFsi(entry);
+ verify(mLogger, never()).logHeadsUp(any());
+
+ assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1);
+ UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0);
+ assertThat(fakeUiEvent.eventId).isEqualTo(
+ NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI.getId());
+ assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid());
+ assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName());
}
@Test
@@ -795,21 +845,41 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
when(mKeyguardStateController.isOccluded()).thenReturn(false);
assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
- .isEqualTo(FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD);
+ .isEqualTo(FullScreenIntentDecision.NO_FSI_EXPECTED_TO_HUN);
assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
.isFalse();
- verify(mLogger, never()).logNoFullscreen(any(), any());
- verify(mLogger).logNoFullscreenWarning(entry, "Expected not to HUN while not on keyguard");
+ verify(mLogger).logNoFullscreen(entry, "Expected to HUN");
+ verify(mLogger, never()).logNoFullscreenWarning(any(), any());
verify(mLogger, never()).logFullscreen(any(), any());
+ }
+
+ @Test
+ public void testShouldHeadsUp_snoozed_unlocked_withStrictRules() throws Exception {
+ when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+ when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+ when(mKeyguardStateController.isOccluded()).thenReturn(false);
+
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+
+ verify(mLogger).logHeadsUpPackageSnoozeBypassedHasFsi(entry);
+ verify(mLogger, never()).logHeadsUp(any());
assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1);
UiEventLoggerFake.FakeUiEvent fakeUiEvent = mUiEventLoggerFake.get(0);
assertThat(fakeUiEvent.eventId).isEqualTo(
- NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD.getId());
+ NotificationInterruptEvent.HUN_SNOOZE_BYPASSED_POTENTIALLY_SUPPRESSED_FSI.getId());
assertThat(fakeUiEvent.uid).isEqualTo(entry.getSbn().getUid());
assertThat(fakeUiEvent.packageName).isEqualTo(entry.getSbn().getPackageName());
}
+ /* TODO: Verify the FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD UiEvent some other way. */
+
/**
* Bubbles can happen.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 06053987202c..8b0d4ce1a248 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -327,6 +327,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
// CentralSurfacesImpl's runtime flag check fails if the flag is absent.
// This value is unused, because test manifest is opted in.
mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI, false);
+ // Set default value to avoid IllegalStateException.
+ mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
IThermalService thermalService = mock(IThermalService.class);
mPowerManager = new PowerManager(mContext, mPowerManagerService, thermalService,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
index cc6be5e09fbc..82b80f53d6b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerStartableTest.kt
@@ -92,6 +92,14 @@ class StylusUsiPowerStartableTest : SysuiTestCase() {
}
@Test
+ fun start_registersCallbacks() {
+ startable.start()
+
+ verify(stylusManager, times(1)).registerCallback(startable)
+ verify(stylusManager, times(1)).registerBatteryCallback(startable)
+ }
+
+ @Test
fun onStylusAdded_internal_updatesNotificationSuppression() {
startable.onStylusAdded(STYLUS_DEVICE_ID)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
index fc7436a6b273..586bdc6c8215 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
@@ -27,6 +27,7 @@ import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import android.widget.ImageView
import android.widget.TextView
+import androidx.core.animation.doOnCancel
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.R
@@ -361,6 +362,105 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
}
@Test
+ fun displayView_loading_animationStarted() {
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.id.check_box, null),
+ Text.Loaded("text"),
+ endItem = ChipbarEndItem.Loading,
+ )
+ )
+
+ assertThat(underTest.loadingDetails!!.animator.isStarted).isTrue()
+ }
+
+ @Test
+ fun displayView_notLoading_noAnimation() {
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.id.check_box, null),
+ Text.Loaded("text"),
+ endItem = ChipbarEndItem.Error,
+ )
+ )
+
+ assertThat(underTest.loadingDetails).isNull()
+ }
+
+ @Test
+ fun displayView_loadingThenNotLoading_animationStopped() {
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.id.check_box, null),
+ Text.Loaded("text"),
+ endItem = ChipbarEndItem.Loading,
+ )
+ )
+
+ val animator = underTest.loadingDetails!!.animator
+ var cancelled = false
+ animator.doOnCancel { cancelled = true }
+
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.id.check_box, null),
+ Text.Loaded("text"),
+ endItem = ChipbarEndItem.Button(Text.Loaded("button")) {},
+ )
+ )
+
+ assertThat(cancelled).isTrue()
+ assertThat(underTest.loadingDetails).isNull()
+ }
+
+ @Test
+ fun displayView_loadingThenHideView_animationStopped() {
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.id.check_box, null),
+ Text.Loaded("text"),
+ endItem = ChipbarEndItem.Loading,
+ )
+ )
+
+ val animator = underTest.loadingDetails!!.animator
+ var cancelled = false
+ animator.doOnCancel { cancelled = true }
+
+ underTest.removeView(DEVICE_ID, "TestReason")
+
+ assertThat(cancelled).isTrue()
+ assertThat(underTest.loadingDetails).isNull()
+ }
+
+ @Test
+ fun displayView_loadingThenNewLoading_animationStaysTheSame() {
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.id.check_box, null),
+ Text.Loaded("text"),
+ endItem = ChipbarEndItem.Loading,
+ )
+ )
+
+ val animator = underTest.loadingDetails!!.animator
+ var cancelled = false
+ animator.doOnCancel { cancelled = true }
+
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.id.check_box, null),
+ Text.Loaded("new text"),
+ endItem = ChipbarEndItem.Loading,
+ )
+ )
+
+ assertThat(underTest.loadingDetails!!.animator).isEqualTo(animator)
+ assertThat(underTest.loadingDetails!!.animator.isStarted).isTrue()
+ assertThat(cancelled).isFalse()
+ }
+
+ @Test
fun displayView_vibrationEffect_doubleClickEffect() {
underTest.displayView(
createChipbarInfo(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
index cc23485f4a61..0c119fd90c23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
@@ -384,14 +384,14 @@ class GuestUserInteractorTest : SysuiTestCase() {
UserInfo(
/* id= */ 818,
/* name= */ "non_guest",
- /* flags= */ 0,
+ /* flags= */ UserInfo.FLAG_FULL,
)
private val GUEST_USER_INFO =
UserInfo(
/* id= */ 669,
/* name= */ "guest",
/* iconPath= */ "",
- /* flags= */ 0,
+ /* flags= */ UserInfo.FLAG_FULL,
UserManager.USER_TYPE_FULL_GUEST,
)
private val EPHEMERAL_GUEST_USER_INFO =
@@ -399,7 +399,7 @@ class GuestUserInteractorTest : SysuiTestCase() {
/* id= */ 669,
/* name= */ "guest",
/* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_EPHEMERAL,
+ /* flags= */ UserInfo.FLAG_EPHEMERAL or UserInfo.FLAG_FULL,
UserManager.USER_TYPE_FULL_GUEST,
)
private val ALL_USERS =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index 3538d9b02577..22d05bf5106a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -28,7 +28,6 @@ import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
import androidx.test.filters.SmallTest
-import com.android.internal.R.drawable.ic_account_circle
import com.android.internal.logging.UiEventLogger
import com.android.systemui.GuestResetOrExitSessionReceiver
import com.android.systemui.GuestResumeSessionReceiver
@@ -89,6 +88,7 @@ class UserInteractorTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var manager: UserManager
+ @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
@Mock private lateinit var activityManager: ActivityManager
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
@@ -147,6 +147,7 @@ class UserInteractorTest : SysuiTestCase() {
featureFlags = featureFlags,
),
manager = manager,
+ headlessSystemUserMode = headlessSystemUserMode,
applicationScope = testScope.backgroundScope,
telephonyInteractor =
TelephonyInteractor(
@@ -890,6 +891,50 @@ class UserInteractorTest : SysuiTestCase() {
assertThat(selectedUser()).isNotNull()
}
+ @Test
+ fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled() =
+ testScope.runTest {
+ keyguardRepository.setKeyguardShowing(true)
+ whenever(manager.getUserSwitchability(any()))
+ .thenReturn(UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED)
+ val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList()
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[1])
+ userRepository.setSettings(
+ UserSwitcherSettingsModel(
+ isUserSwitcherEnabled = true,
+ isAddUsersFromLockscreen = true
+ )
+ )
+
+ runCurrent()
+ underTest.userRecords.value
+ .filter { it.info == null }
+ .forEach { action -> assertThat(action.isSwitchToEnabled).isFalse() }
+ }
+
+ @Test
+ fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled_HeadlessMode() =
+ testScope.runTest {
+ keyguardRepository.setKeyguardShowing(true)
+ whenever(headlessSystemUserMode.isHeadlessSystemUserMode()).thenReturn(true)
+ whenever(manager.isUserUnlocked(anyInt())).thenReturn(false)
+ val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList()
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[1])
+ userRepository.setSettings(
+ UserSwitcherSettingsModel(
+ isUserSwitcherEnabled = true,
+ isAddUsersFromLockscreen = true
+ )
+ )
+
+ runCurrent()
+ underTest.userRecords.value
+ .filter { it.info == null }
+ .forEach { action -> assertThat(action.isSwitchToEnabled).isFalse() }
+ }
+
private fun assertUsers(
models: List<UserModel>?,
count: Int,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
index 8f0375f83141..2f05e65267ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
@@ -41,6 +41,7 @@ import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.domain.interactor.GuestUserInteractor
+import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
import com.android.systemui.user.domain.interactor.UserInteractor
import com.android.systemui.util.mockito.mock
@@ -71,6 +72,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var activityManager: ActivityManager
@Mock private lateinit var manager: UserManager
+ @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Mock private lateinit var uiEventLogger: UiEventLogger
@@ -252,6 +254,7 @@ class StatusBarUserChipViewModelTest : SysuiTestCase() {
),
featureFlags = featureFlags,
manager = manager,
+ headlessSystemUserMode = headlessSystemUserMode,
applicationScope = testScope.backgroundScope,
telephonyInteractor =
TelephonyInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 71a112cfdbd4..9268904ab15e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -41,6 +41,7 @@ import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.domain.interactor.GuestUserInteractor
+import com.android.systemui.user.domain.interactor.HeadlessSystemUserMode
import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
import com.android.systemui.user.domain.interactor.UserInteractor
import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
@@ -72,6 +73,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var activityManager: ActivityManager
@Mock private lateinit var manager: UserManager
+ @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
@Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
@Mock private lateinit var uiEventLogger: UiEventLogger
@@ -154,6 +156,7 @@ class UserSwitcherViewModelTest : SysuiTestCase() {
),
featureFlags = featureFlags,
manager = manager,
+ headlessSystemUserMode = headlessSystemUserMode,
applicationScope = testScope.backgroundScope,
telephonyInteractor =
TelephonyInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 185d40879441..e185922d47d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -82,8 +82,6 @@ import android.view.WindowManager;
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
@@ -285,7 +283,7 @@ public class BubblesTest extends SysuiTestCase {
@Mock
private ShadeWindowLogger mShadeWindowLogger;
@Mock
- private SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver;
+ private NotifPipelineFlags mNotifPipelineFlags;
private TestableBubblePositioner mPositioner;
@@ -298,8 +296,6 @@ public class BubblesTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- setTestFlagResolver(mFlagResolver);
-
mTestableLooper = TestableLooper.get(this);
// For the purposes of this test, just run everything synchronously
@@ -318,24 +314,6 @@ public class BubblesTest extends SysuiTestCase {
mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
mNotificationShadeWindowController.attach();
- // Need notifications for bubbles
- mNotificationTestHelper = new NotificationTestHelper(
- mContext,
- mDependency,
- TestableLooper.get(this));
- mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
- mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
- mNonBubbleNotifRow = mNotificationTestHelper.createRow();
- mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow);
- mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2);
-
- UserHandle handle = mock(UserHandle.class);
- when(handle.getIdentifier()).thenReturn(11);
- mBubbleEntryUser11 = BubblesManager.notifToBubbleEntry(
- mNotificationTestHelper.createBubble(handle));
- mBubbleEntry2User11 = BubblesManager.notifToBubbleEntry(
- mNotificationTestHelper.createBubble(handle));
-
mAppBubbleIntent = new Intent(mContext, BubblesTestActivity.class);
mAppBubbleIntent.setPackage(mContext.getPackageName());
@@ -420,9 +398,28 @@ public class BubblesTest extends SysuiTestCase {
mNotifPipeline,
mSysUiState,
mock(FeatureFlags.class),
+ mNotifPipelineFlags,
syncExecutor);
mBubblesManager.addNotifCallback(mNotifCallback);
+ // Need notifications for bubbles
+ mNotificationTestHelper = new NotificationTestHelper(
+ mContext,
+ mDependency,
+ TestableLooper.get(this));
+ mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
+ mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
+ mNonBubbleNotifRow = mNotificationTestHelper.createRow();
+ mBubbleEntry = mBubblesManager.notifToBubbleEntry(mRow);
+ mBubbleEntry2 = mBubblesManager.notifToBubbleEntry(mRow2);
+
+ UserHandle handle = mock(UserHandle.class);
+ when(handle.getIdentifier()).thenReturn(11);
+ mBubbleEntryUser11 = mBubblesManager.notifToBubbleEntry(
+ mNotificationTestHelper.createBubble(handle));
+ mBubbleEntry2User11 = mBubblesManager.notifToBubbleEntry(
+ mNotificationTestHelper.createBubble(handle));
+
// Get a reference to the BubbleController's entry listener
verify(mNotifPipeline, atLeastOnce())
.addCollectionListener(mNotifListenerCaptor.capture());
@@ -1185,7 +1182,7 @@ public class BubblesTest extends SysuiTestCase {
@Test
public void testDeleteShortcutsDeletesXml() throws Exception {
ExpandableNotificationRow row = mNotificationTestHelper.createShortcutBubble("shortcutId");
- BubbleEntry shortcutBubbleEntry = BubblesManager.notifToBubbleEntry(row.getEntry());
+ BubbleEntry shortcutBubbleEntry = mBubblesManager.notifToBubbleEntry(row.getEntry());
mBubbleController.updateBubble(shortcutBubbleEntry);
mBubbleData.dismissBubbleWithKey(shortcutBubbleEntry.getKey(),
@@ -1297,7 +1294,7 @@ public class BubblesTest extends SysuiTestCase {
entry.getChannel().setConversationId(
row.getEntry().getChannel().getParentChannelId(),
"shortcutId");
- mBubbleController.updateBubble(BubblesManager.notifToBubbleEntry(row.getEntry()));
+ mBubbleController.updateBubble(mBubblesManager.notifToBubbleEntry(row.getEntry()));
assertTrue(mBubbleController.hasBubbles());
// Overflow it
@@ -1323,7 +1320,7 @@ public class BubblesTest extends SysuiTestCase {
entry.getChannel().setConversationId(
row.getEntry().getChannel().getParentChannelId(),
"shortcutId");
- mBubbleController.updateBubble(BubblesManager.notifToBubbleEntry(row.getEntry()));
+ mBubbleController.updateBubble(mBubblesManager.notifToBubbleEntry(row.getEntry()));
assertTrue(mBubbleController.hasBubbles());
// Overflow it
@@ -1706,13 +1703,13 @@ public class BubblesTest extends SysuiTestCase {
@Test
public void testCreateBubbleFromOngoingNotification_OngoingDismissalEnabled() {
- when(mFlagResolver.isEnabled(NotificationFlags.ALLOW_DISMISS_ONGOING)).thenReturn(true);
+ when(mNotifPipelineFlags.allowDismissOngoing()).thenReturn(true);
NotificationEntry notif = new NotificationEntryBuilder()
.setFlag(mContext, Notification.FLAG_ONGOING_EVENT, true)
.setCanBubble(true)
.build();
- BubbleEntry bubble = BubblesManager.notifToBubbleEntry(notif);
+ BubbleEntry bubble = mBubblesManager.notifToBubbleEntry(notif);
assertTrue("Ongoing Notifis should be dismissable", bubble.isDismissable());
}
@@ -1720,13 +1717,13 @@ public class BubblesTest extends SysuiTestCase {
@Test
public void testCreateBubbleFromNoDismissNotification_OngoingDismissalEnabled() {
- when(mFlagResolver.isEnabled(NotificationFlags.ALLOW_DISMISS_ONGOING)).thenReturn(true);
+ when(mNotifPipelineFlags.allowDismissOngoing()).thenReturn(true);
NotificationEntry notif = new NotificationEntryBuilder()
.setFlag(mContext, Notification.FLAG_NO_DISMISS, true)
.setCanBubble(true)
.build();
- BubbleEntry bubble = BubblesManager.notifToBubbleEntry(notif);
+ BubbleEntry bubble = mBubblesManager.notifToBubbleEntry(notif);
assertFalse("FLAG_NO_DISMISS Notifs should be non-dismissable", bubble.isDismissable());
}
@@ -1738,7 +1735,7 @@ public class BubblesTest extends SysuiTestCase {
.setCanBubble(true)
.build();
- BubbleEntry bubble = BubblesManager.notifToBubbleEntry(notif);
+ BubbleEntry bubble = mBubblesManager.notifToBubbleEntry(notif);
assertFalse(
"Ongoing Notifis should be dismissable, if the feature is off",
@@ -1754,7 +1751,7 @@ public class BubblesTest extends SysuiTestCase {
.setCanBubble(true)
.build();
- BubbleEntry bubble = BubblesManager.notifToBubbleEntry(notif);
+ BubbleEntry bubble = mBubblesManager.notifToBubbleEntry(notif);
assertTrue(
"FLAG_NO_DISMISS should be ignored, if the feature is off",
@@ -1772,7 +1769,7 @@ public class BubblesTest extends SysuiTestCase {
workEntry.setBubbleMetadata(getMetadata());
workEntry.setFlagBubble(true);
- return new Bubble(BubblesManager.notifToBubbleEntry(workEntry),
+ return new Bubble(mBubblesManager.notifToBubbleEntry(workEntry),
null,
mock(Bubbles.PendingIntentCanceledListener.class), new SyncExecutor());
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index c236bc90f42c..1bab99787de4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -34,7 +34,6 @@ import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.animation.DialogLaunchAnimator;
@@ -145,7 +144,6 @@ public abstract class SysuiTestCase {
disallowTestableLooperAsMainThread();
mContext.cleanUpReceivers(this.getClass().getSimpleName());
mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName());
- setTestFlagResolver(null);
}
@AfterClass
@@ -208,10 +206,6 @@ public abstract class SysuiTestCase {
}
}
- protected void setTestFlagResolver(SystemUiSystemPropertiesFlags.FlagResolver flagResolver) {
- SystemUiSystemPropertiesFlags.TEST_RESOLVER = flagResolver;
- }
-
public static void waitForIdleSync(Handler h) {
validateThread(h.getLooper());
Idler idler = new Idler(null);
diff --git a/services/api/current.txt b/services/api/current.txt
index e7299efc5b61..5c7b9476b131 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -85,69 +85,72 @@ package com.android.server.pm.pkg {
method @Nullable public String getAppComponentFactory();
method @Nullable public String getApplicationClassName();
method @Nullable public String getBackupAgentName();
- method @DrawableRes public int getBannerRes();
+ method @DrawableRes public int getBannerResourceId();
method public int getBaseRevisionCode();
method public int getCategory();
method @Nullable public String getClassLoaderName();
method @Dimension(unit=android.annotation.Dimension.DP) public int getCompatibleWidthLimitDp();
- method @XmlRes public int getDataExtractionRulesRes();
- method @StringRes public int getDescriptionRes();
- method @XmlRes public int getFullBackupContentRes();
+ method @XmlRes public int getDataExtractionRulesResourceId();
+ method @StringRes public int getDescriptionResourceId();
+ method @XmlRes public int getFullBackupContentResourceId();
method public int getGwpAsanMode();
- method @DrawableRes public int getIconRes();
- method @StringRes public int getLabelRes();
+ method @DrawableRes public int getIconResourceId();
+ method @StringRes public int getLabelResourceId();
method @Dimension(unit=android.annotation.Dimension.DP) public int getLargestWidthLimitDp();
method @NonNull public java.util.List<java.lang.String> getLibraryNames();
- method @XmlRes public int getLocaleConfigRes();
- method @DrawableRes public int getLogoRes();
+ method @XmlRes public int getLocaleConfigResourceId();
+ method @DrawableRes public int getLogoResourceId();
method public long getLongVersionCode();
method public float getMaxAspectRatio();
method public float getMinAspectRatio();
method public int getNativeHeapZeroInitialized();
- method @XmlRes public int getNetworkSecurityConfigRes();
+ method @XmlRes public int getNetworkSecurityConfigResourceId();
method @Nullable public String getRequiredAccountType();
method @Dimension(unit=android.annotation.Dimension.DP) public int getRequiresSmallestWidthDp();
method @Nullable public String getRestrictedAccountType();
- method @DrawableRes public int getRoundIconRes();
+ method @DrawableRes public int getRoundIconResourceId();
method @Nullable public String getSdkLibraryName();
method @Nullable public String getSharedUserId();
- method @StringRes public int getSharedUserLabelRes();
+ method @StringRes public int getSharedUserLabelResourceId();
method @NonNull public java.util.List<com.android.server.pm.pkg.AndroidPackageSplit> getSplits();
method @Nullable public String getStaticSharedLibraryName();
method @NonNull public java.util.UUID getStorageUuid();
method public int getTargetSdkVersion();
- method @StyleRes public int getThemeRes();
+ method @StyleRes public int getThemeResourceId();
method public int getUiOptions();
method @Nullable public String getVersionName();
method @Nullable public String getZygotePreloadName();
+ method public boolean is32BitAbiPreferred();
method public boolean isAllowAudioPlaybackCapture();
- method public boolean isAllowBackup();
- method public boolean isAllowClearUserData();
- method public boolean isAllowClearUserDataOnFailedRestore();
method public boolean isAllowNativeHeapPointerTagging();
- method public boolean isAllowTaskReparenting();
method public boolean isAnyDensity();
method public boolean isAttributionsUserVisible();
+ method public boolean isBackupAllowed();
method public boolean isBackupInForeground();
- method public boolean isCantSaveState();
+ method public boolean isClearUserDataAllowed();
+ method public boolean isClearUserDataOnFailedRestoreAllowed();
+ method public boolean isCleartextTrafficAllowed();
method public boolean isCoreApp();
method public boolean isCrossProfile();
method public boolean isDebuggable();
+ method public boolean isDeclaredHavingCode();
method public boolean isDefaultToDeviceProtectedStorage();
method public boolean isDirectBootAware();
- method public boolean isExtractNativeLibs();
+ method public boolean isExtraLargeScreensSupported();
+ method public boolean isExtractNativeLibrariesRequested();
method public boolean isFactoryTest();
method public boolean isForceQueryable();
method public boolean isFullBackupOnly();
method public boolean isHardwareAccelerated();
- method public boolean isHasCode();
- method public boolean isHasFragileUserData();
method public boolean isIsolatedSplitLoading();
- method public boolean isKillAfterRestore();
+ method public boolean isKillAfterRestoreAllowed();
method public boolean isLargeHeap();
+ method public boolean isLargeScreensSupported();
method public boolean isLeavingSharedUser();
method public boolean isMultiArch();
method public boolean isNativeLibraryRootRequiresIsa();
+ method public boolean isNonSdkApiRequested();
+ method public boolean isNormalScreensSupported();
method public boolean isOnBackInvokedCallbackEnabled();
method public boolean isPersistent();
method public boolean isProfileable();
@@ -157,17 +160,14 @@ package com.android.server.pm.pkg {
method public boolean isResetEnabledSettingsOnAppDataCleared();
method public boolean isResourceOverlay();
method public boolean isRestoreAnyVersion();
+ method public boolean isRtlSupported();
+ method public boolean isSaveStateDisallowed();
method public boolean isSignedWithPlatformKey();
- method public boolean isSupportsExtraLargeScreens();
- method public boolean isSupportsLargeScreens();
- method public boolean isSupportsNormalScreens();
- method public boolean isSupportsRtl();
- method public boolean isSupportsSmallScreens();
+ method public boolean isSmallScreensSupported();
+ method public boolean isTaskReparentingAllowed();
method public boolean isTestOnly();
- method public boolean isUse32BitAbi();
method public boolean isUseEmbeddedDex();
- method public boolean isUsesCleartextTraffic();
- method public boolean isUsesNonSdkApi();
+ method public boolean isUserDataFragile();
method public boolean isVmSafeMode();
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 24d7c901ceeb..598521f31ff5 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1458,7 +1458,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (((response.getDatasets() == null || response.getDatasets().isEmpty())
&& response.getAuthentication() == null)
|| autofillDisabled) {
- // Response is "empty" from an UI point of view, need to notify client.
+ // Response is "empty" from a UI point of view, need to notify client.
notifyUnavailableToClient(
autofillDisabled ? AutofillManager.STATE_DISABLED_BY_SERVICE : 0,
/* autofillableIds= */ null);
@@ -4283,7 +4283,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mService.resetLastResponse();
- // The default autofill service cannot fullfill the request, let's check if the augmented
+ // The default autofill service cannot fulfill the request, let's check if the augmented
// autofill service can.
mAugmentedAutofillDestroyer = triggerAugmentedAutofillLocked(flags);
if (mAugmentedAutofillDestroyer == null && ((flags & FLAG_PASSWORD_INPUT_TYPE) == 0)) {
diff --git a/services/companion/java/com/android/server/companion/virtual/SensorController.java b/services/companion/java/com/android/server/companion/virtual/SensorController.java
index ec7e993ec30e..7804ebf1583d 100644
--- a/services/companion/java/com/android/server/companion/virtual/SensorController.java
+++ b/services/companion/java/com/android/server/companion/virtual/SensorController.java
@@ -17,7 +17,9 @@
package com.android.server.companion.virtual;
import android.annotation.NonNull;
-import android.companion.virtual.sensor.IVirtualSensorStateChangeCallback;
+import android.annotation.Nullable;
+import android.companion.virtual.sensor.IVirtualSensorCallback;
+import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.os.IBinder;
@@ -40,17 +42,30 @@ public class SensorController {
private static final String TAG = "SensorController";
+ // See system/core/libutils/include/utils/Errors.h
+ private static final int OK = 0;
+ private static final int UNKNOWN_ERROR = (-2147483647 - 1); // INT32_MIN value
+ private static final int BAD_VALUE = -22;
+
private final Object mLock;
private final int mVirtualDeviceId;
@GuardedBy("mLock")
private final Map<IBinder, SensorDescriptor> mSensorDescriptors = new ArrayMap<>();
+ @NonNull
+ private final SensorManagerInternal.RuntimeSensorCallback mRuntimeSensorCallback;
private final SensorManagerInternal mSensorManagerInternal;
+ private final VirtualDeviceManagerInternal mVdmInternal;
+
- public SensorController(@NonNull Object lock, int virtualDeviceId) {
+
+ public SensorController(@NonNull Object lock, int virtualDeviceId,
+ @Nullable IVirtualSensorCallback virtualSensorCallback) {
mLock = lock;
mVirtualDeviceId = virtualDeviceId;
+ mRuntimeSensorCallback = new RuntimeSensorCallbackWrapper(virtualSensorCallback);
mSensorManagerInternal = LocalServices.getService(SensorManagerInternal.class);
+ mVdmInternal = LocalServices.getService(VirtualDeviceManagerInternal.class);
}
void close() {
@@ -67,36 +82,23 @@ public class SensorController {
}
}
- void createSensor(@NonNull IBinder deviceToken, @NonNull VirtualSensorConfig config) {
- Objects.requireNonNull(deviceToken);
+ int createSensor(@NonNull IBinder sensorToken, @NonNull VirtualSensorConfig config) {
+ Objects.requireNonNull(sensorToken);
Objects.requireNonNull(config);
try {
- createSensorInternal(deviceToken, config);
+ return createSensorInternal(sensorToken, config);
} catch (SensorCreationException e) {
throw new RuntimeException(
"Failed to create virtual sensor '" + config.getName() + "'.", e);
}
}
- private void createSensorInternal(IBinder deviceToken, VirtualSensorConfig config)
+ private int createSensorInternal(IBinder sensorToken, VirtualSensorConfig config)
throws SensorCreationException {
- final SensorManagerInternal.RuntimeSensorStateChangeCallback runtimeSensorCallback =
- (enabled, samplingPeriodMicros, batchReportLatencyMicros) -> {
- IVirtualSensorStateChangeCallback callback = config.getStateChangeCallback();
- if (callback != null) {
- try {
- callback.onStateChanged(
- enabled, samplingPeriodMicros, batchReportLatencyMicros);
- } catch (RemoteException e) {
- throw new RuntimeException("Failed to call sensor callback.", e);
- }
- }
- };
-
final int handle = mSensorManagerInternal.createRuntimeSensor(mVirtualDeviceId,
config.getType(), config.getName(),
config.getVendor() == null ? "" : config.getVendor(),
- runtimeSensorCallback);
+ mRuntimeSensorCallback);
if (handle <= 0) {
throw new SensorCreationException("Received an invalid virtual sensor handle.");
}
@@ -104,8 +106,8 @@ public class SensorController {
// The handle is valid from here, so ensure that all failures clean it up.
final BinderDeathRecipient binderDeathRecipient;
try {
- binderDeathRecipient = new BinderDeathRecipient(deviceToken);
- deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0);
+ binderDeathRecipient = new BinderDeathRecipient(sensorToken);
+ sensorToken.linkToDeath(binderDeathRecipient, /* flags= */ 0);
} catch (RemoteException e) {
mSensorManagerInternal.removeRuntimeSensor(handle);
throw new SensorCreationException("Client died before sensor could be created.", e);
@@ -114,8 +116,9 @@ public class SensorController {
synchronized (mLock) {
SensorDescriptor sensorDescriptor = new SensorDescriptor(
handle, config.getType(), config.getName(), binderDeathRecipient);
- mSensorDescriptors.put(deviceToken, sensorDescriptor);
+ mSensorDescriptors.put(sensorToken, sensorDescriptor);
}
+ return handle;
}
boolean sendSensorEvent(@NonNull IBinder token, @NonNull VirtualSensorEvent event) {
@@ -178,6 +181,39 @@ public class SensorController {
}
}
+ private final class RuntimeSensorCallbackWrapper
+ implements SensorManagerInternal.RuntimeSensorCallback {
+ @Nullable
+ private IVirtualSensorCallback mCallback;
+
+ RuntimeSensorCallbackWrapper(@Nullable IVirtualSensorCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public int onConfigurationChanged(int handle, boolean enabled, int samplingPeriodMicros,
+ int batchReportLatencyMicros) {
+ if (mCallback == null) {
+ Slog.e(TAG, "No sensor callback configured for sensor handle " + handle);
+ return BAD_VALUE;
+ }
+ VirtualSensor sensor = mVdmInternal.getVirtualSensor(mVirtualDeviceId, handle);
+ if (sensor == null) {
+ Slog.e(TAG, "No sensor found for deviceId=" + mVirtualDeviceId
+ + " and sensor handle=" + handle);
+ return BAD_VALUE;
+ }
+ try {
+ mCallback.onConfigurationChanged(sensor, enabled, samplingPeriodMicros,
+ batchReportLatencyMicros);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to call sensor callback: " + e);
+ return UNKNOWN_ERROR;
+ }
+ return OK;
+ }
+ }
+
@VisibleForTesting
static final class SensorDescriptor {
@@ -207,10 +243,10 @@ public class SensorController {
}
private final class BinderDeathRecipient implements IBinder.DeathRecipient {
- private final IBinder mDeviceToken;
+ private final IBinder mSensorToken;
- BinderDeathRecipient(IBinder deviceToken) {
- mDeviceToken = deviceToken;
+ BinderDeathRecipient(IBinder sensorToken) {
+ mSensorToken = sensorToken;
}
@Override
@@ -219,7 +255,7 @@ public class SensorController {
// quitting, which removes this death recipient. If this is invoked, the remote end
// died, or they disposed of the object without properly unregistering.
Slog.e(TAG, "Virtual sensor controller binder died");
- unregisterSensor(mDeviceToken);
+ unregisterSensor(mSensorToken);
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 7fce44237720..b4dcf43c2e1a 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -41,6 +41,7 @@ import android.companion.virtual.VirtualDeviceManager.ActivityListener;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.audio.IAudioConfigChangedCallback;
import android.companion.virtual.audio.IAudioRoutingCallback;
+import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.content.ComponentName;
@@ -86,6 +87,8 @@ import com.android.server.companion.virtual.audio.VirtualAudioController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -131,6 +134,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@GuardedBy("mVirtualDeviceLock")
@Nullable
private LocaleList mLocaleList = null;
+ // This device's sensors, keyed by sensor handle.
+ @GuardedBy("mVirtualDeviceLock")
+ private SparseArray<VirtualSensor> mVirtualSensors = new SparseArray<>();
+ @GuardedBy("mVirtualDeviceLock")
+ private List<VirtualSensor> mVirtualSensorList = null;
private ActivityListener createListenerAdapter() {
return new ActivityListener() {
@@ -240,10 +248,15 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mInputController = inputController;
}
if (sensorController == null) {
- mSensorController = new SensorController(mVirtualDeviceLock, mDeviceId);
+ mSensorController = new SensorController(
+ mVirtualDeviceLock, mDeviceId, mParams.getVirtualSensorCallback());
} else {
mSensorController = sensorController;
}
+ final List<VirtualSensorConfig> virtualSensorConfigs = mParams.getVirtualSensorConfigs();
+ for (int i = 0; i < virtualSensorConfigs.size(); ++i) {
+ createVirtualSensor(virtualSensorConfigs.get(i));
+ }
mCameraAccessController = cameraAccessController;
mCameraAccessController.startObservingIfNeeded();
mOnDeviceCloseListener = onDeviceCloseListener;
@@ -384,6 +397,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mVirtualAudioController = null;
}
mLocaleList = null;
+ mVirtualSensorList = null;
+ mVirtualSensors.clear();
}
mOnDeviceCloseListener.onClose(mDeviceId);
mAppToken.unlinkToDeath(this, 0);
@@ -698,17 +713,17 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
}
- @Override // Binder call
- @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
- public void createVirtualSensor(
- @NonNull IBinder deviceToken,
- @NonNull VirtualSensorConfig config) {
- super.createVirtualSensor_enforcePermission();
- Objects.requireNonNull(config);
- Objects.requireNonNull(deviceToken);
+ private void createVirtualSensor(@NonNull VirtualSensorConfig config) {
+ final IBinder sensorToken =
+ new Binder("android.hardware.sensor.VirtualSensor:" + config.getName());
final long ident = Binder.clearCallingIdentity();
try {
- mSensorController.createSensor(deviceToken, config);
+ int handle = mSensorController.createSensor(sensorToken, config);
+ VirtualSensor sensor = new VirtualSensor(handle, config.getType(), config.getName(),
+ this, sensorToken);
+ synchronized (mVirtualDeviceLock) {
+ mVirtualSensors.put(handle, sensor);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -716,13 +731,24 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
@Override // Binder call
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
- public void unregisterSensor(@NonNull IBinder token) {
- super.unregisterSensor_enforcePermission();
- final long ident = Binder.clearCallingIdentity();
- try {
- mSensorController.unregisterSensor(token);
- } finally {
- Binder.restoreCallingIdentity(ident);
+ @Nullable
+ public List<VirtualSensor> getVirtualSensorList() {
+ super.getVirtualSensorList_enforcePermission();
+ synchronized (mVirtualDeviceLock) {
+ if (mVirtualSensorList == null) {
+ mVirtualSensorList = new ArrayList<>();
+ for (int i = 0; i < mVirtualSensors.size(); ++i) {
+ mVirtualSensorList.add(mVirtualSensors.valueAt(i));
+ }
+ mVirtualSensorList = Collections.unmodifiableList(mVirtualSensorList);
+ }
+ return mVirtualSensorList;
+ }
+ }
+
+ VirtualSensor getVirtualSensorByHandle(int handle) {
+ synchronized (mVirtualDeviceLock) {
+ return mVirtualSensors.get(handle);
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index f39c32df1844..9bb05a6bfe5d 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -34,6 +34,7 @@ import android.companion.virtual.IVirtualDeviceSoundEffectListener;
import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
+import android.companion.virtual.sensor.VirtualSensor;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManagerInternal;
@@ -470,6 +471,17 @@ public class VirtualDeviceManagerService extends SystemService {
}
@Override
+ public @Nullable VirtualSensor getVirtualSensor(int deviceId, int handle) {
+ synchronized (mVirtualDeviceManagerLock) {
+ VirtualDeviceImpl virtualDevice = mVirtualDevices.get(deviceId);
+ if (virtualDevice != null) {
+ return virtualDevice.getVirtualSensorByHandle(handle);
+ }
+ }
+ return null;
+ }
+
+ @Override
public @NonNull ArraySet<Integer> getDeviceIdsForUid(int uid) {
ArraySet<Integer> result = new ArraySet<>();
synchronized (mVirtualDeviceManagerLock) {
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 6fb5730a05e3..26d0860c73cf 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1329,6 +1329,11 @@ public abstract class PackageManagerInternal {
/** @deprecated For legacy shell command only. */
@Deprecated
+ public abstract void legacyForceDexOpt(@NonNull String packageName)
+ throws LegacyDexoptDisabledException;
+
+ /** @deprecated For legacy shell command only. */
+ @Deprecated
public abstract void legacyReconcileSecondaryDexFiles(String packageName)
throws LegacyDexoptDisabledException;
}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 54c47b2faec0..669dcfc7424c 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -892,9 +892,9 @@ public final class BatteryService extends SystemService {
pw.println("Battery service (battery) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" get [-f] [ac|usb|wireless|status|level|temp|present|counter|invalid]");
- pw.println(
- " set [-f] [ac|usb|wireless|status|level|temp|present|counter|invalid] <value>");
+ pw.println(" get [-f] [ac|usb|wireless|dock|status|level|temp|present|counter|invalid]");
+ pw.println(" set [-f] "
+ + "[ac|usb|wireless|dock|status|level|temp|present|counter|invalid] <value>");
pw.println(" Force a battery property value, freezing battery state.");
pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
pw.println(" unplug [-f]");
@@ -954,6 +954,9 @@ public final class BatteryService extends SystemService {
case "wireless":
pw.println(mHealthInfo.chargerWirelessOnline);
break;
+ case "dock":
+ pw.println(mHealthInfo.chargerDockOnline);
+ break;
case "status":
pw.println(mHealthInfo.batteryStatus);
break;
@@ -1008,6 +1011,9 @@ public final class BatteryService extends SystemService {
case "wireless":
mHealthInfo.chargerWirelessOnline = Integer.parseInt(value) != 0;
break;
+ case "dock":
+ mHealthInfo.chargerDockOnline = Integer.parseInt(value) != 0;
+ break;
case "status":
mHealthInfo.batteryStatus = Integer.parseInt(value);
break;
@@ -1085,6 +1091,7 @@ public final class BatteryService extends SystemService {
mHealthInfo.chargerAcOnline = false;
mHealthInfo.chargerUsbOnline = false;
mHealthInfo.chargerWirelessOnline = false;
+ mHealthInfo.chargerDockOnline = false;
mUpdatesStopped = true;
Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw));
}
@@ -1127,6 +1134,7 @@ public final class BatteryService extends SystemService {
pw.println(" AC powered: " + mHealthInfo.chargerAcOnline);
pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline);
pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline);
+ pw.println(" Dock powered: " + mHealthInfo.chargerDockOnline);
pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrentMicroamps);
pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltageMicrovolts);
pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounterUah);
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index eafd3e0ab3e7..9d0736557d3e 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -263,26 +263,26 @@ public class BinaryTransparencyService extends SystemService {
Map<Integer, byte[]> contentDigests = computeApkContentDigest(apkPath);
if (contentDigests == null) {
Slog.d(TAG, "Failed to compute content digest for " + apkPath);
- return new Checksum(0, new byte[] { -1 });
- }
-
- // in this iteration, we'll be supporting only 2 types of digests:
- // CHUNKED_SHA256 and CHUNKED_SHA512.
- // And only one of them will be available per package.
- if (contentDigests.containsKey(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)) {
- return new Checksum(
- Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256,
- contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256));
- } else if (contentDigests.containsKey(
- ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)) {
- return new Checksum(
- Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512,
- contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512));
} else {
- // TODO(b/259423111): considering putting the raw values for the algorithm & digest
- // into the bundle to track potential other digest algorithms that may be in use
- return new Checksum(0, new byte[] { -1 });
+ // in this iteration, we'll be supporting only 2 types of digests:
+ // CHUNKED_SHA256 and CHUNKED_SHA512.
+ // And only one of them will be available per package.
+ if (contentDigests.containsKey(
+ ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256)) {
+ return new Checksum(
+ Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256,
+ contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256));
+ } else if (contentDigests.containsKey(
+ ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512)) {
+ return new Checksum(
+ Checksum.TYPE_PARTIAL_MERKLE_ROOT_1M_SHA512,
+ contentDigests.get(ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512));
+ }
}
+ // When something went wrong, fall back to simple sha256.
+ byte[] digest = PackageUtils.computeSha256DigestForLargeFileAsBytes(apkPath,
+ PackageUtils.createLargeFileBuffer());
+ return new Checksum(Checksum.TYPE_WHOLE_SHA256, digest);
}
@@ -1199,7 +1199,7 @@ public class BinaryTransparencyService extends SystemService {
}
/**
- * JobService to measure all covered binaries and record result to Westworld.
+ * JobService to measure all covered binaries and record results to statsd.
*/
public static class UpdateMeasurementsJobService extends JobService {
private static long sTimeLastRanMs = 0;
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 2aeaa2f704a2..13f327c4bae0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -260,6 +260,10 @@ final class ActivityManagerConstants extends ContentObserver {
*/
private static final String KEY_LOW_SWAP_THRESHOLD_PERCENT = "low_swap_threshold_percent";
+ /** Default value for mFlagApplicationStartInfoEnabled. Defaults to false. */
+ private static final String KEY_DEFAULT_APPLICATION_START_INFO_ENABLED =
+ "enable_app_start_info";
+
/**
* Default value for mFlagBackgroundActivityStartsEnabled if not explicitly set in
* Settings.Global. This allows it to be set experimentally unless it has been
@@ -550,6 +554,9 @@ final class ActivityManagerConstants extends ContentObserver {
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
volatile boolean mFlagActivityStartsLoggingEnabled;
+ // Indicates whether ApplicationStartInfo is enabled.
+ volatile boolean mFlagApplicationStartInfoEnabled;
+
// Indicates whether the background activity starts is enabled.
// Controlled by Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED.
// If not set explicitly the default is controlled by DeviceConfig.
@@ -996,6 +1003,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_MAX_CACHED_PROCESSES:
updateMaxCachedProcesses();
break;
+ case KEY_DEFAULT_APPLICATION_START_INFO_ENABLED:
+ updateApplicationStartInfoEnabled();
+ break;
case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED:
updateBackgroundActivityStarts();
break;
@@ -1390,6 +1400,14 @@ final class ActivityManagerConstants extends ContentObserver {
Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 1) == 1;
}
+ private void updateApplicationStartInfoEnabled() {
+ mFlagApplicationStartInfoEnabled =
+ DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_DEFAULT_APPLICATION_START_INFO_ENABLED,
+ /*defaultValue*/ false);
+ }
+
private void updateBackgroundActivityStarts() {
mFlagBackgroundActivityStartsEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1970,6 +1988,10 @@ final class ActivityManagerConstants extends ContentObserver {
pw.println(mFgToBgFgsGraceDuration);
pw.print(" "); pw.print(KEY_FGS_START_FOREGROUND_TIMEOUT); pw.print("=");
pw.println(mFgsStartForegroundTimeoutMs);
+ pw.print(" ");
+ pw.print(KEY_DEFAULT_APPLICATION_START_INFO_ENABLED);
+ pw.print("=");
+ pw.println(mFlagApplicationStartInfoEnabled);
pw.print(" "); pw.print(KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED); pw.print("=");
pw.println(mFlagBackgroundActivityStartsEnabled);
pw.print(" "); pw.print(KEY_DEFAULT_BACKGROUND_FGS_STARTS_RESTRICTION_ENABLED);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1fe097e66771..ec69306d6783 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -184,6 +184,7 @@ import android.app.AppOpsManager.AttributionFlags;
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
+import android.app.ApplicationStartInfo;
import android.app.ApplicationThreadConstants;
import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
@@ -192,6 +193,7 @@ import android.app.ContentProviderHolder;
import android.app.ForegroundServiceDelegationOptions;
import android.app.IActivityController;
import android.app.IActivityManager;
+import android.app.IApplicationStartInfoCompleteListener;
import android.app.IApplicationThread;
import android.app.IForegroundServiceObserver;
import android.app.IInstrumentationWatcher;
@@ -9452,6 +9454,37 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public ParceledListSlice<ApplicationStartInfo> getHistoricalProcessStartReasons(
+ String packageName, int maxNum, int userId) {
+ if (!mConstants.mFlagApplicationStartInfoEnabled) {
+ return new ParceledListSlice<ApplicationStartInfo>(
+ new ArrayList<ApplicationStartInfo>());
+ }
+ enforceNotIsolatedCaller("getHistoricalProcessStartReasons");
+
+ final ArrayList<ApplicationStartInfo> results = new ArrayList<ApplicationStartInfo>();
+
+ return new ParceledListSlice<ApplicationStartInfo>(results);
+ }
+
+ @Override
+ public void setApplicationStartInfoCompleteListener(
+ IApplicationStartInfoCompleteListener listener, int userId) {
+ if (!mConstants.mFlagApplicationStartInfoEnabled) {
+ return;
+ }
+ enforceNotIsolatedCaller("setApplicationStartInfoCompleteListener");
+ }
+
+ @Override
+ public void removeApplicationStartInfoCompleteListener(int userId) {
+ if (!mConstants.mFlagApplicationStartInfoEnabled) {
+ return;
+ }
+ enforceNotIsolatedCaller("removeApplicationStartInfoCompleteListener");
+ }
+
+ @Override
public ParceledListSlice<ApplicationExitInfo> getHistoricalProcessExitReasons(
String packageName, int pid, int maxNum, int userId) {
enforceNotIsolatedCaller("getHistoricalProcessExitReasons");
@@ -13692,6 +13725,17 @@ public class ActivityManagerService extends IActivityManager.Stub
// not be used generally, so we will be marking them as exported by default
boolean requireExplicitFlagForDynamicReceivers = CompatChanges.isChangeEnabled(
DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED, callingUid);
+
+ // A receiver that is visible to instant apps must also be exported.
+ final boolean unexportedReceiverVisibleToInstantApps =
+ ((flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0) && (
+ (flags & Context.RECEIVER_NOT_EXPORTED) != 0);
+ if (unexportedReceiverVisibleToInstantApps && requireExplicitFlagForDynamicReceivers) {
+ throw new IllegalArgumentException(
+ "Receiver can't specify both RECEIVER_VISIBLE_TO_INSTANT_APPS and "
+ + "RECEIVER_NOT_EXPORTED flag");
+ }
+
// STOPSHIP(b/259139792): Allow apps that are currently targeting U and in process of
// updating their receivers to be exempt from this requirement until their receivers
// are flagged.
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index d29c32745a37..05cf5dbbc7f1 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -229,14 +229,19 @@ class BroadcastProcessQueue {
* When defined, this receiver is considered "blocked" until at least the
* given count of other receivers have reached a terminal state; typically
* used for ordered broadcasts and priority traunches.
+ *
+ * @return the existing broadcast record in the queue that was replaced with a newer broadcast
+ * sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
+ * wasn't any broadcast that was replaced.
*/
- public void enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
- @NonNull BroadcastConsumer replacedBroadcastConsumer, boolean wouldBeSkipped) {
+ @Nullable
+ public BroadcastRecord enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record,
+ int recordIndex, boolean wouldBeSkipped) {
if (record.isReplacePending()) {
- final boolean didReplace = replaceBroadcast(record, recordIndex,
- replacedBroadcastConsumer, wouldBeSkipped);
- if (didReplace) {
- return;
+ final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex,
+ wouldBeSkipped);
+ if (replacedBroadcastRecord != null) {
+ return replacedBroadcastRecord;
}
}
@@ -253,34 +258,37 @@ class BroadcastProcessQueue {
// with implicit responsiveness expectations.
getQueueForBroadcast(record).addLast(newBroadcastArgs);
onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
+ return null;
}
/**
* Searches from newest to oldest in the pending broadcast queues, and at the first matching
* pending broadcast it finds, replaces it in-place and returns -- does not attempt to handle
* "duplicate" broadcasts in the queue.
- * <p>
- * @return {@code true} if it found and replaced an existing record in the queue;
- * {@code false} otherwise.
+ *
+ * @return the existing broadcast record in the queue that was replaced with a newer broadcast
+ * sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
+ * wasn't any broadcast that was replaced.
*/
- private boolean replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
- @NonNull BroadcastConsumer replacedBroadcastConsumer, boolean wouldBeSkipped) {
+ @Nullable
+ private BroadcastRecord replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
+ boolean wouldBeSkipped) {
final ArrayDeque<SomeArgs> queue = getQueueForBroadcast(record);
- return replaceBroadcastInQueue(queue, record, recordIndex,
- replacedBroadcastConsumer, wouldBeSkipped);
+ return replaceBroadcastInQueue(queue, record, recordIndex, wouldBeSkipped);
}
/**
* Searches from newest to oldest, and at the first matching pending broadcast
* it finds, replaces it in-place and returns -- does not attempt to handle
* "duplicate" broadcasts in the queue.
- * <p>
- * @return {@code true} if it found and replaced an existing record in the queue;
- * {@code false} otherwise.
+ *
+ * @return the existing broadcast record in the queue that was replaced with a newer broadcast
+ * sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
+ * wasn't any broadcast that was replaced.
*/
- private boolean replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
+ @Nullable
+ private BroadcastRecord replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
@NonNull BroadcastRecord record, int recordIndex,
- @NonNull BroadcastConsumer replacedBroadcastConsumer,
boolean wouldBeSkipped) {
final Iterator<SomeArgs> it = queue.descendingIterator();
final Object receiver = record.receivers.get(recordIndex);
@@ -302,11 +310,10 @@ class BroadcastProcessQueue {
record.copyEnqueueTimeFrom(testRecord);
onBroadcastDequeued(testRecord, testRecordIndex, testWouldBeSkipped);
onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
- replacedBroadcastConsumer.accept(testRecord, testRecordIndex);
- return true;
+ return testRecord;
}
}
- return false;
+ return null;
}
/**
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index f954420fc6ae..d4d6eb202c57 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -92,6 +92,7 @@ import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -204,6 +205,14 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
@GuardedBy("mService")
private final ArrayList<Pair<BooleanSupplier, CountDownLatch>> mWaitingFor = new ArrayList<>();
+ /**
+ * Container for holding the set of broadcasts that have been replaced by a newer broadcast
+ * sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING}.
+ */
+ @GuardedBy("mService")
+ private final AtomicReference<ArraySet<BroadcastRecord>> mReplacedBroadcastsCache =
+ new AtomicReference<>();
+
private final BroadcastConstants mConstants;
private final BroadcastConstants mFgConstants;
private final BroadcastConstants mBgConstants;
@@ -627,9 +636,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
r.enqueueRealTime = SystemClock.elapsedRealtime();
r.enqueueClockTime = System.currentTimeMillis();
- final ArraySet<BroadcastRecord> replacedBroadcasts = new ArraySet<>();
- final BroadcastConsumer replacedBroadcastConsumer =
- (record, i) -> replacedBroadcasts.add(record);
+ ArraySet<BroadcastRecord> replacedBroadcasts = mReplacedBroadcastsCache.getAndSet(null);
+ if (replacedBroadcasts == null) {
+ replacedBroadcasts = new ArraySet<>();
+ }
boolean enqueuedBroadcast = false;
for (int i = 0; i < r.receivers.size(); i++) {
@@ -653,7 +663,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
}
}
enqueuedBroadcast = true;
- queue.enqueueOrReplaceBroadcast(r, i, replacedBroadcastConsumer, wouldBeSkipped);
+ final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast(
+ r, i, wouldBeSkipped);
+ if (replacedBroadcast != null) {
+ replacedBroadcasts.add(replacedBroadcast);
+ }
if (r.isDeferUntilActive() && queue.isDeferredUntilActive()) {
setDeliveryState(queue, null, r, i, receiver, BroadcastRecord.DELIVERY_DEFERRED,
"deferred at enqueue time");
@@ -664,7 +678,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// Skip any broadcasts that have been replaced by newer broadcasts with
// FLAG_RECEIVER_REPLACE_PENDING.
+ // TODO: Optimize and reuse mBroadcastConsumerSkipAndCanceled for the case of
+ // cancelling all receivers for a broadcast.
skipAndCancelReplacedBroadcasts(replacedBroadcasts);
+ replacedBroadcasts.clear();
+ mReplacedBroadcastsCache.compareAndSet(null, replacedBroadcasts);
// If nothing to dispatch, send any pending result immediately
if (r.receivers.isEmpty() || !enqueuedBroadcast) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index b001f3d0c892..a88055d0cb2b 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1556,6 +1556,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
case MSG_I_BT_SERVICE_DISCONNECTED_PROFILE:
if (msg.arg1 != BluetoothProfile.HEADSET) {
synchronized (mDeviceStateLock) {
+ mBtHelper.onBtProfileDisconnected(msg.arg1);
mDeviceInventory.onBtProfileDisconnected(msg.arg1);
}
} else {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index df65dbd53e06..4ab23c5ac84f 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -278,7 +278,11 @@ public class BtHelper {
}
AudioService.sVolumeLogger.enqueue(new AudioServiceEvents.VolumeEvent(
AudioServiceEvents.VolumeEvent.VOL_SET_AVRCP_VOL, index));
- mA2dp.setAvrcpAbsoluteVolume(index);
+ try {
+ mA2dp.setAvrcpAbsoluteVolume(index);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while changing abs volume", e);
+ }
}
/*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec int getA2dpCodec(
@@ -286,7 +290,12 @@ public class BtHelper {
if (mA2dp == null) {
return AudioSystem.AUDIO_FORMAT_DEFAULT;
}
- final BluetoothCodecStatus btCodecStatus = mA2dp.getCodecStatus(device);
+ final BluetoothCodecStatus btCodecStatus = null;
+ try {
+ mA2dp.getCodecStatus(device);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while getting status of " + device, e);
+ }
if (btCodecStatus == null) {
return AudioSystem.AUDIO_FORMAT_DEFAULT;
}
@@ -420,7 +429,11 @@ public class BtHelper {
}
AudioService.sVolumeLogger.enqueue(new AudioServiceEvents.VolumeEvent(
AudioServiceEvents.VolumeEvent.VOL_SET_LE_AUDIO_VOL, index, maxIndex));
- mLeAudio.setVolume(volume);
+ try {
+ mLeAudio.setVolume(volume);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while setting LE volume", e);
+ }
}
/*package*/ synchronized void setHearingAidVolume(int index, int streamType,
@@ -446,7 +459,11 @@ public class BtHelper {
AudioService.sVolumeLogger.enqueue(new AudioServiceEvents.VolumeEvent(
AudioServiceEvents.VolumeEvent.VOL_SET_HEARING_AID_VOL, index, gainDB));
}
- mHearingAid.setVolume(gainDB);
+ try {
+ mHearingAid.setVolume(gainDB);
+ } catch (Exception e) {
+ Log.i(TAG, "Exception while setting hearing aid volume", e);
+ }
}
/*package*/ synchronized void onBroadcastScoConnectionState(int state) {
@@ -471,7 +488,7 @@ public class BtHelper {
}
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
- @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void resetBluetoothSco() {
mScoAudioState = SCO_STATE_INACTIVE;
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
@@ -486,6 +503,35 @@ public class BtHelper {
mBluetoothHeadset = null;
}
+ //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ /*package*/ synchronized void onBtProfileDisconnected(int profile) {
+ switch (profile) {
+ case BluetoothProfile.A2DP:
+ mA2dp = null;
+ break;
+ case BluetoothProfile.HEARING_AID:
+ mHearingAid = null;
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ mLeAudio = null;
+ break;
+
+ case BluetoothProfile.A2DP_SINK:
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ // shouldn't be received here as profile doesn't involve BtHelper
+ Log.e(TAG, "onBtProfileDisconnected: Not a profile handled by BtHelper "
+ + BluetoothProfile.getProfileName(profile));
+ break;
+
+ default:
+ // Not a valid profile to disconnect
+ Log.e(TAG, "onBtProfileDisconnected: Not a valid profile to disconnect "
+ + BluetoothProfile.getProfileName(profile));
+ break;
+ }
+ }
+
+ @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
/*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
onHeadsetProfileConnected((BluetoothHeadset) proxy);
@@ -671,7 +717,6 @@ public class BtHelper {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
switch(profile) {
case BluetoothProfile.A2DP:
- case BluetoothProfile.A2DP_SINK:
case BluetoothProfile.HEADSET:
case BluetoothProfile.HEARING_AID:
case BluetoothProfile.LE_AUDIO:
@@ -681,6 +726,10 @@ public class BtHelper {
mDeviceBroker.postBtProfileConnected(profile, proxy);
break;
+ case BluetoothProfile.A2DP_SINK:
+ // no A2DP sink functionality handled by BtHelper
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ // no broadcast functionality handled by BtHelper
default:
break;
}
@@ -689,14 +738,19 @@ public class BtHelper {
switch (profile) {
case BluetoothProfile.A2DP:
- case BluetoothProfile.A2DP_SINK:
case BluetoothProfile.HEADSET:
case BluetoothProfile.HEARING_AID:
case BluetoothProfile.LE_AUDIO:
- case BluetoothProfile.LE_AUDIO_BROADCAST:
+ AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+ "BT profile service: disconnecting "
+ + BluetoothProfile.getProfileName(profile) + " profile"));
mDeviceBroker.postBtProfileDisconnected(profile);
break;
+ case BluetoothProfile.A2DP_SINK:
+ // no A2DP sink functionality handled by BtHelper
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ // no broadcast functionality handled by BtHelper
default:
break;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
index 0b5c1c171354..969a174f49c7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
@@ -150,13 +150,6 @@ public final class SensorOverlays {
}
/**
- * Returns if the sensor is side fps.
- */
- public boolean isSfps() {
- return mSidefpsController.isPresent();
- }
-
- /**
* Consumer for a biometric overlay controller.
*
* This behaves like a normal {@link Consumer} except that it will trap and log
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 932c0b4948a0..a90679e755cf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -236,14 +236,8 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
@Override
public void onError(int errorCode, int vendorCode) {
- if (errorCode == BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR
- && vendorCode == BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED
- && mSensorOverlays.isSfps()) {
- super.onError(BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED,
- 0 /* vendorCode */);
- } else {
- super.onError(errorCode, vendorCode);
- }
+ super.onError(errorCode, vendorCode);
+
if (errorCode == BiometricFingerprintConstants.FINGERPRINT_ERROR_BAD_CALIBRATION) {
BiometricNotificationUtils.showBadCalibrationNotification(getContext());
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index cf54662dfa7d..513b3e3e6e86 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -146,14 +146,7 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps
}
});
mCallback.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
- if (acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR
- && vendorCode == BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED
- && mSensorOverlays.isSfps()) {
- super.onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED,
- 0 /* vendorCode */);
- } else {
- super.onAcquired(acquiredInfo, vendorCode);
- }
+ super.onAcquired(acquiredInfo, vendorCode);
}
@Override
@@ -281,5 +274,8 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps
}
@Override
- public void onPowerPressed() { }
+ public void onPowerPressed() {
+ onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED,
+ 0 /* vendorCode */);
+ }
}
diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
index 001cb10e1b29..a33533841e89 100644
--- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
+++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java
@@ -19,6 +19,7 @@ package com.android.server.companion.virtual;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.companion.virtual.IVirtualDevice;
+import android.companion.virtual.sensor.VirtualSensor;
import android.os.LocaleList;
import android.util.ArraySet;
@@ -78,6 +79,15 @@ public abstract class VirtualDeviceManagerInternal {
public abstract int getDeviceOwnerUid(int deviceId);
/**
+ * Returns the VirtualSensor for the given deviceId and sensor handle, if any.
+ *
+ * @param deviceId the virtual device that owns the sensor
+ * @param handle the sensor handle
+ * @return the VirtualSensor with the given handle, or {@code null} if no such sensor exists.
+ */
+ public abstract @Nullable VirtualSensor getVirtualSensor(int deviceId, int handle);
+
+ /**
* Finds VirtualDevices where an app is running.
*
* @param uid - the app's uid
diff --git a/services/core/java/com/android/server/display/DisplayControl.java b/services/core/java/com/android/server/display/DisplayControl.java
index f229d0f71d35..a1081b2a2de0 100644
--- a/services/core/java/com/android/server/display/DisplayControl.java
+++ b/services/core/java/com/android/server/display/DisplayControl.java
@@ -37,6 +37,7 @@ public class DisplayControl {
private static native void nativeSetHdrConversionMode(int conversionMode,
int preferredHdrOutputType, int[] autoHdrTypes, int autoHdrTypesLength);
private static native int[] nativeGetSupportedHdrOutputTypes();
+ private static native boolean nativeGetHdrOutputConversionSupport();
/**
* Create a display in SurfaceFlinger.
@@ -118,4 +119,11 @@ public class DisplayControl {
public static @Display.HdrCapabilities.HdrType int[] getSupportedHdrOutputTypes() {
return nativeGetSupportedHdrOutputTypes();
}
+
+ /**
+ * @hide
+ */
+ public static boolean getHdrOutputConversionSupport() {
+ return nativeGetHdrOutputConversionSupport();
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e200d1214c3d..49bf0f56b06e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -247,6 +247,8 @@ public final class DisplayManagerService extends SystemService {
// HDR conversion mode chosen by user
@GuardedBy("mSyncRoot")
private HdrConversionMode mHdrConversionMode = null;
+ // Actual HDR conversion mode, which takes app overrides into account.
+ private HdrConversionMode mOverrideHdrConversionMode = null;
// The synchronization root for the display manager.
// This lock guards most of the display manager's state.
@@ -2025,12 +2027,23 @@ public final class DisplayManagerService extends SystemService {
if (hdrConversionMode.getConversionMode() == HdrConversionMode.HDR_CONVERSION_SYSTEM) {
autoHdrOutputTypes = getEnabledAutoHdrTypesLocked();
}
- mInjector.setHdrConversionMode(hdrConversionMode.getConversionMode(),
- hdrConversionMode.getPreferredHdrOutputType(), autoHdrOutputTypes);
+
+ if (!mInjector.getHdrOutputConversionSupport()) {
+ return;
+ }
+ // If the HDR conversion is disabled by an app through WindowManager.LayoutParams, then
+ // set HDR conversion mode to HDR_CONVERSION_PASSTHROUGH.
+ if (mOverrideHdrConversionMode == null) {
+ mInjector.setHdrConversionMode(hdrConversionMode.getConversionMode(),
+ hdrConversionMode.getPreferredHdrOutputType(), autoHdrOutputTypes);
+ } else {
+ mInjector.setHdrConversionMode(mOverrideHdrConversionMode.getConversionMode(),
+ mOverrideHdrConversionMode.getPreferredHdrOutputType(), null);
+ }
}
}
- private HdrConversionMode getHdrConversionModeInternal() {
+ private HdrConversionMode getHdrConversionModeSettingInternal() {
synchronized (mSyncRoot) {
if (mHdrConversionMode != null) {
return mHdrConversionMode;
@@ -2039,6 +2052,16 @@ public final class DisplayManagerService extends SystemService {
return new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM);
}
+ private HdrConversionMode getHdrConversionModeInternal() {
+ HdrConversionMode mode;
+ synchronized (mSyncRoot) {
+ mode = mOverrideHdrConversionMode != null
+ ? mOverrideHdrConversionMode
+ : mHdrConversionMode;
+ }
+ return mode != null ? mode : new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_SYSTEM);
+ }
+
private @Display.HdrCapabilities.HdrType int[] getSupportedHdrOutputTypesInternal() {
if (mSupportedHdrOutputType == null) {
mSupportedHdrOutputType = mInjector.getSupportedHdrOutputTypes();
@@ -2181,7 +2204,7 @@ public final class DisplayManagerService extends SystemService {
private void setDisplayPropertiesInternal(int displayId, boolean hasContent,
float requestedRefreshRate, int requestedModeId, float requestedMinRefreshRate,
float requestedMaxRefreshRate, boolean preferMinimalPostProcessing,
- boolean inTraversal) {
+ boolean disableHdrConversion, boolean inTraversal) {
synchronized (mSyncRoot) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
if (display == null) {
@@ -2226,6 +2249,20 @@ public final class DisplayManagerService extends SystemService {
if (shouldScheduleTraversal) {
scheduleTraversalLocked(inTraversal);
}
+
+ if (mHdrConversionMode == null) {
+ return;
+ }
+ if (mOverrideHdrConversionMode == null && disableHdrConversion) {
+ mOverrideHdrConversionMode =
+ new HdrConversionMode(HdrConversionMode.HDR_CONVERSION_PASSTHROUGH);
+ setHdrConversionModeInternal(mHdrConversionMode);
+ handleLogicalDisplayChangedLocked(display);
+ } else if (mOverrideHdrConversionMode != null && !disableHdrConversion) {
+ mOverrideHdrConversionMode = null;
+ setHdrConversionModeInternal(mHdrConversionMode);
+ handleLogicalDisplayChangedLocked(display);
+ }
}
}
@@ -2783,6 +2820,10 @@ public final class DisplayManagerService extends SystemService {
int[] getSupportedHdrOutputTypes() {
return DisplayControl.getSupportedHdrOutputTypes();
}
+
+ boolean getHdrOutputConversionSupport() {
+ return DisplayControl.getHdrOutputConversionSupport();
+ }
}
@VisibleForTesting
@@ -3757,6 +3798,16 @@ public final class DisplayManagerService extends SystemService {
}
@Override // Binder call
+ public HdrConversionMode getHdrConversionModeSetting() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getHdrConversionModeSettingInternal();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public HdrConversionMode getHdrConversionMode() {
final long token = Binder.clearCallingIdentity();
try {
@@ -4030,10 +4081,10 @@ public final class DisplayManagerService extends SystemService {
public void setDisplayProperties(int displayId, boolean hasContent,
float requestedRefreshRate, int requestedMode, float requestedMinRefreshRate,
float requestedMaxRefreshRate, boolean requestedMinimalPostProcessing,
- boolean inTraversal) {
+ boolean disableHdrConversion, boolean inTraversal) {
setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate,
requestedMode, requestedMinRefreshRate, requestedMaxRefreshRate,
- requestedMinimalPostProcessing, inTraversal);
+ requestedMinimalPostProcessing, disableHdrConversion, inTraversal);
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1305d63a77d1..f5ca8aaa0997 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -138,6 +138,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private static final int MSG_UPDATE_RBC = 11;
private static final int MSG_BRIGHTNESS_RAMP_DONE = 12;
private static final int MSG_STATSD_HBM_BRIGHTNESS = 13;
+ private static final int MSG_SWITCH_USER = 14;
private static final int PROXIMITY_UNKNOWN = -1;
private static final int PROXIMITY_NEGATIVE = 0;
@@ -714,6 +715,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
@Override
public void onSwitchUser(@UserIdInt int newUserId) {
+ Message msg = mHandler.obtainMessage(MSG_SWITCH_USER, newUserId);
+ mHandler.sendMessage(msg);
+ }
+
+ private void handleOnSwitchUser(@UserIdInt int newUserId) {
handleSettingsChange(true /* userSwitch */);
handleBrightnessModeChange();
if (mBrightnessTracker != null) {
@@ -3073,6 +3079,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
case MSG_STATSD_HBM_BRIGHTNESS:
logHbmBrightnessStats(Float.intBitsToFloat(msg.arg1), msg.arg2);
break;
+
+ case MSG_SWITCH_USER:
+ handleOnSwitchUser(msg.arg1);
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 82faa12be90e..5667ddf59b3c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -135,6 +135,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
private static final int MSG_UPDATE_RBC = 9;
private static final int MSG_BRIGHTNESS_RAMP_DONE = 10;
private static final int MSG_STATSD_HBM_BRIGHTNESS = 11;
+ private static final int MSG_SWITCH_USER = 12;
private static final int BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS = 500;
@@ -605,6 +606,11 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
@Override
public void onSwitchUser(@UserIdInt int newUserId) {
+ Message msg = mHandler.obtainMessage(MSG_SWITCH_USER, newUserId);
+ mHandler.sendMessage(msg);
+ }
+
+ private void handleOnSwitchUser(@UserIdInt int newUserId) {
handleSettingsChange(true /* userSwitch */);
handleBrightnessModeChange();
if (mBrightnessTracker != null) {
@@ -2573,6 +2579,10 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
case MSG_STATSD_HBM_BRIGHTNESS:
logHbmBrightnessStats(Float.intBitsToFloat(msg.arg1), msg.arg2);
break;
+
+ case MSG_SWITCH_USER:
+ handleOnSwitchUser(msg.arg1);
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 25efe0c3214f..77b9abed0d41 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -287,19 +287,16 @@ public final class MediaProjectionManagerService extends SystemService
if (packageName == null || packageName.isEmpty()) {
throw new IllegalArgumentException("package name must not be empty");
}
-
- final UserHandle callingUser = Binder.getCallingUserHandle();
- final long callingToken = Binder.clearCallingIdentity();
+ final ApplicationInfo ai;
+ try {
+ ai = mPackageManager.getApplicationInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException("No package matching :" + packageName);
+ }
MediaProjection projection;
+ final long callingToken = Binder.clearCallingIdentity();
try {
- ApplicationInfo ai;
- try {
- ai = mPackageManager.getApplicationInfoAsUser(packageName, 0, callingUser);
- } catch (NameNotFoundException e) {
- throw new IllegalArgumentException("No package matching :" + packageName);
- }
-
projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion,
ai.isPrivilegedApp());
if (isPermanentGrant) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c1b3834eba70..fd9f8d113dec 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -393,12 +393,17 @@ public class NotificationManagerService extends SystemService {
static final int INVALID_UID = -1;
static final String ROOT_PKG = "root";
- static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
+ static final String[] ALLOWED_ADJUSTMENTS = new String[] {
+ Adjustment.KEY_PEOPLE,
+ Adjustment.KEY_SNOOZE_CRITERIA,
+ Adjustment.KEY_USER_SENTIMENT,
Adjustment.KEY_CONTEXTUAL_ACTIONS,
Adjustment.KEY_TEXT_REPLIES,
- Adjustment.KEY_NOT_CONVERSATION,
Adjustment.KEY_IMPORTANCE,
- Adjustment.KEY_RANKING_SCORE
+ Adjustment.KEY_IMPORTANCE_PROPOSAL,
+ Adjustment.KEY_SENSITIVE_CONTENT,
+ Adjustment.KEY_RANKING_SCORE,
+ Adjustment.KEY_NOT_CONVERSATION
};
static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] {
@@ -2567,27 +2572,6 @@ public class NotificationManagerService extends SystemService {
for (String name : properties.getKeyset()) {
if (SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE.equals(name)) {
mAssistants.resetDefaultAssistantsIfNecessary();
- } else if (SystemUiDeviceConfigFlags.ENABLE_NAS_PRIORITIZER.equals(name)) {
- String value = properties.getString(name, null);
- if ("true".equals(value)) {
- mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE);
- } else if ("false".equals(value)) {
- mAssistants.disallowAdjustmentType(Adjustment.KEY_IMPORTANCE);
- }
- } else if (SystemUiDeviceConfigFlags.ENABLE_NAS_RANKING.equals(name)) {
- String value = properties.getString(name, null);
- if ("true".equals(value)) {
- mAssistants.allowAdjustmentType(Adjustment.KEY_RANKING_SCORE);
- } else if ("false".equals(value)) {
- mAssistants.disallowAdjustmentType(Adjustment.KEY_RANKING_SCORE);
- }
- } else if (SystemUiDeviceConfigFlags.ENABLE_NAS_NOT_CONVERSATION.equals(name)) {
- String value = properties.getString(name, null);
- if ("true".equals(value)) {
- mAssistants.allowAdjustmentType(Adjustment.KEY_NOT_CONVERSATION);
- } else if ("false".equals(value)) {
- mAssistants.disallowAdjustmentType(Adjustment.KEY_NOT_CONVERSATION);
- }
} else if (SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED.equals(name)) {
String value = properties.getString(name, null);
if ("true".equals(value)) {
@@ -4256,22 +4240,6 @@ public class NotificationManagerService extends SystemService {
return mAssistants.getAllowedAssistantAdjustments();
}
- @Override
- public void allowAssistantAdjustment(String adjustmentType) {
- checkCallerIsSystemOrSystemUiOrShell();
- mAssistants.allowAdjustmentType(adjustmentType);
-
- handleSavePolicyFile();
- }
-
- @Override
- public void disallowAssistantAdjustment(String adjustmentType) {
- checkCallerIsSystemOrSystemUiOrShell();
- mAssistants.disallowAdjustmentType(adjustmentType);
-
- handleSavePolicyFile();
- }
-
/**
* @deprecated Use {@link #getActiveNotificationsWithAttribution(String, String)} instead.
*/
@@ -10146,8 +10114,6 @@ public class NotificationManagerService extends SystemService {
public class NotificationAssistants extends ManagedServices {
static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
- private static final String TAG_ALLOWED_ADJUSTMENT_TYPES_OLD = "q_allowed_adjustments";
- private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "s_allowed_adjustments";
private static final String ATT_TYPES = "types";
private final Object mLock = new Object();
@@ -10224,10 +10190,9 @@ public class NotificationManagerService extends SystemService {
IPackageManager pm) {
super(context, lock, up, pm);
- // Add all default allowed adjustment types. Will be overwritten by values in xml,
- // if they exist
- for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) {
- mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]);
+ // Add all default allowed adjustment types.
+ for (int i = 0; i < ALLOWED_ADJUSTMENTS.length; i++) {
+ mAllowedAdjustments.add(ALLOWED_ADJUSTMENTS[i]);
}
}
@@ -10285,52 +10250,6 @@ public class NotificationManagerService extends SystemService {
return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
}
- @Override
- protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {
- synchronized (mLock) {
- out.startTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
- out.attribute(null, ATT_TYPES, TextUtils.join(",", mAllowedAdjustments));
- out.endTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
- }
- }
-
- @Override
- protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {
- if (TAG_ALLOWED_ADJUSTMENT_TYPES_OLD.equals(tag)
- || TAG_ALLOWED_ADJUSTMENT_TYPES.equals(tag)) {
- final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
- synchronized (mLock) {
- mAllowedAdjustments.clear();
- if (!TextUtils.isEmpty(types)) {
- mAllowedAdjustments.addAll(Arrays.asList(types.split(",")));
- }
- if (TAG_ALLOWED_ADJUSTMENT_TYPES_OLD.equals(tag)) {
- if (DEBUG) Slog.d(TAG, "Migrate allowed adjustments.");
- mAllowedAdjustments.addAll(
- Arrays.asList(DEFAULT_ALLOWED_ADJUSTMENTS));
- }
- }
- }
- }
-
- protected void allowAdjustmentType(String type) {
- synchronized (mLock) {
- mAllowedAdjustments.add(type);
- }
- for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
- mHandler.post(() -> notifyCapabilitiesChanged(info));
- }
- }
-
- protected void disallowAdjustmentType(String type) {
- synchronized (mLock) {
- mAllowedAdjustments.remove(type);
- }
- for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
- mHandler.post(() -> notifyCapabilitiesChanged(info));
- }
- }
-
protected List<String> getAllowedAssistantAdjustments() {
synchronized (mLock) {
List<String> types = new ArrayList<>();
@@ -10402,15 +10321,6 @@ public class NotificationManagerService extends SystemService {
mIsUserChanged.put(userId, set);
}
- private void notifyCapabilitiesChanged(final ManagedServiceInfo info) {
- final INotificationListener assistant = (INotificationListener) info.service;
- try {
- assistant.onAllowedAdjustmentsChanged();
- } catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify assistant (capabilities): " + info, ex);
- }
- }
-
private void notifySeen(final ManagedServiceInfo info,
final ArrayList<String> keys) {
final INotificationListener assistant = (INotificationListener) info.service;
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index d8bfa592ea95..1bd5b9962436 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -566,7 +566,10 @@ public final class DexOptHelper {
mPm.getDexManager().getPackageUseInfoOrDefault(p.getPackageName()), options);
}
- public void forceDexOpt(@NonNull Computer snapshot, String packageName) {
+ /** @deprecated For legacy shell command only. */
+ @Deprecated
+ public void forceDexOpt(@NonNull Computer snapshot, String packageName)
+ throws LegacyDexoptDisabledException {
PackageManagerServiceUtils.enforceSystemOrRoot("forceDexOpt");
final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
@@ -586,19 +589,7 @@ public final class DexOptHelper {
getDefaultCompilerFilter(), null /* splitName */,
DexoptOptions.DEXOPT_FORCE | DexoptOptions.DEXOPT_BOOT_COMPLETE);
- @DexOptResult int res;
- if (useArtService()) {
- // performDexOptWithArtService ignores the snapshot and takes its own, so it can race
- // with the package checks above, but at worst the effect is only a bit less friendly
- // error below.
- res = performDexOptWithArtService(options, ArtFlags.FLAG_SHOULD_INCLUDE_DEPENDENCIES);
- } else {
- try {
- res = performDexOptInternalWithDependenciesLI(pkg, packageState, options);
- } catch (LegacyDexoptDisabledException e) {
- throw new RuntimeException(e);
- }
- }
+ @DexOptResult int res = performDexOptInternalWithDependenciesLI(pkg, packageState, options);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
index d4e3549f60a3..d39cac070413 100644
--- a/services/core/java/com/android/server/pm/IPackageManagerBase.java
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -303,12 +303,6 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub {
@Override
@Deprecated
- public final void forceDexOpt(String packageName) {
- mDexOptHelper.forceDexOpt(snapshot(), packageName);
- }
-
- @Override
- @Deprecated
public final ActivityInfo getActivityInfo(ComponentName component,
@PackageManager.ComponentInfoFlagsBits long flags, int userId) {
return snapshot().getActivityInfo(component, flags, userId);
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index f989f6f5b169..c3cc3929d56d 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -153,7 +153,7 @@ class InstallingSession {
mInstallSource = installSource;
mVolumeUuid = sessionParams.volumeUuid;
mPackageAbiOverride = sessionParams.abiOverride;
- mPermissionStates = sessionParams.getFinalPermissionStates();
+ mPermissionStates = sessionParams.getPermissionStates();
mAllowlistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
mAutoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
mSigningDetails = signingDetails;
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index e25430099301..85d2df320fc9 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -388,7 +388,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
if (abi32 >= 0) {
final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];
if (abi64 >= 0) {
- if (pkg.isUse32BitAbi()) {
+ if (pkg.is32BitAbiPreferred()) {
secondaryCpuAbi = primaryCpuAbi;
primaryCpuAbi = abi;
} else {
@@ -474,7 +474,8 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
private boolean shouldExtractLibs(AndroidPackage pkg, boolean isSystemApp,
boolean isUpdatedSystemApp) {
// We shouldn't extract libs if the package is a library or if extractNativeLibs=false
- boolean extractLibs = !AndroidPackageUtils.isLibrary(pkg) && pkg.isExtractNativeLibs();
+ boolean extractLibs = !AndroidPackageUtils.isLibrary(pkg)
+ && pkg.isExtractNativeLibrariesRequested();
// We shouldn't attempt to extract libs from system app when it was not updated.
if (isSystemApp && !isUpdatedSystemApp) {
extractLibs = false;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index f708fbb81dba..f33813759e4f 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -189,7 +189,7 @@ public class PackageDexOptimizer {
}
// We do not dexopt a package with no code.
- if (!pkg.isHasCode()) {
+ if (!pkg.isDeclaredHavingCode()) {
return false;
}
@@ -287,7 +287,7 @@ public class PackageDexOptimizer {
// For each code path in the package, this array contains the class loader context that
// needs to be passed to dexopt in order to ensure correct optimizations.
boolean[] pathsWithCode = new boolean[paths.size()];
- pathsWithCode[0] = pkg.isHasCode();
+ pathsWithCode[0] = pkg.isDeclaredHavingCode();
for (int i = 1; i < paths.size(); i++) {
pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index ed9d370fd9e3..08972899e9ef 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -804,7 +804,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
+ " PackageManager.INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS flag");
}
- var permissionStates = params.getFinalPermissionStates();
+ var permissionStates = params.getPermissionStates();
if (!permissionStates.isEmpty()) {
if (!hasInstallGrantRuntimePermissions) {
for (int index = 0; index < permissionStates.size(); index++) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3ad3af3e1c2b..39519039e95b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -4878,7 +4878,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static void writePermissionsLocked(@NonNull TypedXmlSerializer out,
@NonNull SessionParams params) throws IOException {
- params.writePermissionStateXml(out, TAG_GRANT_PERMISSION, TAG_DENY_PERMISSION, ATTR_NAME);
+ var permissionStates = params.getPermissionStates();
+ for (int index = 0; index < permissionStates.size(); index++) {
+ var permissionName = permissionStates.keyAt(index);
+ var state = permissionStates.valueAt(index);
+ String tag = state == SessionParams.PERMISSION_STATE_GRANTED ? TAG_GRANT_PERMISSION
+ : TAG_DENY_PERMISSION;
+ out.startTag(null, tag);
+ writeStringAttribute(out, ATTR_NAME, permissionName);
+ out.endTag(null, tag);
+ }
}
private static void writeWhitelistedRestrictedPermissionsLocked(@NonNull TypedXmlSerializer out,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 382be45fd9df..1c24cec65cc8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6679,6 +6679,13 @@ public class PackageManagerService implements PackageSender, TestUtilityService
/** @deprecated For legacy shell command only. */
@Override
@Deprecated
+ public void legacyForceDexOpt(String packageName) throws LegacyDexoptDisabledException {
+ mDexOptHelper.forceDexOpt(snapshotComputer(), packageName);
+ }
+
+ /** @deprecated For legacy shell command only. */
+ @Override
+ @Deprecated
public void legacyReconcileSecondaryDexFiles(String packageName)
throws LegacyDexoptDisabledException {
final Computer snapshot = snapshotComputer();
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d322fa2998f2..74bd0092ab4d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2002,8 +2002,8 @@ class PackageManagerShellCommand extends ShellCommand {
return 0;
}
- public int runForceDexOpt() throws RemoteException {
- mInterface.forceDexOpt(getNextArgRequired());
+ public int runForceDexOpt() throws RemoteException, LegacyDexoptDisabledException {
+ mPm.legacyForceDexOpt(getNextArgRequired());
return 0;
}
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 253887107a04..e4f3e2b87497 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -547,7 +547,7 @@ final class ScanPackageUtils {
*/
public static void assertCodePolicy(AndroidPackage pkg)
throws PackageManagerException {
- final boolean shouldHaveCode = pkg.isHasCode();
+ final boolean shouldHaveCode = pkg.isDeclaredHavingCode();
if (shouldHaveCode && !apkHasCode(pkg.getBaseApkPath())) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Package " + pkg.getBaseApkPath() + " code is missing");
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6541b40cc724..f1998f764e7c 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4864,7 +4864,7 @@ public final class Settings implements Watchable, Snappable {
pw.println();
if (pkg != null) {
pw.print(prefix); pw.print(" versionName="); pw.println(pkg.getVersionName());
- pw.print(prefix); pw.print(" usesNonSdkApi="); pw.println(pkg.isUsesNonSdkApi());
+ pw.print(prefix); pw.print(" usesNonSdkApi="); pw.println(pkg.isNonSdkApiRequested());
pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, pkg); pw.println();
final int apkSigningVersion = pkg.getSigningDetails().getSignatureSchemeVersion();
pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion);
@@ -4897,25 +4897,25 @@ public final class Settings implements Watchable, Snappable {
pw.print(prefix); pw.print(" dataDir="); pw.println(dataDir.getAbsolutePath());
pw.print(prefix); pw.print(" supportsScreens=[");
boolean first = true;
- if (pkg.isSupportsSmallScreens()) {
+ if (pkg.isSmallScreensSupported()) {
if (!first)
pw.print(", ");
first = false;
pw.print("small");
}
- if (pkg.isSupportsNormalScreens()) {
+ if (pkg.isNormalScreensSupported()) {
if (!first)
pw.print(", ");
first = false;
pw.print("medium");
}
- if (pkg.isSupportsLargeScreens()) {
+ if (pkg.isLargeScreensSupported()) {
if (!first)
pw.print(", ");
first = false;
pw.print("large");
}
- if (pkg.isSupportsExtraLargeScreens()) {
+ if (pkg.isExtraLargeScreensSupported()) {
if (!first)
pw.print(", ");
first = false;
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 3cbaebe4101e..36efc0ddfc44 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -238,8 +238,9 @@ public abstract class UserManagerInternal {
* the user is created (as it will be passed back to it through
* {@link UserLifecycleListener#onUserCreated(UserInfo, Object)});
*/
- public abstract UserInfo createUserEvenWhenDisallowed(String name, String userType,
- int flags, String[] disallowedPackages, @Nullable Object token)
+ public abstract @NonNull UserInfo createUserEvenWhenDisallowed(
+ @Nullable String name, @NonNull String userType, @UserInfo.UserInfoFlag int flags,
+ @Nullable String[] disallowedPackages, @Nullable Object token)
throws UserManager.CheckedUserOperationException;
/**
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 372b580214cd..a22ea9626bc0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4495,9 +4495,11 @@ public class UserManagerService extends IUserManager.Stub {
* as well as for {@link UserManager#USER_TYPE_FULL_RESTRICTED}.
*/
@Override
- public UserInfo createProfileForUserWithThrow(@Nullable String name, @NonNull String userType,
- @UserInfoFlag int flags, @UserIdInt int userId, @Nullable String[] disallowedPackages)
+ public @NonNull UserInfo createProfileForUserWithThrow(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+ @UserIdInt int userId, @Nullable String[] disallowedPackages)
throws ServiceSpecificException {
+
checkCreateUsersPermission(flags);
try {
return createUserInternal(name, userType, flags, userId, disallowedPackages);
@@ -4510,10 +4512,11 @@ public class UserManagerService extends IUserManager.Stub {
* @see #createProfileForUser
*/
@Override
- public UserInfo createProfileForUserEvenWhenDisallowedWithThrow(String name,
- @NonNull String userType,
- @UserInfoFlag int flags, @UserIdInt int userId, @Nullable String[] disallowedPackages)
+ public @NonNull UserInfo createProfileForUserEvenWhenDisallowedWithThrow(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+ @UserIdInt int userId, @Nullable String[] disallowedPackages)
throws ServiceSpecificException {
+
checkCreateUsersPermission(flags);
try {
return createUserInternalUnchecked(name, userType, flags, userId,
@@ -4524,9 +4527,10 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public UserInfo createUserWithThrow(String name, @NonNull String userType,
- @UserInfoFlag int flags)
+ public @NonNull UserInfo createUserWithThrow(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags)
throws ServiceSpecificException {
+
checkCreateUsersPermission(flags);
try {
return createUserInternal(name, userType, flags, UserHandle.USER_NULL,
@@ -4537,7 +4541,10 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public UserInfo preCreateUserWithThrow(String userType) throws ServiceSpecificException {
+ public @NonNull UserInfo preCreateUserWithThrow(
+ @NonNull String userType)
+ throws ServiceSpecificException {
+
final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
final int flags = userTypeDetails != null ? userTypeDetails.getDefaultUserInfoFlags() : 0;
@@ -4557,10 +4564,12 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public UserHandle createUserWithAttributes(
- String userName, String userType, @UserInfoFlag int flags,
- Bitmap userIcon,
- String accountName, String accountType, PersistableBundle accountOptions) {
+ public @NonNull UserHandle createUserWithAttributes(
+ @Nullable String userName, @NonNull String userType, @UserInfoFlag int flags,
+ @Nullable Bitmap userIcon, @Nullable String accountName, @Nullable String accountType,
+ @Nullable PersistableBundle accountOptions)
+ throws ServiceSpecificException {
+
checkCreateUsersPermission(flags);
if (someUserHasAccountNoChecks(accountName, accountType)) {
@@ -4570,12 +4579,7 @@ public class UserManagerService extends IUserManager.Stub {
UserInfo userInfo;
try {
- userInfo = createUserInternal(userName, userType, flags,
- UserHandle.USER_NULL, null);
-
- if (userInfo == null) {
- throw new ServiceSpecificException(USER_OPERATION_ERROR_UNKNOWN);
- }
+ userInfo = createUserInternal(userName, userType, flags, UserHandle.USER_NULL, null);
} catch (UserManager.CheckedUserOperationException e) {
throw e.toServiceSpecificException();
}
@@ -4589,7 +4593,8 @@ public class UserManagerService extends IUserManager.Stub {
return userInfo.getUserHandle();
}
- private UserInfo createUserInternal(@Nullable String name, @NonNull String userType,
+ private @NonNull UserInfo createUserInternal(
+ @Nullable String name, @NonNull String userType,
@UserInfoFlag int flags, @UserIdInt int parentId,
@Nullable String[] disallowedPackages)
throws UserManager.CheckedUserOperationException {
@@ -4611,11 +4616,12 @@ public class UserManagerService extends IUserManager.Stub {
/* preCreate= */ false, disallowedPackages, /* token= */ null);
}
- private UserInfo createUserInternalUnchecked(@Nullable String name,
- @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId,
- boolean preCreate, @Nullable String[] disallowedPackages,
+ private @NonNull UserInfo createUserInternalUnchecked(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+ @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages,
@Nullable Object token)
throws UserManager.CheckedUserOperationException {
+
final int noneUserId = -1;
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("createUser-" + flags);
@@ -4633,27 +4639,31 @@ public class UserManagerService extends IUserManager.Stub {
}
}
- private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name,
- @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId,
- boolean preCreate, @Nullable String[] disallowedPackages,
+ private @NonNull UserInfo createUserInternalUncheckedNoTracing(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+ @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages,
@NonNull TimingsTraceAndSlog t, @Nullable Object token)
- throws UserManager.CheckedUserOperationException {
+ throws UserManager.CheckedUserOperationException {
+
final UserTypeDetails userTypeDetails = mUserTypes.get(userType);
if (userTypeDetails == null) {
- Slog.e(LOG_TAG, "Cannot create user of invalid user type: " + userType);
- return null;
+ throwCheckedUserOperationException(
+ "Cannot create user of invalid user type: " + userType,
+ USER_OPERATION_ERROR_UNKNOWN);
}
userType = userType.intern(); // Now that we know it's valid, we can intern it.
flags |= userTypeDetails.getDefaultUserInfoFlags();
if (!checkUserTypeConsistency(flags)) {
- Slog.e(LOG_TAG, "Cannot add user. Flags (" + Integer.toHexString(flags)
- + ") and userTypeDetails (" + userType + ") are inconsistent.");
- return null;
+ throwCheckedUserOperationException(
+ "Cannot add user. Flags (" + Integer.toHexString(flags)
+ + ") and userTypeDetails (" + userType + ") are inconsistent.",
+ USER_OPERATION_ERROR_UNKNOWN);
}
if ((flags & UserInfo.FLAG_SYSTEM) != 0) {
- Slog.e(LOG_TAG, "Cannot add user. Flags (" + Integer.toHexString(flags)
- + ") indicated SYSTEM user, which cannot be created.");
- return null;
+ throwCheckedUserOperationException(
+ "Cannot add user. Flags (" + Integer.toHexString(flags)
+ + ") indicated SYSTEM user, which cannot be created.",
+ USER_OPERATION_ERROR_UNKNOWN);
}
if (!isUserTypeEnabled(userTypeDetails)) {
throwCheckedUserOperationException(
@@ -4679,7 +4689,8 @@ public class UserManagerService extends IUserManager.Stub {
DeviceStorageMonitorInternal dsm = LocalServices
.getService(DeviceStorageMonitorInternal.class);
if (dsm.isMemoryLow()) {
- throwCheckedUserOperationException("Cannot add user. Not enough space on disk.",
+ throwCheckedUserOperationException(
+ "Cannot add user. Not enough space on disk.",
UserManager.USER_OPERATION_ERROR_LOW_STORAGE);
}
@@ -4707,7 +4718,8 @@ public class UserManagerService extends IUserManager.Stub {
}
}
if (!preCreate && !canAddMoreUsersOfType(userTypeDetails)) {
- throwCheckedUserOperationException("Cannot add more users of type " + userType
+ throwCheckedUserOperationException(
+ "Cannot add more users of type " + userType
+ ". Maximum number of that type already exists.",
UserManager.USER_OPERATION_ERROR_MAX_USERS);
}
@@ -5332,13 +5344,13 @@ public class UserManagerService extends IUserManager.Stub {
* @hide
*/
@Override
- public UserInfo createRestrictedProfileWithThrow(@Nullable String name, int parentUserId) {
+ public @NonNull UserInfo createRestrictedProfileWithThrow(
+ @Nullable String name, @UserIdInt int parentUserId)
+ throws ServiceSpecificException {
+
checkCreateUsersPermission("setupRestrictedProfile");
final UserInfo user = createProfileForUserWithThrow(
name, UserManager.USER_TYPE_FULL_RESTRICTED, 0, parentUserId, null);
- if (user == null) {
- return null;
- }
final long identity = Binder.clearCallingIdentity();
try {
setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
@@ -6339,8 +6351,10 @@ public class UserManagerService extends IUserManager.Stub {
setSeedAccountDataNoChecks(userId, accountName, accountType, accountOptions, persist);
}
- private void setSeedAccountDataNoChecks(@UserIdInt int userId, String accountName,
- String accountType, PersistableBundle accountOptions, boolean persist) {
+ private void setSeedAccountDataNoChecks(@UserIdInt int userId, @Nullable String accountName,
+ @Nullable String accountType, @Nullable PersistableBundle accountOptions,
+ boolean persist) {
+
synchronized (mPackagesLock) {
final UserData userData;
synchronized (mUsersLock) {
@@ -6909,9 +6923,11 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
- public UserInfo createUserEvenWhenDisallowed(String name, @NonNull String userType,
- @UserInfoFlag int flags, String[] disallowedPackages, @Nullable Object token)
+ public @NonNull UserInfo createUserEvenWhenDisallowed(
+ @Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
+ @Nullable String[] disallowedPackages, @Nullable Object token)
throws UserManager.CheckedUserOperationException {
+
return createUserInternalUnchecked(name, userType, flags,
UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages, token);
}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 3f2083f1c857..6032fecfea67 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -167,10 +167,10 @@ public class UserRestrictionsUtils {
);
/**
- * User restrictions that cannot be set by profile owners of secondary users. When set by DO
- * they will be applied to all users.
+ * User restrictions that can only be set by profile owners on the main user, or by device
+ * owners. When set by DO they will be applied to all users.
*/
- private static final Set<String> PRIMARY_USER_ONLY_RESTRICTIONS = Sets.newArraySet(
+ private static final Set<String> MAIN_USER_ONLY_RESTRICTIONS = Sets.newArraySet(
UserManager.DISALLOW_BLUETOOTH,
UserManager.DISALLOW_USB_FILE_TRANSFER,
UserManager.DISALLOW_CONFIG_TETHERING,
@@ -454,14 +454,14 @@ public class UserRestrictionsUtils {
}
/**
- * @return true if a restriction is settable by profile owner. Note it takes a user ID because
- * some restrictions can be changed by PO only when it's running on the system user.
+ * @return true if a restriction is settable by profile owner. Note it takes a boolean to say
+ * if the relevant user is the {@link UserManager#isMainUser() MainUser}, because some
+ * restrictions can be changed by PO only when it's running on the main user.
*/
- public static boolean canProfileOwnerChange(String restriction, int userId) {
+ public static boolean canProfileOwnerChange(String restriction, boolean isMainUser) {
return !IMMUTABLE_BY_OWNERS.contains(restriction)
&& !DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction)
- && !(userId != UserHandle.USER_SYSTEM
- && PRIMARY_USER_ONLY_RESTRICTIONS.contains(restriction));
+ && !(!isMainUser && MAIN_USER_ONLY_RESTRICTIONS.contains(restriction));
}
/**
@@ -494,7 +494,7 @@ public class UserRestrictionsUtils {
public static boolean isGlobal(@UserManagerInternal.OwnerType int restrictionOwnerType,
String key) {
return ((restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER) && (
- PRIMARY_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)))
+ MAIN_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)))
|| ((restrictionOwnerType
== UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)
&& PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS.contains(key))
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index d8b6cd5bb7e3..d88b66b412e7 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -580,7 +580,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
*/
private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) {
ArrayMap<String, String> result = new ArrayMap<>();
- if (pkg.isHasCode()) {
+ if (pkg.isDeclaredHavingCode()) {
result.put(pkg.getBaseApkPath(), ArtManager.getProfileName(null));
}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index a3be8d35d4b9..d108e1487564 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -133,7 +133,7 @@ public class PackageInfoUtils {
info.splitRevisionCodes = pkg.getSplitRevisionCodes();
info.versionName = pkg.getVersionName();
info.sharedUserId = pkg.getSharedUserId();
- info.sharedUserLabel = pkg.getSharedUserLabelRes();
+ info.sharedUserLabel = pkg.getSharedUserLabelResourceId();
info.applicationInfo = applicationInfo;
info.installLocation = pkg.getInstallLocation();
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
@@ -876,27 +876,27 @@ public class PackageInfoUtils {
// @formatter:off
int pkgWithoutStateFlags = flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE)
| flag(pkg.isHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED)
- | flag(pkg.isAllowBackup(), ApplicationInfo.FLAG_ALLOW_BACKUP)
- | flag(pkg.isKillAfterRestore(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
+ | flag(pkg.isBackupAllowed(), ApplicationInfo.FLAG_ALLOW_BACKUP)
+ | flag(pkg.isKillAfterRestoreAllowed(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
| flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
| flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY)
| flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT)
| flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE)
| flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE)
- | flag(pkg.isHasCode(), ApplicationInfo.FLAG_HAS_CODE)
- | flag(pkg.isAllowTaskReparenting(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
- | flag(pkg.isAllowClearUserData(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
+ | flag(pkg.isDeclaredHavingCode(), ApplicationInfo.FLAG_HAS_CODE)
+ | flag(pkg.isTaskReparentingAllowed(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
+ | flag(pkg.isClearUserDataAllowed(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
| flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP)
- | flag(pkg.isUsesCleartextTraffic(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
- | flag(pkg.isSupportsRtl(), ApplicationInfo.FLAG_SUPPORTS_RTL)
+ | flag(pkg.isCleartextTrafficAllowed(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
+ | flag(pkg.isRtlSupported(), ApplicationInfo.FLAG_SUPPORTS_RTL)
| flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY)
| flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH)
- | flag(pkg.isExtractNativeLibs(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
+ | flag(pkg.isExtractNativeLibrariesRequested(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
| flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME)
- | flag(pkg.isSupportsSmallScreens(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
- | flag(pkg.isSupportsNormalScreens(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
- | flag(pkg.isSupportsLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
- | flag(pkg.isSupportsExtraLargeScreens(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
+ | flag(pkg.isSmallScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
+ | flag(pkg.isNormalScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
+ | flag(pkg.isLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
+ | flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
| flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
| flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
| flag(AndroidPackageUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
@@ -932,12 +932,12 @@ public class PackageInfoUtils {
| flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
| flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE)
| flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE)
- | flag(pkg.isAllowClearUserDataOnFailedRestore(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
+ | flag(pkg.isClearUserDataOnFailedRestoreAllowed(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
| flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE)
| flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE)
- | flag(pkg.isUsesNonSdkApi(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
- | flag(pkg.isHasFragileUserData(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
- | flag(pkg.isCantSaveState(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+ | flag(pkg.isNonSdkApiRequested(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
+ | flag(pkg.isUserDataFragile(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
+ | flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
| flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
| flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING)
| flag(AndroidPackageUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index f3ee53178b60..e2acc17e94c4 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -59,7 +59,7 @@ public class AndroidPackageUtils {
AndroidPackage aPkg) {
PackageImpl pkg = (PackageImpl) aPkg;
ArrayList<String> paths = new ArrayList<>();
- if (pkg.isHasCode()) {
+ if (pkg.isDeclaredHavingCode()) {
paths.add(pkg.getBaseApkPath());
}
String[] splitCodePaths = pkg.getSplitCodePaths();
@@ -156,7 +156,7 @@ public class AndroidPackageUtils {
return NativeLibraryHelper.Handle.create(
AndroidPackageUtils.getAllCodePaths(pkg),
pkg.isMultiArch(),
- pkg.isExtractNativeLibs(),
+ pkg.isExtractNativeLibrariesRequested(),
pkg.isDebuggable()
);
}
@@ -243,7 +243,7 @@ public class AndroidPackageUtils {
} else if (pkg.isSignedWithPlatformKey()) {
isAllowedToUseHiddenApis = true;
} else if (packageState.isSystem()) {
- isAllowedToUseHiddenApis = pkg.isUsesNonSdkApi()
+ isAllowedToUseHiddenApis = pkg.isNonSdkApiRequested()
|| SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(
pkg.getPackageName());
} else {
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index d7c4a09d045c..de31b4699918 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -793,7 +793,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
null,
getBaseApkPath(),
getBaseRevisionCode(),
- isHasCode() ? ApplicationInfo.FLAG_HAS_CODE : 0,
+ isDeclaredHavingCode() ? ApplicationInfo.FLAG_HAS_CODE : 0,
getClassLoaderName()
));
@@ -879,7 +879,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public int getBannerRes() {
+ public int getBannerResourceId() {
return banner;
}
@@ -934,12 +934,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public int getDataExtractionRulesRes() {
+ public int getDataExtractionRulesResourceId() {
return dataExtractionRules;
}
@Override
- public int getDescriptionRes() {
+ public int getDescriptionResourceId() {
return descriptionRes;
}
@@ -950,7 +950,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public int getFullBackupContentRes() {
+ public int getFullBackupContentResourceId() {
return fullBackupContent;
}
@@ -961,7 +961,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public int getIconRes() {
+ public int getIconResourceId() {
return iconRes;
}
@@ -995,7 +995,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public int getLabelRes() {
+ public int getLabelResourceId() {
return labelRes;
}
@@ -1011,12 +1011,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public int getLocaleConfigRes() {
+ public int getLocaleConfigResourceId() {
return mLocaleConfigRes;
}
@Override
- public int getLogoRes() {
+ public int getLogoResourceId() {
return logo;
}
@@ -1077,7 +1077,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public int getNetworkSecurityConfigRes() {
+ public int getNetworkSecurityConfigResourceId() {
return networkSecurityConfigRes;
}
@@ -1259,7 +1259,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public int getRoundIconRes() {
+ public int getRoundIconResourceId() {
return roundIconRes;
}
@@ -1287,7 +1287,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public int getSharedUserLabelRes() {
+ public int getSharedUserLabelResourceId() {
return sharedUserLabel;
}
@@ -1366,7 +1366,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public int getThemeRes() {
+ public int getThemeResourceId() {
return theme;
}
@@ -1531,17 +1531,17 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public boolean isAllowBackup() {
+ public boolean isBackupAllowed() {
return getBoolean(Booleans.ALLOW_BACKUP);
}
@Override
- public boolean isAllowClearUserData() {
+ public boolean isClearUserDataAllowed() {
return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA);
}
@Override
- public boolean isAllowClearUserDataOnFailedRestore() {
+ public boolean isClearUserDataOnFailedRestoreAllowed() {
return getBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE);
}
@@ -1551,7 +1551,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public boolean isAllowTaskReparenting() {
+ public boolean isTaskReparentingAllowed() {
return getBoolean(Booleans.ALLOW_TASK_REPARENTING);
}
@@ -1574,7 +1574,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public boolean isCantSaveState() {
+ public boolean isSaveStateDisallowed() {
return getBoolean(Booleans.CANT_SAVE_STATE);
}
@@ -1609,7 +1609,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public boolean isExtractNativeLibs() {
+ public boolean isExtractNativeLibrariesRequested() {
return getBoolean(Booleans.EXTRACT_NATIVE_LIBS);
}
@@ -1629,7 +1629,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public boolean isHasCode() {
+ public boolean isDeclaredHavingCode() {
return getBoolean(Booleans.HAS_CODE);
}
@@ -1639,7 +1639,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public boolean isHasFragileUserData() {
+ public boolean isUserDataFragile() {
return getBoolean(Booleans.HAS_FRAGILE_USER_DATA);
}
@@ -1649,7 +1649,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public boolean isKillAfterRestore() {
+ public boolean isKillAfterRestoreAllowed() {
return getBoolean(Booleans.KILL_AFTER_RESTORE);
}
@@ -1746,7 +1746,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
return getBoolean(Booleans.STATIC_SHARED_LIBRARY);
}
- public boolean isSupportsExtraLargeScreens() {
+ public boolean isExtraLargeScreensSupported() {
if (supportsExtraLargeScreens == null) {
return targetSdkVersion >= Build.VERSION_CODES.GINGERBREAD;
}
@@ -1754,7 +1754,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
return supportsExtraLargeScreens;
}
- public boolean isSupportsLargeScreens() {
+ public boolean isLargeScreensSupported() {
if (supportsLargeScreens == null) {
return targetSdkVersion >= Build.VERSION_CODES.DONUT;
}
@@ -1762,16 +1762,16 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
return supportsLargeScreens;
}
- public boolean isSupportsNormalScreens() {
+ public boolean isNormalScreensSupported() {
return supportsNormalScreens == null || supportsNormalScreens;
}
@Override
- public boolean isSupportsRtl() {
+ public boolean isRtlSupported() {
return getBoolean(Booleans.SUPPORTS_RTL);
}
- public boolean isSupportsSmallScreens() {
+ public boolean isSmallScreensSupported() {
if (supportsSmallScreens == null) {
return targetSdkVersion >= Build.VERSION_CODES.DONUT;
}
@@ -1785,7 +1785,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public boolean isUse32BitAbi() {
+ public boolean is32BitAbiPreferred() {
return getBoolean(Booleans.USE_32_BIT_ABI);
}
@@ -1795,12 +1795,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public boolean isUsesCleartextTraffic() {
+ public boolean isCleartextTrafficAllowed() {
return getBoolean(Booleans.USES_CLEARTEXT_TRAFFIC);
}
@Override
- public boolean isUsesNonSdkApi() {
+ public boolean isNonSdkApiRequested() {
return getBoolean(Booleans.USES_NON_SDK_API);
}
@@ -1831,17 +1831,17 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setAllowBackup(boolean value) {
+ public PackageImpl setBackupAllowed(boolean value) {
return setBoolean(Booleans.ALLOW_BACKUP, value);
}
@Override
- public PackageImpl setAllowClearUserData(boolean value) {
+ public PackageImpl setClearUserDataAllowed(boolean value) {
return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA, value);
}
@Override
- public PackageImpl setAllowClearUserDataOnFailedRestore(boolean value) {
+ public PackageImpl setClearUserDataOnFailedRestoreAllowed(boolean value) {
return setBoolean(Booleans.ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, value);
}
@@ -1851,7 +1851,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setAllowTaskReparenting(boolean value) {
+ public PackageImpl setTaskReparentingAllowed(boolean value) {
return setBoolean(Booleans.ALLOW_TASK_REPARENTING, value);
}
@@ -1895,7 +1895,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setBannerRes(int value) {
+ public PackageImpl setBannerResourceId(int value) {
banner = value;
return this;
}
@@ -1912,7 +1912,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setCantSaveState(boolean value) {
+ public PackageImpl setSaveStateDisallowed(boolean value) {
return setBoolean(Booleans.CANT_SAVE_STATE, value);
}
@@ -1958,7 +1958,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setDataExtractionRulesRes(int value) {
+ public PackageImpl setDataExtractionRulesResourceId(int value) {
dataExtractionRules = value;
return this;
}
@@ -1969,7 +1969,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setDescriptionRes(int value) {
+ public PackageImpl setDescriptionResourceId(int value) {
descriptionRes = value;
return this;
}
@@ -1985,7 +1985,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setExtractNativeLibs(boolean value) {
+ public PackageImpl setExtractNativeLibrariesRequested(boolean value) {
return setBoolean(Booleans.EXTRACT_NATIVE_LIBS, value);
}
@@ -1995,7 +1995,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setFullBackupContentRes(int value) {
+ public PackageImpl setFullBackupContentResourceId(int value) {
fullBackupContent = value;
return this;
}
@@ -2017,7 +2017,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setHasCode(boolean value) {
+ public PackageImpl setDeclaredHavingCode(boolean value) {
return setBoolean(Booleans.HAS_CODE, value);
}
@@ -2027,12 +2027,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setHasFragileUserData(boolean value) {
+ public PackageImpl setUserDataFragile(boolean value) {
return setBoolean(Booleans.HAS_FRAGILE_USER_DATA, value);
}
@Override
- public PackageImpl setIconRes(int value) {
+ public PackageImpl setIconResourceId(int value) {
iconRes = value;
return this;
}
@@ -2049,7 +2049,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setKillAfterRestore(boolean value) {
+ public PackageImpl setKillAfterRestoreAllowed(boolean value) {
return setBoolean(Booleans.KILL_AFTER_RESTORE, value);
}
@@ -2060,7 +2060,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setLabelRes(int value) {
+ public PackageImpl setLabelResourceId(int value) {
labelRes = value;
return this;
}
@@ -2082,13 +2082,13 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setLocaleConfigRes(int value) {
+ public PackageImpl setLocaleConfigResourceId(int value) {
mLocaleConfigRes = value;
return this;
}
@Override
- public PackageImpl setLogoRes(int value) {
+ public PackageImpl setLogoResourceId(int value) {
logo = value;
return this;
}
@@ -2154,7 +2154,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setNetworkSecurityConfigRes(int value) {
+ public PackageImpl setNetworkSecurityConfigResourceId(int value) {
networkSecurityConfigRes = value;
return this;
}
@@ -2318,7 +2318,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setRoundIconRes(int value) {
+ public PackageImpl setRoundIconResourceId(int value) {
roundIconRes = value;
return this;
}
@@ -2347,7 +2347,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setSharedUserLabelRes(int value) {
+ public PackageImpl setSharedUserLabelResourceId(int value) {
sharedUserLabel = value;
return this;
}
@@ -2384,7 +2384,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setSupportsExtraLargeScreens(int supportsExtraLargeScreens) {
+ public PackageImpl setExtraLargeScreensSupported(int supportsExtraLargeScreens) {
if (supportsExtraLargeScreens == 1) {
return this;
}
@@ -2394,7 +2394,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setSupportsLargeScreens(int supportsLargeScreens) {
+ public PackageImpl setLargeScreensSupported(int supportsLargeScreens) {
if (supportsLargeScreens == 1) {
return this;
}
@@ -2404,7 +2404,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setSupportsNormalScreens(int supportsNormalScreens) {
+ public PackageImpl setNormalScreensSupported(int supportsNormalScreens) {
if (supportsNormalScreens == 1) {
return this;
}
@@ -2414,12 +2414,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setSupportsRtl(boolean value) {
+ public PackageImpl setRtlSupported(boolean value) {
return setBoolean(Booleans.SUPPORTS_RTL, value);
}
@Override
- public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) {
+ public PackageImpl setSmallScreensSupported(int supportsSmallScreens) {
if (supportsSmallScreens == 1) {
return this;
}
@@ -2452,7 +2452,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setThemeRes(int value) {
+ public PackageImpl setThemeResourceId(int value) {
theme = value;
return this;
}
@@ -2470,7 +2470,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setUse32BitAbi(boolean value) {
+ public PackageImpl set32BitAbiPreferred(boolean value) {
return setBoolean(Booleans.USE_32_BIT_ABI, value);
}
@@ -2480,12 +2480,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal,
}
@Override
- public PackageImpl setUsesCleartextTraffic(boolean value) {
+ public PackageImpl setCleartextTrafficAllowed(boolean value) {
return setBoolean(Booleans.USES_CLEARTEXT_TRAFFIC, value);
}
@Override
- public PackageImpl setUsesNonSdkApi(boolean value) {
+ public PackageImpl setNonSdkApiRequested(boolean value) {
return setBoolean(Booleans.USES_NON_SDK_API, value);
}
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
index ad738730598f..2fdda1210394 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -116,7 +116,7 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestApplication_banner
*/
@DrawableRes
- int getBannerRes();
+ int getBannerResourceId();
/**
* @see PackageInfo#baseRevisionCode
@@ -149,21 +149,21 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestApplication_dataExtractionRules
*/
@XmlRes
- int getDataExtractionRulesRes();
+ int getDataExtractionRulesResourceId();
/**
* @see ApplicationInfo#descriptionRes
* @see R.styleable#AndroidManifestApplication_description
*/
@StringRes // This is actually format="reference"
- int getDescriptionRes();
+ int getDescriptionResourceId();
/**
* @see ApplicationInfo#fullBackupContent
* @see R.styleable#AndroidManifestApplication_fullBackupContent
*/
@XmlRes
- int getFullBackupContentRes();
+ int getFullBackupContentResourceId();
/**
* @see ApplicationInfo#getGwpAsanMode()
@@ -177,14 +177,14 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestApplication_icon
*/
@DrawableRes
- int getIconRes();
+ int getIconResourceId();
/**
* @see ApplicationInfo#labelRes
* @see R.styleable#AndroidManifestApplication_label
*/
@StringRes
- int getLabelRes();
+ int getLabelResourceId();
/**
* @see ApplicationInfo#largestWidthLimitDp
@@ -206,7 +206,7 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestApplication_logo
*/
@DrawableRes
- int getLogoRes();
+ int getLogoResourceId();
/**
* The resource ID used to provide the application's locales configuration.
@@ -214,7 +214,7 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestApplication_localeConfig
*/
@XmlRes
- int getLocaleConfigRes();
+ int getLocaleConfigResourceId();
/**
* @see PackageInfo#getLongVersionCode()
@@ -247,7 +247,7 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestApplication_networkSecurityConfig
*/
@XmlRes
- int getNetworkSecurityConfigRes();
+ int getNetworkSecurityConfigResourceId();
/**
* @see PackageInfo#requiredAccountType
@@ -277,7 +277,7 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestApplication_roundIcon
*/
@DrawableRes
- int getRoundIconRes();
+ int getRoundIconResourceId();
/**
* @see R.styleable#AndroidManifestSdkLibrary_name
@@ -297,7 +297,7 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifest_sharedUserLabel
*/
@StringRes
- int getSharedUserLabelRes();
+ int getSharedUserLabelResourceId();
/**
* @return List of all splits for a package. Note that base.apk is considered a
@@ -336,7 +336,7 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestApplication_theme
*/
@StyleRes
- int getThemeRes();
+ int getThemeResourceId();
/**
* @see ApplicationInfo#uiOptions
@@ -367,19 +367,19 @@ public interface AndroidPackage {
* @see ApplicationInfo#FLAG_ALLOW_BACKUP
* @see R.styleable#AndroidManifestApplication_allowBackup
*/
- boolean isAllowBackup();
+ boolean isBackupAllowed();
/**
* @see ApplicationInfo#FLAG_ALLOW_CLEAR_USER_DATA
* @see R.styleable#AndroidManifestApplication_allowClearUserData
*/
- boolean isAllowClearUserData();
+ boolean isClearUserDataAllowed();
/**
* @see ApplicationInfo#PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE
* @see R.styleable#AndroidManifestApplication_allowClearUserDataOnFailedRestore
*/
- boolean isAllowClearUserDataOnFailedRestore();
+ boolean isClearUserDataOnFailedRestoreAllowed();
/**
* @see ApplicationInfo#PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING
@@ -391,7 +391,7 @@ public interface AndroidPackage {
* @see ApplicationInfo#FLAG_ALLOW_TASK_REPARENTING
* @see R.styleable#AndroidManifestApplication_allowTaskReparenting
*/
- boolean isAllowTaskReparenting();
+ boolean isTaskReparentingAllowed();
/**
* If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
@@ -424,7 +424,7 @@ public interface AndroidPackage {
* @see ApplicationInfo#PRIVATE_FLAG_CANT_SAVE_STATE
* @see R.styleable#AndroidManifestApplication_cantSaveState
*/
- boolean isCantSaveState();
+ boolean isSaveStateDisallowed();
/**
* @see PackageInfo#coreApp
@@ -459,7 +459,7 @@ public interface AndroidPackage {
* @see ApplicationInfo#FLAG_EXTRACT_NATIVE_LIBS
* @see R.styleable#AndroidManifestApplication_extractNativeLibs
*/
- boolean isExtractNativeLibs();
+ boolean isExtractNativeLibrariesRequested();
/**
* @see ApplicationInfo#FLAG_FACTORY_TEST
@@ -481,13 +481,13 @@ public interface AndroidPackage {
* @see ApplicationInfo#FLAG_HAS_CODE
* @see R.styleable#AndroidManifestApplication_hasCode
*/
- boolean isHasCode();
+ boolean isDeclaredHavingCode();
/**
* @see ApplicationInfo#PRIVATE_FLAG_HAS_FRAGILE_USER_DATA
* @see R.styleable#AndroidManifestApplication_hasFragileUserData
*/
- boolean isHasFragileUserData();
+ boolean isUserDataFragile();
/**
* @see ApplicationInfo#PRIVATE_FLAG_ISOLATED_SPLIT_LOADING
@@ -499,7 +499,7 @@ public interface AndroidPackage {
* @see ApplicationInfo#FLAG_KILL_AFTER_RESTORE
* @see R.styleable#AndroidManifestApplication_killAfterRestore
*/
- boolean isKillAfterRestore();
+ boolean isKillAfterRestoreAllowed();
/**
* @see ApplicationInfo#FLAG_LARGE_HEAP
@@ -596,7 +596,7 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestSupportsScreens_xlargeScreens
* @see ApplicationInfo#FLAG_SUPPORTS_XLARGE_SCREENS
*/
- boolean isSupportsExtraLargeScreens();
+ boolean isExtraLargeScreensSupported();
/**
* If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
@@ -605,7 +605,7 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestSupportsScreens_largeScreens
* @see ApplicationInfo#FLAG_SUPPORTS_LARGE_SCREENS
*/
- boolean isSupportsLargeScreens();
+ boolean isLargeScreensSupported();
/**
* If omitted from manifest, returns true.
@@ -613,13 +613,13 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestSupportsScreens_normalScreens
* @see ApplicationInfo#FLAG_SUPPORTS_NORMAL_SCREENS
*/
- boolean isSupportsNormalScreens();
+ boolean isNormalScreensSupported();
/**
* @see ApplicationInfo#FLAG_SUPPORTS_RTL
* @see R.styleable#AndroidManifestApplication_supportsRtl
*/
- boolean isSupportsRtl();
+ boolean isRtlSupported();
/**
* If omitted from manifest, returns true if {@link #getTargetSdkVersion()} >= {@link
@@ -628,7 +628,7 @@ public interface AndroidPackage {
* @see R.styleable#AndroidManifestSupportsScreens_smallScreens
* @see ApplicationInfo#FLAG_SUPPORTS_SMALL_SCREENS
*/
- boolean isSupportsSmallScreens();
+ boolean isSmallScreensSupported();
/**
* @see ApplicationInfo#FLAG_TEST_ONLY
@@ -643,13 +643,13 @@ public interface AndroidPackage {
*
* @see R.attr#use32bitAbi
*/
- boolean isUse32BitAbi();
+ boolean is32BitAbiPreferred();
/**
* @see ApplicationInfo#FLAG_USES_CLEARTEXT_TRAFFIC
* @see R.styleable#AndroidManifestApplication_usesCleartextTraffic
*/
- boolean isUsesCleartextTraffic();
+ boolean isCleartextTrafficAllowed();
/**
* @see ApplicationInfo#PRIVATE_FLAG_USE_EMBEDDED_DEX
@@ -661,7 +661,7 @@ public interface AndroidPackage {
* @see ApplicationInfo#PRIVATE_FLAG_USES_NON_SDK_API
* @see R.styleable#AndroidManifestApplication_usesNonSdkApi
*/
- boolean isUsesNonSdkApi();
+ boolean isNonSdkApiRequested();
/**
* @see ApplicationInfo#FLAG_VM_SAFE_MODE
@@ -892,7 +892,7 @@ public interface AndroidPackage {
/**
* If {@link R.styleable#AndroidManifestApplication_label} is a string literal, this is it.
- * Otherwise, it's stored as {@link #getLabelRes()}.
+ * Otherwise, it's stored as {@link #getLabelResourceId()}.
*
* @see ApplicationInfo#nonLocalizedLabel
* @see R.styleable#AndroidManifestApplication_label
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index 106b149997a7..2c37876dd261 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -160,6 +160,14 @@ public interface PackageState {
/**
* List of shared libraries that this package declares a dependency on. This includes all
* types of libraries, system or app provided and Java or native.
+ * <p/>
+ * This includes libraries declared in the manifest under the following tags:
+ * <ul>
+ * <li>uses-library</li>
+ * <li>uses-native-library</li>
+ * <li>uses-sdk-library</li>
+ * <li>uses-static-library</li>
+ * </ul>
*/
@NonNull
List<SharedLibrary> getSharedLibraryDependencies();
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
index b73ff3480359..ee793c8b2f87 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
@@ -114,7 +114,7 @@ public class ParsedActivityUtils {
return input.error(result);
}
- if (receiver && pkg.isCantSaveState()) {
+ if (receiver && pkg.isSaveStateDisallowed()) {
// A heavy-weight application can not have receivers in its main process
if (Objects.equals(activity.getProcessName(), packageName)) {
return input.error("Heavy-weight applications can not have receivers "
@@ -129,7 +129,7 @@ public class ParsedActivityUtils {
activity.setTheme(sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0))
.setUiOptions(sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, pkg.getUiOptions()));
- activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isAllowTaskReparenting(), sa)
+ activity.setFlags(activity.getFlags() | (flag(ActivityInfo.FLAG_ALLOW_TASK_REPARENTING, R.styleable.AndroidManifestActivity_allowTaskReparenting, pkg.isTaskReparentingAllowed(), sa)
| flag(ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE, R.styleable.AndroidManifestActivity_alwaysRetainTaskState, sa)
| flag(ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH, R.styleable.AndroidManifestActivity_clearTaskOnLaunch, sa)
| flag(ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS, R.styleable.AndroidManifestActivity_excludeFromRecents, sa)
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
index 4cb4dd04f42a..37bed15ba1d7 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
@@ -136,7 +136,7 @@ public class ParsedProviderUtils {
sa.recycle();
}
- if (pkg.isCantSaveState()) {
+ if (pkg.isSaveStateDisallowed()) {
// A heavy-weight application can not have providers in its main process
if (Objects.equals(provider.getProcessName(), packageName)) {
return input.error("Heavy-weight applications can not have providers"
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
index a812257eec92..c15266fc4cbc 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
@@ -115,7 +115,7 @@ public class ParsedServiceUtils {
sa.recycle();
}
- if (pkg.isCantSaveState()) {
+ if (pkg.isSaveStateDisallowed()) {
// A heavy-weight application can not have services in its main process
// We can do direct compare because we intern all strings.
if (Objects.equals(service.getProcessName(), packageName)) {
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index bb36758f1e77..6cb6a9783134 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -163,19 +163,20 @@ public interface ParsingPackage {
ParsingPackage setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture);
- ParsingPackage setAllowBackup(boolean allowBackup);
+ ParsingPackage setBackupAllowed(boolean allowBackup);
- ParsingPackage setAllowClearUserData(boolean allowClearUserData);
+ ParsingPackage setClearUserDataAllowed(boolean allowClearUserData);
- ParsingPackage setAllowClearUserDataOnFailedRestore(boolean allowClearUserDataOnFailedRestore);
+ ParsingPackage setClearUserDataOnFailedRestoreAllowed(
+ boolean allowClearUserDataOnFailedRestore);
- ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting);
+ ParsingPackage setTaskReparentingAllowed(boolean allowTaskReparenting);
ParsingPackage setResourceOverlay(boolean isResourceOverlay);
ParsingPackage setBackupInForeground(boolean backupInForeground);
- ParsingPackage setCantSaveState(boolean cantSaveState);
+ ParsingPackage setSaveStateDisallowed(boolean cantSaveState);
ParsingPackage setDebuggable(boolean debuggable);
@@ -185,19 +186,19 @@ public interface ParsingPackage {
ParsingPackage setExternalStorage(boolean externalStorage);
- ParsingPackage setExtractNativeLibs(boolean extractNativeLibs);
+ ParsingPackage setExtractNativeLibrariesRequested(boolean extractNativeLibs);
ParsingPackage setFullBackupOnly(boolean fullBackupOnly);
- ParsingPackage setHasCode(boolean hasCode);
+ ParsingPackage setDeclaredHavingCode(boolean hasCode);
- ParsingPackage setHasFragileUserData(boolean hasFragileUserData);
+ ParsingPackage setUserDataFragile(boolean hasFragileUserData);
ParsingPackage setGame(boolean isGame);
ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading);
- ParsingPackage setKillAfterRestore(boolean killAfterRestore);
+ ParsingPackage setKillAfterRestoreAllowed(boolean killAfterRestore);
ParsingPackage setLargeHeap(boolean largeHeap);
@@ -231,15 +232,15 @@ public interface ParsingPackage {
ParsingPackage setStaticSharedLibrary(boolean staticSharedLibrary);
- ParsingPackage setSupportsRtl(boolean supportsRtl);
+ ParsingPackage setRtlSupported(boolean supportsRtl);
ParsingPackage setTestOnly(boolean testOnly);
ParsingPackage setUseEmbeddedDex(boolean useEmbeddedDex);
- ParsingPackage setUsesCleartextTraffic(boolean usesCleartextTraffic);
+ ParsingPackage setCleartextTrafficAllowed(boolean usesCleartextTraffic);
- ParsingPackage setUsesNonSdkApi(boolean usesNonSdkApi);
+ ParsingPackage setNonSdkApiRequested(boolean usesNonSdkApi);
ParsingPackage setVisibleToInstantApps(boolean visibleToInstantApps);
@@ -255,7 +256,7 @@ public interface ParsingPackage {
ParsingPackage setBackupAgentName(String backupAgentName);
- ParsingPackage setBannerRes(int banner);
+ ParsingPackage setBannerResourceId(int banner);
ParsingPackage setCategory(int category);
@@ -265,7 +266,7 @@ public interface ParsingPackage {
ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp);
- ParsingPackage setDescriptionRes(int descriptionRes);
+ ParsingPackage setDescriptionResourceId(int descriptionRes);
ParsingPackage setEnabled(boolean enabled);
@@ -281,24 +282,24 @@ public interface ParsingPackage {
ParsingPackage setCrossProfile(boolean crossProfile);
- ParsingPackage setFullBackupContentRes(int fullBackupContentRes);
+ ParsingPackage setFullBackupContentResourceId(int fullBackupContentRes);
- ParsingPackage setDataExtractionRulesRes(int dataExtractionRulesRes);
+ ParsingPackage setDataExtractionRulesResourceId(int dataExtractionRulesRes);
ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
- ParsingPackage setIconRes(int iconRes);
+ ParsingPackage setIconResourceId(int iconRes);
ParsingPackage setInstallLocation(int installLocation);
/** @see R#styleable.AndroidManifest_sharedUserMaxSdkVersion */
ParsingPackage setLeavingSharedUser(boolean leavingSharedUser);
- ParsingPackage setLabelRes(int labelRes);
+ ParsingPackage setLabelResourceId(int labelRes);
ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp);
- ParsingPackage setLogoRes(int logo);
+ ParsingPackage setLogoResourceId(int logo);
ParsingPackage setManageSpaceActivityName(String manageSpaceActivityName);
@@ -308,7 +309,7 @@ public interface ParsingPackage {
ParsingPackage setMaxSdkVersion(int maxSdkVersion);
- ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes);
+ ParsingPackage setNetworkSecurityConfigResourceId(int networkSecurityConfigRes);
ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel);
@@ -334,9 +335,9 @@ public interface ParsingPackage {
ParsingPackage setRestrictedAccountType(String restrictedAccountType);
- ParsingPackage setRoundIconRes(int roundIconRes);
+ ParsingPackage setRoundIconResourceId(int roundIconRes);
- ParsingPackage setSharedUserLabelRes(int sharedUserLabelRes);
+ ParsingPackage setSharedUserLabelResourceId(int sharedUserLabelRes);
ParsingPackage setSigningDetails(@NonNull SigningDetails signingDetails);
@@ -344,23 +345,23 @@ public interface ParsingPackage {
ParsingPackage setStaticSharedLibraryVersion(long staticSharedLibraryVersion);
- ParsingPackage setSupportsLargeScreens(int supportsLargeScreens);
+ ParsingPackage setLargeScreensSupported(int supportsLargeScreens);
- ParsingPackage setSupportsNormalScreens(int supportsNormalScreens);
+ ParsingPackage setNormalScreensSupported(int supportsNormalScreens);
- ParsingPackage setSupportsSmallScreens(int supportsSmallScreens);
+ ParsingPackage setSmallScreensSupported(int supportsSmallScreens);
- ParsingPackage setSupportsExtraLargeScreens(int supportsExtraLargeScreens);
+ ParsingPackage setExtraLargeScreensSupported(int supportsExtraLargeScreens);
ParsingPackage setTargetSandboxVersion(int targetSandboxVersion);
- ParsingPackage setThemeRes(int theme);
+ ParsingPackage setThemeResourceId(int theme);
ParsingPackage setRequestForegroundServiceExemption(boolean requestForegroundServiceExemption);
ParsingPackage setUpgradeKeySets(@NonNull Set<String> upgradeKeySets);
- ParsingPackage setUse32BitAbi(boolean use32BitAbi);
+ ParsingPackage set32BitAbiPreferred(boolean use32BitAbi);
ParsingPackage setVolumeUuid(@Nullable String volumeUuid);
@@ -385,7 +386,7 @@ public interface ParsingPackage {
ParsingPackage setResetEnabledSettingsOnAppDataCleared(
boolean resetEnabledSettingsOnAppDataCleared);
- ParsingPackage setLocaleConfigRes(int localeConfigRes);
+ ParsingPackage setLocaleConfigResourceId(int localeConfigRes);
ParsingPackage setAllowUpdateOwnership(boolean value);
@@ -508,15 +509,15 @@ public interface ParsingPackage {
@Nullable
String getZygotePreloadName();
- boolean isAllowBackup();
+ boolean isBackupAllowed();
- boolean isAllowTaskReparenting();
+ boolean isTaskReparentingAllowed();
boolean isAnyDensity();
boolean isHardwareAccelerated();
- boolean isCantSaveState();
+ boolean isSaveStateDisallowed();
boolean isProfileable();
@@ -528,11 +529,11 @@ public interface ParsingPackage {
boolean isStaticSharedLibrary();
- boolean isSupportsExtraLargeScreens();
+ boolean isExtraLargeScreensSupported();
- boolean isSupportsLargeScreens();
+ boolean isLargeScreensSupported();
- boolean isSupportsNormalScreens();
+ boolean isNormalScreensSupported();
- boolean isSupportsSmallScreens();
+ boolean isSmallScreensSupported();
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 31f291fa948d..fda44e495b89 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -430,7 +430,7 @@ public class ParsingPackageUtils {
}
}
- pkg.setUse32BitAbi(lite.isUse32bitAbi());
+ pkg.set32BitAbiPreferred(lite.isUse32bitAbi());
return input.success(pkg);
} catch (IllegalArgumentException e) {
return input.error(e.getCause() instanceof IOException ? INSTALL_FAILED_INVALID_APK
@@ -466,7 +466,7 @@ public class ParsingPackageUtils {
}
return input.success(result.getResult()
- .setUse32BitAbi(lite.isUse32bitAbi()));
+ .set32BitAbiPreferred(lite.isUse32bitAbi()));
} catch (IOException e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to get path: " + apkFile, e);
@@ -957,10 +957,10 @@ public class ParsingPackageUtils {
// cannot be windowed / resized. Note that an SDK version of 0 is common for
// pre-Doughnut applications.
if (pkg.getTargetSdkVersion() < DONUT
- || (!pkg.isSupportsSmallScreens()
- && !pkg.isSupportsNormalScreens()
- && !pkg.isSupportsLargeScreens()
- && !pkg.isSupportsExtraLargeScreens()
+ || (!pkg.isSmallScreensSupported()
+ && !pkg.isNormalScreensSupported()
+ && !pkg.isLargeScreensSupported()
+ && !pkg.isExtraLargeScreensSupported()
&& !pkg.isResizeable()
&& !pkg.isAnyDensity())) {
adjustPackageToBeUnresizeableAndUnpipable(pkg);
@@ -1052,7 +1052,8 @@ public class ParsingPackageUtils {
return input.success(pkg
.setLeavingSharedUser(leaving)
.setSharedUserId(str.intern())
- .setSharedUserLabelRes(resId(R.styleable.AndroidManifest_sharedUserLabel, sa)));
+ .setSharedUserLabelResourceId(
+ resId(R.styleable.AndroidManifest_sharedUserLabel, sa)));
}
private static ParseResult<ParsingPackage> parseKeySets(ParseInput input,
@@ -1885,7 +1886,7 @@ public class ParsingPackageUtils {
TypedValue labelValue = sa.peekValue(R.styleable.AndroidManifestApplication_label);
if (labelValue != null) {
- pkg.setLabelRes(labelValue.resourceId);
+ pkg.setLabelResourceId(labelValue.resourceId);
if (labelValue.resourceId == 0) {
pkg.setNonLocalizedLabel(labelValue.coerceToString());
}
@@ -1906,7 +1907,7 @@ public class ParsingPackageUtils {
pkg.setManageSpaceActivityName(manageSpaceActivityName);
}
- if (pkg.isAllowBackup()) {
+ if (pkg.isBackupAllowed()) {
// backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
// and restoreAnyVersion are only relevant if backup is possible for the
// given application.
@@ -1924,7 +1925,7 @@ public class ParsingPackageUtils {
}
pkg.setBackupAgentName(backupAgentName)
- .setKillAfterRestore(bool(true,
+ .setKillAfterRestoreAllowed(bool(true,
R.styleable.AndroidManifestApplication_killAfterRestore, sa))
.setRestoreAnyVersion(bool(false,
R.styleable.AndroidManifestApplication_restoreAnyVersion, sa))
@@ -1950,7 +1951,7 @@ public class ParsingPackageUtils {
fullBackupContent = v.data == 0 ? -1 : 0;
}
- pkg.setFullBackupContentRes(fullBackupContent);
+ pkg.setFullBackupContentResourceId(fullBackupContent);
}
if (DEBUG_BACKUP) {
Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName);
@@ -2024,7 +2025,7 @@ public class ParsingPackageUtils {
String processName = processNameResult.getResult();
pkg.setProcessName(processName);
- if (pkg.isCantSaveState()) {
+ if (pkg.isSaveStateDisallowed()) {
// A heavy-weight application can not be in a custom process.
// We can do direct compare because we intern all strings.
if (processName != null && !processName.equals(pkgName)) {
@@ -2224,31 +2225,31 @@ public class ParsingPackageUtils {
// CHECKSTYLE:off
pkg
// Default true
- .setAllowBackup(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa))
- .setAllowClearUserData(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa))
- .setAllowClearUserDataOnFailedRestore(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa))
+ .setBackupAllowed(bool(true, R.styleable.AndroidManifestApplication_allowBackup, sa))
+ .setClearUserDataAllowed(bool(true, R.styleable.AndroidManifestApplication_allowClearUserData, sa))
+ .setClearUserDataOnFailedRestoreAllowed(bool(true, R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, sa))
.setAllowNativeHeapPointerTagging(bool(true, R.styleable.AndroidManifestApplication_allowNativeHeapPointerTagging, sa))
.setEnabled(bool(true, R.styleable.AndroidManifestApplication_enabled, sa))
- .setExtractNativeLibs(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa))
- .setHasCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa))
+ .setExtractNativeLibrariesRequested(bool(true, R.styleable.AndroidManifestApplication_extractNativeLibs, sa))
+ .setDeclaredHavingCode(bool(true, R.styleable.AndroidManifestApplication_hasCode, sa))
// Default false
- .setAllowTaskReparenting(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa))
- .setCantSaveState(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa))
+ .setTaskReparentingAllowed(bool(false, R.styleable.AndroidManifestApplication_allowTaskReparenting, sa))
+ .setSaveStateDisallowed(bool(false, R.styleable.AndroidManifestApplication_cantSaveState, sa))
.setCrossProfile(bool(false, R.styleable.AndroidManifestApplication_crossProfile, sa))
.setDebuggable(bool(false, R.styleable.AndroidManifestApplication_debuggable, sa))
.setDefaultToDeviceProtectedStorage(bool(false, R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, sa))
.setDirectBootAware(bool(false, R.styleable.AndroidManifestApplication_directBootAware, sa))
.setForceQueryable(bool(false, R.styleable.AndroidManifestApplication_forceQueryable, sa))
.setGame(bool(false, R.styleable.AndroidManifestApplication_isGame, sa))
- .setHasFragileUserData(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa))
+ .setUserDataFragile(bool(false, R.styleable.AndroidManifestApplication_hasFragileUserData, sa))
.setLargeHeap(bool(false, R.styleable.AndroidManifestApplication_largeHeap, sa))
.setMultiArch(bool(false, R.styleable.AndroidManifestApplication_multiArch, sa))
.setPreserveLegacyExternalStorage(bool(false, R.styleable.AndroidManifestApplication_preserveLegacyExternalStorage, sa))
.setRequiredForAllUsers(bool(false, R.styleable.AndroidManifestApplication_requiredForAllUsers, sa))
- .setSupportsRtl(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa))
+ .setRtlSupported(bool(false, R.styleable.AndroidManifestApplication_supportsRtl, sa))
.setTestOnly(bool(false, R.styleable.AndroidManifestApplication_testOnly, sa))
.setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa))
- .setUsesNonSdkApi(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
+ .setNonSdkApiRequested(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
.setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa))
.setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa))
.setAttributionsAreUserVisible(bool(false, R.styleable.AndroidManifestApplication_attributionsAreUserVisible, sa))
@@ -2260,7 +2261,7 @@ public class ParsingPackageUtils {
.setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
.setHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
.setRequestLegacyExternalStorage(bool(targetSdk < Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, sa))
- .setUsesCleartextTraffic(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa))
+ .setCleartextTrafficAllowed(bool(targetSdk < Build.VERSION_CODES.P, R.styleable.AndroidManifestApplication_usesCleartextTraffic, sa))
// Ints Default 0
.setUiOptions(anInt(R.styleable.AndroidManifestApplication_uiOptions, sa))
// Ints
@@ -2269,16 +2270,16 @@ public class ParsingPackageUtils {
.setMaxAspectRatio(aFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, sa))
.setMinAspectRatio(aFloat(R.styleable.AndroidManifestApplication_minAspectRatio, sa))
// Resource ID
- .setBannerRes(resId(R.styleable.AndroidManifestApplication_banner, sa))
- .setDescriptionRes(resId(R.styleable.AndroidManifestApplication_description, sa))
- .setIconRes(resId(R.styleable.AndroidManifestApplication_icon, sa))
- .setLogoRes(resId(R.styleable.AndroidManifestApplication_logo, sa))
- .setNetworkSecurityConfigRes(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
- .setRoundIconRes(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
- .setThemeRes(resId(R.styleable.AndroidManifestApplication_theme, sa))
- .setDataExtractionRulesRes(
+ .setBannerResourceId(resId(R.styleable.AndroidManifestApplication_banner, sa))
+ .setDescriptionResourceId(resId(R.styleable.AndroidManifestApplication_description, sa))
+ .setIconResourceId(resId(R.styleable.AndroidManifestApplication_icon, sa))
+ .setLogoResourceId(resId(R.styleable.AndroidManifestApplication_logo, sa))
+ .setNetworkSecurityConfigResourceId(resId(R.styleable.AndroidManifestApplication_networkSecurityConfig, sa))
+ .setRoundIconResourceId(resId(R.styleable.AndroidManifestApplication_roundIcon, sa))
+ .setThemeResourceId(resId(R.styleable.AndroidManifestApplication_theme, sa))
+ .setDataExtractionRulesResourceId(
resId(R.styleable.AndroidManifestApplication_dataExtractionRules, sa))
- .setLocaleConfigRes(resId(R.styleable.AndroidManifestApplication_localeConfig, sa))
+ .setLocaleConfigResourceId(resId(R.styleable.AndroidManifestApplication_localeConfig, sa))
// Strings
.setClassLoaderName(string(R.styleable.AndroidManifestApplication_classLoader, sa))
.setRequiredAccountType(string(R.styleable.AndroidManifestApplication_requiredAccountType, sa))
@@ -2883,13 +2884,13 @@ public class ParsingPackageUtils {
// This is a trick to get a boolean and still able to detect
// if a value was actually set.
return input.success(pkg
- .setSupportsSmallScreens(
+ .setSmallScreensSupported(
anInt(1, R.styleable.AndroidManifestSupportsScreens_smallScreens, sa))
- .setSupportsNormalScreens(
+ .setNormalScreensSupported(
anInt(1, R.styleable.AndroidManifestSupportsScreens_normalScreens, sa))
- .setSupportsLargeScreens(
+ .setLargeScreensSupported(
anInt(1, R.styleable.AndroidManifestSupportsScreens_largeScreens, sa))
- .setSupportsExtraLargeScreens(
+ .setExtraLargeScreensSupported(
anInt(1, R.styleable.AndroidManifestSupportsScreens_xlargeScreens, sa))
.setResizeable(
anInt(1, R.styleable.AndroidManifestSupportsScreens_resizeable, sa))
diff --git a/services/core/java/com/android/server/power/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java
index 223bd551b71d..0dc5f76dfd92 100644
--- a/services/core/java/com/android/server/power/LowPowerStandbyController.java
+++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java
@@ -16,6 +16,7 @@
package com.android.server.power;
+import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST;
import static android.os.PowerManager.lowPowerStandbyAllowedReasonsToString;
import android.Manifest;
@@ -59,6 +60,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.LocalServices;
+import com.android.server.PowerAllowlistInternal;
import com.android.server.net.NetworkPolicyManagerInternal;
import org.xmlpull.v1.XmlPullParser;
@@ -134,7 +136,7 @@ public class LowPowerStandbyController {
@GuardedBy("mLock")
private boolean mEnableCustomPolicy;
- private final BroadcastReceiver mIdleBroadcastReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
@@ -150,6 +152,8 @@ public class LowPowerStandbyController {
}
}
};
+ private final TempAllowlistChangeListener mTempAllowlistChangeListener =
+ new TempAllowlistChangeListener();
private final BroadcastReceiver mPackageBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -318,7 +322,7 @@ public class LowPowerStandbyController {
updateSettingsLocked();
if (mIsEnabled) {
- registerBroadcastReceiver();
+ registerListeners();
}
}
@@ -594,7 +598,7 @@ public class LowPowerStandbyController {
onNonInteractive();
}
- registerBroadcastReceiver();
+ registerListeners();
}
@GuardedBy("mLock")
@@ -604,7 +608,7 @@ public class LowPowerStandbyController {
}
cancelStandbyTimeoutAlarmLocked();
- unregisterBroadcastReceiver();
+ unregisterListeners();
updateActiveLocked();
}
@@ -629,13 +633,13 @@ public class LowPowerStandbyController {
}
}
- private void registerBroadcastReceiver() {
+ private void registerListeners() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
- mContext.registerReceiver(mIdleBroadcastReceiver, intentFilter);
+ mContext.registerReceiver(mBroadcastReceiver, intentFilter);
IntentFilter packageFilter = new IntentFilter();
packageFilter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
@@ -648,12 +652,18 @@ public class LowPowerStandbyController {
userFilter.addAction(Intent.ACTION_USER_ADDED);
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
+
+ PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class);
+ pai.registerTempAllowlistChangeListener(mTempAllowlistChangeListener);
}
- private void unregisterBroadcastReceiver() {
- mContext.unregisterReceiver(mIdleBroadcastReceiver);
+ private void unregisterListeners() {
+ mContext.unregisterReceiver(mBroadcastReceiver);
mContext.unregisterReceiver(mPackageBroadcastReceiver);
mContext.unregisterReceiver(mUserReceiver);
+
+ PowerAllowlistInternal pai = LocalServices.getService(PowerAllowlistInternal.class);
+ pai.unregisterTempAllowlistChangeListener(mTempAllowlistChangeListener);
}
@GuardedBy("mLock")
@@ -1197,4 +1207,18 @@ public class LowPowerStandbyController {
onSettingsChanged();
}
}
+
+ final class TempAllowlistChangeListener implements
+ PowerAllowlistInternal.TempAllowlistChangeListener {
+ @Override
+ public void onAppAdded(int uid) {
+ addToAllowlistInternal(uid, LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST);
+ }
+
+ @Override
+ public void onAppRemoved(int uid) {
+ removeFromAllowlistInternal(uid,
+ LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/sensors/SensorManagerInternal.java b/services/core/java/com/android/server/sensors/SensorManagerInternal.java
index f17e5e73ceb0..41c2fbfd3314 100644
--- a/services/core/java/com/android/server/sensors/SensorManagerInternal.java
+++ b/services/core/java/com/android/server/sensors/SensorManagerInternal.java
@@ -58,7 +58,7 @@ public abstract class SensorManagerInternal {
* @return The sensor handle.
*/
public abstract int createRuntimeSensor(int deviceId, int type, @NonNull String name,
- @NonNull String vendor, @NonNull RuntimeSensorStateChangeCallback callback);
+ @NonNull String vendor, @NonNull RuntimeSensorCallback callback);
/**
* Unregisters the sensor with the given handle from the framework.
@@ -95,11 +95,12 @@ public abstract class SensorManagerInternal {
* {@link #createRuntimeSensor}, i.e. the dynamic sensors created via the dynamic sensor HAL are
* not covered.
*/
- public interface RuntimeSensorStateChangeCallback {
+ public interface RuntimeSensorCallback {
/**
* Invoked when the listeners of the runtime sensor have changed.
+ * Returns an error code if the invocation was unsuccessful, zero otherwise.
*/
- void onStateChanged(boolean enabled, int samplingPeriodMicros,
+ int onConfigurationChanged(int handle, boolean enabled, int samplingPeriodMicros,
int batchReportLatencyMicros);
}
}
diff --git a/services/core/java/com/android/server/sensors/SensorService.java b/services/core/java/com/android/server/sensors/SensorService.java
index d8e3bddd6432..979065950dc4 100644
--- a/services/core/java/com/android/server/sensors/SensorService.java
+++ b/services/core/java/com/android/server/sensors/SensorService.java
@@ -56,8 +56,7 @@ public class SensorService extends SystemService {
private static native void unregisterProximityActiveListenerNative(long ptr);
private static native int registerRuntimeSensorNative(long ptr, int deviceId, int type,
- String name, String vendor,
- SensorManagerInternal.RuntimeSensorStateChangeCallback callback);
+ String name, String vendor, SensorManagerInternal.RuntimeSensorCallback callback);
private static native void unregisterRuntimeSensorNative(long ptr, int handle);
private static native boolean sendRuntimeSensorEventNative(long ptr, int handle, int type,
long timestampNanos, float[] values);
@@ -96,7 +95,7 @@ public class SensorService extends SystemService {
class LocalService extends SensorManagerInternal {
@Override
public int createRuntimeSensor(int deviceId, int type, @NonNull String name,
- @NonNull String vendor, @NonNull RuntimeSensorStateChangeCallback callback) {
+ @NonNull String vendor, @NonNull RuntimeSensorCallback callback) {
synchronized (mLock) {
int handle = registerRuntimeSensorNative(mPtr, deviceId, type, name, vendor,
callback);
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index f8294491b4f6..61c137ed1c5b 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -1140,7 +1140,8 @@ public class TvInteractiveAppManagerService extends SystemService {
@Override
- public void notifyRecordingStarted(IBinder sessionToken, String recordingId, int userId) {
+ public void notifyRecordingStarted(IBinder sessionToken, String recordingId,
+ String requestId, int userId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
@@ -1151,7 +1152,8 @@ public class TvInteractiveAppManagerService extends SystemService {
try {
SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
- getSessionLocked(sessionState).notifyRecordingStarted(recordingId);
+ getSessionLocked(sessionState).notifyRecordingStarted(
+ recordingId, requestId);
} catch (RemoteException | SessionNotFoundException e) {
Slogf.e(TAG, "error in notifyRecordingStarted", e);
}
@@ -2831,7 +2833,7 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
- public void onRequestStartRecording(Uri programUri) {
+ public void onRequestStartRecording(String requestId, Uri programUri) {
synchronized (mLock) {
if (DEBUG) {
Slogf.d(TAG, "onRequestStartRecording: " + programUri);
@@ -2840,7 +2842,8 @@ public class TvInteractiveAppManagerService extends SystemService {
return;
}
try {
- mSessionState.mClient.onRequestStartRecording(programUri, mSessionState.mSeq);
+ mSessionState.mClient.onRequestStartRecording(
+ requestId, programUri, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onRequestStartRecording", e);
}
@@ -2866,7 +2869,7 @@ public class TvInteractiveAppManagerService extends SystemService {
@Override
public void onRequestScheduleRecording(
- String inputId, Uri channelUri, Uri programUri, Bundle params) {
+ String requestId, String inputId, Uri channelUri, Uri programUri, Bundle params) {
synchronized (mLock) {
if (DEBUG) {
Slogf.d(TAG, "onRequestScheduleRecording");
@@ -2876,7 +2879,7 @@ public class TvInteractiveAppManagerService extends SystemService {
}
try {
mSessionState.mClient.onRequestScheduleRecording(
- inputId, channelUri, programUri, params, mSessionState.mSeq);
+ requestId, inputId, channelUri, programUri, params, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onRequestScheduleRecording", e);
}
@@ -2884,8 +2887,8 @@ public class TvInteractiveAppManagerService extends SystemService {
}
@Override
- public void onRequestScheduleRecording2(String inputId, Uri channelUri, long start,
- long duration, int repeat, Bundle params) {
+ public void onRequestScheduleRecording2(String inputId, String requestId, Uri channelUri,
+ long start, long duration, int repeat, Bundle params) {
synchronized (mLock) {
if (DEBUG) {
Slogf.d(TAG, "onRequestScheduleRecording2");
@@ -2894,8 +2897,8 @@ public class TvInteractiveAppManagerService extends SystemService {
return;
}
try {
- mSessionState.mClient.onRequestScheduleRecording2(inputId, channelUri, start,
- duration, repeat, params, mSessionState.mSeq);
+ mSessionState.mClient.onRequestScheduleRecording2(requestId, inputId,
+ channelUri, start, duration, repeat, params, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onRequestScheduleRecording2", e);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fe9306be2aef..626bac449c64 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1014,6 +1014,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing
|= w.mAttrs.preferMinimalPostProcessing;
+ mTmpApplySurfaceChangesTransactionState.disableHdrConversion
+ |= !(w.mAttrs.isHdrConversionEnabled());
+
final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
.getPreferredModeId(w);
@@ -4891,6 +4894,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
+ mTmpApplySurfaceChangesTransactionState.disableHdrConversion,
true /* inTraversal, must call performTraversalInTrans... below */);
}
// If the display now has content, or no longer has content, update recording.
@@ -5095,6 +5099,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
public int preferredModeId;
public float preferredMinRefreshRate;
public float preferredMaxRefreshRate;
+ public boolean disableHdrConversion;
void reset() {
displayHasContent = false;
@@ -5105,6 +5110,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
preferredModeId = 0;
preferredMinRefreshRate = 0;
preferredMaxRefreshRate = 0;
+ disableHdrConversion = false;
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 294e90b858a4..c2afeaf8990e 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -904,37 +904,46 @@ class TaskFragment extends WindowContainer<WindowContainer> {
* starting (about to be visible) activity that is fullscreen (opaque).
* @param starting The currently starting activity or null if there is none.
*/
- @VisibleForTesting
- boolean isTranslucent(ActivityRecord starting) {
+ boolean isTranslucent(@Nullable ActivityRecord starting) {
if (!isAttached() || isForceHidden() || isForceTranslucent()) {
return true;
}
final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
- PooledLambda.__(ActivityRecord.class), starting);
+ PooledLambda.__(ActivityRecord.class), starting, false /* including*/);
final ActivityRecord opaque = getActivity(p);
p.recycle();
return opaque == null;
}
- private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
- if (r.finishing) {
- // We don't factor in finishing activities when determining translucency since
- // they will be gone soon.
- return false;
+ /**
+ * Whether the TaskFragment should be treated as translucent for the current transition.
+ * This is different from {@link #isTranslucent(ActivityRecord)} as this function also checks
+ * finishing activities when the TaskFragment itself is becoming invisible.
+ */
+ boolean isTranslucentForTransition() {
+ if (!isAttached() || isForceHidden() || isForceTranslucent()) {
+ return true;
}
+ // Including finishing Activity if the TaskFragment is becoming invisible in the transition.
+ final boolean includingFinishing = !isVisibleRequested();
+ final PooledPredicate p = PooledLambda.obtainPredicate(TaskFragment::isOpaqueActivity,
+ PooledLambda.__(ActivityRecord.class), null /* starting */, includingFinishing);
+ final ActivityRecord opaque = getActivity(p);
+ p.recycle();
+ return opaque == null;
+ }
+ private static boolean isOpaqueActivity(@NonNull ActivityRecord r,
+ @Nullable ActivityRecord starting, boolean includingFinishing) {
if (!r.visibleIgnoringKeyguard && r != starting) {
// Also ignore invisible activities that are not the currently starting
// activity (about to be visible).
return false;
}
- if (r.occludesParent()) {
- // Root task isn't translucent if it has at least one fullscreen activity
- // that is visible.
- return true;
- }
- return false;
+ // TaskFragment isn't translucent if it has at least one fullscreen activity that is
+ // visible.
+ return r.occludesParent(includingFinishing);
}
ActivityRecord getTopNonFinishingActivity() {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index d23b9540f451..43dbcc886d59 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1447,22 +1447,25 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
private static boolean isTranslucent(@NonNull WindowContainer wc) {
final TaskFragment taskFragment = wc.asTaskFragment();
- if (taskFragment != null) {
- if (taskFragment.isTranslucent(null /* starting */)) {
- return true;
- }
- final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
- if (adjacentTaskFragment != null) {
- // Treat the TaskFragment as translucent if its adjacent TF is, otherwise everything
- // behind two adjacent TaskFragments are occluded.
- return adjacentTaskFragment.isTranslucent(null /* starting */);
- }
+ if (taskFragment == null) {
+ return !wc.fillsParent();
+ }
+
+ // Check containers differently as they are affected by child visibility.
+
+ if (taskFragment.isTranslucentForTransition()) {
+ // TaskFragment doesn't contain occluded ActivityRecord.
+ return true;
+ }
+ final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
+ if (adjacentTaskFragment != null) {
+ // When the TaskFragment has an adjacent TaskFragment, sibling behind them should be
+ // hidden unless any of them are translucent.
+ return adjacentTaskFragment.isTranslucentForTransition();
+ } else {
+ // Non-filling without adjacent is considered as translucent.
+ return !wc.fillsParent();
}
- // TODO(b/172695805): hierarchical check. This is non-trivial because for containers
- // it is effected by child visibility but needs to work even
- // before visibility is committed. This means refactoring some
- // checks to use requested visibility.
- return !wc.fillsParent();
}
/**
@@ -2019,7 +2022,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
final DisplayContent dc = wc.asDisplayContent();
if (dc == null || !mChanges.get(dc).hasChanged()) continue;
dc.sendNewConfiguration();
- setReady(dc, true);
+ // Set to ready if no other change controls the ready state. But if there is, such as
+ // if an activity is pausing, it will call setReady(ar, false) and wait for the next
+ // resumed activity. Then do not set to ready because the transition only contains
+ // partial participants. Otherwise the transition may only handle HIDE and miss OPEN.
+ if (!mReadyTracker.mUsed) {
+ setReady(dc, true);
+ }
}
}
diff --git a/services/core/jni/com_android_server_display_DisplayControl.cpp b/services/core/jni/com_android_server_display_DisplayControl.cpp
index db7fced0822a..77e83242b3a5 100644
--- a/services/core/jni/com_android_server_display_DisplayControl.cpp
+++ b/services/core/jni/com_android_server_display_DisplayControl.cpp
@@ -110,6 +110,15 @@ static jintArray nativeGetSupportedHdrOutputTypes(JNIEnv* env, jclass clazz) {
return array;
}
+static jboolean nativeGetHdrOutputConversionSupport(JNIEnv* env, jclass clazz) {
+ bool isSupported;
+ status_t err = SurfaceComposerClient::getHdrOutputConversionSupport(&isSupported);
+ if (err == OK) {
+ return isSupported;
+ }
+ return JNI_FALSE;
+}
+
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
ScopedLongArrayRW values(env, env->NewLongArray(displayIds.size()));
@@ -150,6 +159,8 @@ static const JNINativeMethod sDisplayMethods[] = {
(void*)nativeSetHdrConversionMode },
{"nativeGetSupportedHdrOutputTypes", "()[I",
(void*)nativeGetSupportedHdrOutputTypes },
+ {"nativeGetHdrOutputConversionSupport", "()Z",
+ (void*) nativeGetHdrOutputConversionSupport },
// clang-format on
};
diff --git a/services/core/jni/com_android_server_sensor_SensorService.cpp b/services/core/jni/com_android_server_sensor_SensorService.cpp
index 10d8b42c2979..356e9a95e311 100644
--- a/services/core/jni/com_android_server_sensor_SensorService.cpp
+++ b/services/core/jni/com_android_server_sensor_SensorService.cpp
@@ -32,13 +32,13 @@
"com/android/server/sensors/SensorManagerInternal$ProximityActiveListener"
#define RUNTIME_SENSOR_CALLBACK_CLASS \
- "com/android/server/sensors/SensorManagerInternal$RuntimeSensorStateChangeCallback"
+ "com/android/server/sensors/SensorManagerInternal$RuntimeSensorCallback"
namespace android {
static JavaVM* sJvm = nullptr;
static jmethodID sMethodIdOnProximityActive;
-static jmethodID sMethodIdOnStateChanged;
+static jmethodID sMethodIdOnConfigurationChanged;
class NativeSensorService {
public:
@@ -67,13 +67,13 @@ private:
};
sp<ProximityActiveListenerDelegate> mProximityActiveListenerDelegate;
- class RuntimeSensorCallbackDelegate : public SensorService::RuntimeSensorStateChangeCallback {
+ class RuntimeSensorCallbackDelegate : public SensorService::RuntimeSensorCallback {
public:
RuntimeSensorCallbackDelegate(JNIEnv* env, jobject callback);
~RuntimeSensorCallbackDelegate();
- void onStateChanged(bool enabled, int64_t samplingPeriodNs,
- int64_t batchReportLatencyNs) override;
+ status_t onConfigurationChanged(int32_t handle, bool enabled, int64_t samplingPeriodNs,
+ int64_t batchReportLatencyNs) override;
private:
jobject mCallback;
@@ -231,12 +231,13 @@ NativeSensorService::RuntimeSensorCallbackDelegate::~RuntimeSensorCallbackDelega
AndroidRuntime::getJNIEnv()->DeleteGlobalRef(mCallback);
}
-void NativeSensorService::RuntimeSensorCallbackDelegate::onStateChanged(
- bool enabled, int64_t samplingPeriodNs, int64_t batchReportLatencyNs) {
+status_t NativeSensorService::RuntimeSensorCallbackDelegate::onConfigurationChanged(
+ int32_t handle, bool enabled, int64_t samplingPeriodNs, int64_t batchReportLatencyNs) {
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
- jniEnv->CallVoidMethod(mCallback, sMethodIdOnStateChanged, static_cast<jboolean>(enabled),
- static_cast<jint>(ns2us(samplingPeriodNs)),
- static_cast<jint>(ns2us(batchReportLatencyNs)));
+ return jniEnv->CallIntMethod(mCallback, sMethodIdOnConfigurationChanged,
+ static_cast<jint>(handle), static_cast<jboolean>(enabled),
+ static_cast<jint>(ns2us(samplingPeriodNs)),
+ static_cast<jint>(ns2us(batchReportLatencyNs)));
}
static jlong startSensorServiceNative(JNIEnv* env, jclass, jobject listener) {
@@ -292,8 +293,8 @@ int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env) {
jclass listenerClass = FindClassOrDie(env, PROXIMITY_ACTIVE_CLASS);
sMethodIdOnProximityActive = GetMethodIDOrDie(env, listenerClass, "onProximityActive", "(Z)V");
jclass runtimeSensorCallbackClass = FindClassOrDie(env, RUNTIME_SENSOR_CALLBACK_CLASS);
- sMethodIdOnStateChanged =
- GetMethodIDOrDie(env, runtimeSensorCallbackClass, "onStateChanged", "(ZII)V");
+ sMethodIdOnConfigurationChanged =
+ GetMethodIDOrDie(env, runtimeSensorCallbackClass, "onConfigurationChanged", "(IZII)I");
return jniRegisterNativeMethods(env, "com/android/server/sensors/SensorService", methods,
NELEM(methods));
}
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index 447c67fa44f8..d262fb7e163f 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -83,7 +83,10 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
}
@Override
- public void onFinalResponseReceived(ComponentName componentName, Void response) {
+ public void onFinalResponseReceived(
+ ComponentName componentName,
+ Void response) {
+ setChosenMetric(componentName);
respondToClientWithResponseAndFinish();
}
@@ -114,6 +117,8 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
Log.i(TAG, "respondToClientWithResponseAndFinish");
if (isSessionCancelled()) {
// TODO: Differentiate btw cancelled and false
+ mChosenProviderMetric.setChosenProviderStatus(
+ MetricUtilities.METRICS_PROVIDER_STATUS_FINAL_SUCCESS);
logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ true);
finishSession(/*propagateCancellation=*/true);
return;
@@ -122,6 +127,8 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
mClientCallback.onSuccess();
logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ true);
} catch (RemoteException e) {
+ mChosenProviderMetric.setChosenProviderStatus(
+ MetricUtilities.METRICS_PROVIDER_STATUS_FINAL_FAILURE);
Log.i(TAG, "Issue while propagating the response to the client");
logApiCalled(RequestType.CLEAR_CREDENTIALS, /* isSuccessful */ false);
}
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index c8518c5587a8..01e7fb95b003 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -16,6 +16,9 @@
package com.android.server.credentials;
+import static com.android.server.credentials.MetricUtilities.METRICS_PROVIDER_STATUS_FINAL_FAILURE;
+import static com.android.server.credentials.MetricUtilities.METRICS_PROVIDER_STATUS_FINAL_SUCCESS;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
@@ -94,9 +97,14 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
public void onFinalResponseReceived(ComponentName componentName,
@Nullable CreateCredentialResponse response) {
Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString());
+ setChosenMetric(componentName);
if (response != null) {
+ mChosenProviderMetric.setChosenProviderStatus(
+ METRICS_PROVIDER_STATUS_FINAL_SUCCESS);
respondToClientWithResponseAndFinish(response);
} else {
+ mChosenProviderMetric.setChosenProviderStatus(
+ METRICS_PROVIDER_STATUS_FINAL_FAILURE);
respondToClientWithErrorAndFinish(CreateCredentialException.TYPE_NO_CREATE_OPTIONS,
"Invalid response");
}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 34101fe4bd15..03340512fe56 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -357,7 +357,6 @@ public final class CredentialManagerService
final int userId = UserHandle.getCallingUserId();
final int callingUid = Binder.getCallingUid();
enforceCallingPackage(callingPackage, callingUid);
-
// New request session, scoped for this request only.
final GetRequestSession session =
new GetRequestSession(
@@ -497,6 +496,7 @@ public final class CredentialManagerService
Log.i(TAG, "starting executeCreateCredential with callingPackage: "
+ callingPackage);
ICancellationSignal cancelTransport = CancellationSignal.createTransport();
+
final int userId = UserHandle.getCallingUserId();
final int callingUid = Binder.getCallingUid();
enforceCallingPackage(callingPackage, callingUid);
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index 332499911f9c..14b45b2f2463 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -16,6 +16,9 @@
package com.android.server.credentials;
+import static com.android.server.credentials.MetricUtilities.METRICS_PROVIDER_STATUS_FINAL_FAILURE;
+import static com.android.server.credentials.MetricUtilities.METRICS_PROVIDER_STATUS_FINAL_SUCCESS;
+
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
@@ -87,9 +90,14 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest
public void onFinalResponseReceived(ComponentName componentName,
@Nullable GetCredentialResponse response) {
Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString());
+ setChosenMetric(componentName);
if (response != null) {
+ mChosenProviderMetric.setChosenProviderStatus(
+ METRICS_PROVIDER_STATUS_FINAL_SUCCESS);
respondToClientWithResponseAndFinish(response);
} else {
+ mChosenProviderMetric.setChosenProviderStatus(
+ METRICS_PROVIDER_STATUS_FINAL_FAILURE);
respondToClientWithErrorAndFinish(GetCredentialException.TYPE_NO_CREDENTIAL,
"Invalid response from provider");
}
diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
new file mode 100644
index 000000000000..27d9836d9b66
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.credentials;
+
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CLEAR_CREDENTIAL;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CREATE_CREDENTIAL;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_GET_CREDENTIAL;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_CLIENT_CANCELED;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_FAILURE;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_SUCCESS;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_USER_CANCELED;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_FINAL_FAILURE;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_FINAL_SUCCESS;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_QUERY_FAILURE;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_QUERY_SUCCESS;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_UNKNOWN;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+/**
+ * For all future metric additions, this will contain their names for local usage after importing
+ * from {@link com.android.internal.util.FrameworkStatsLog}.
+ */
+public class MetricUtilities {
+
+ private static final String TAG = "MetricUtilities";
+
+ // Metrics constants
+ protected static final int METRICS_API_NAME_UNKNOWN =
+ CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_UNKNOWN;
+ protected static final int METRICS_API_NAME_GET_CREDENTIAL =
+ CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_GET_CREDENTIAL;
+ protected static final int METRICS_API_NAME_CREATE_CREDENTIAL =
+ CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CREATE_CREDENTIAL;
+ protected static final int METRICS_API_NAME_CLEAR_CREDENTIAL =
+ CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CLEAR_CREDENTIAL;
+ // TODO add isEnabled
+ protected static final int METRICS_API_STATUS_SUCCESS =
+ CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_SUCCESS;
+ protected static final int METRICS_API_STATUS_FAILURE =
+ CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_FAILURE;
+ protected static final int METRICS_API_STATUS_CLIENT_CANCEL =
+ CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_CLIENT_CANCELED;
+ protected static final int METRICS_API_STATUS_USER_CANCEL =
+ CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_USER_CANCELED;
+ protected static final int METRICS_PROVIDER_STATUS_FINAL_FAILURE =
+ CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_FINAL_FAILURE;
+ protected static final int METRICS_PROVIDER_STATUS_QUERY_FAILURE =
+ CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_QUERY_FAILURE;
+ protected static final int METRICS_PROVIDER_STATUS_FINAL_SUCCESS =
+ CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_FINAL_SUCCESS;
+ protected static final int METRICS_PROVIDER_STATUS_QUERY_SUCCESS =
+ CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_QUERY_SUCCESS;
+ protected static final int METRICS_PROVIDER_STATUS_UNKNOWN =
+ CREDENTIAL_MANAGER_API_CALLED__CANDIDATE_PROVIDER_STATUS__PROVIDER_UNKNOWN;
+
+
+ /**
+ * This retrieves the uid of any package name, given a context and a component name for the
+ * package. By default, if the desired package uid cannot be found, it will fall back to a
+ * bogus uid.
+ * @return the uid of a given package
+ */
+ protected static int getPackageUid(Context context, ComponentName componentName) {
+ int sessUid = -1;
+ try {
+ // Only for T and above, which is fine for our use case
+ sessUid = context.getPackageManager().getApplicationInfo(
+ componentName.getPackageName(),
+ PackageManager.ApplicationInfoFlags.of(0)).uid;
+ } catch (Throwable t) {
+ Log.i(TAG, "Couldn't find required uid");
+ }
+ return sessUid;
+ }
+
+}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
index b20f0cd0f906..ce9fca753a06 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
@@ -33,7 +33,7 @@ import android.util.Slog;
*
* @hide
*/
-public final class ProviderClearSession extends ProviderSession<ClearCredentialStateRequest,
+public final class ProviderClearSession extends ProviderSession<ClearCredentialStateRequest,
Void>
implements
RemoteCredentialService.ProviderCallbacks<Void> {
@@ -120,6 +120,7 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS
protected void invokeSession() {
if (mRemoteCredentialService != null) {
mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
+ mCandidateProviderMetric.setStartTimeNanoseconds(System.nanoTime());
}
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index b4c4233e888a..3245c914b2b8 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -19,6 +19,7 @@ package com.android.server.credentials;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.credentials.CreateCredentialException;
@@ -56,14 +57,11 @@ public final class ProviderCreateSession extends ProviderSession<
// Key to be used as an entry key for a remote entry
private static final String REMOTE_ENTRY_KEY = "remote_entry_key";
- @NonNull
- private final Map<String, CreateEntry> mUiSaveEntries = new HashMap<>();
- /** The complete request to be used in the second round. */
private final CreateCredentialRequest mCompleteRequest;
private CreateCredentialException mProviderException;
- @Nullable protected Pair<String, CreateEntry> mUiRemoteEntry;
+ private final ProviderResponseDataHandler mProviderResponseDataHandler;
/** Creates a new provider session to be used by the request session. */
@Nullable public static ProviderCreateSession createNewSession(
@@ -88,7 +86,8 @@ public final class ProviderCreateSession extends ProviderSession<
createRequestSession.mClientAppInfo,
createRequestSession
.mClientRequest.alwaysSendAppInfoToProvider()),
- providerCreateRequest
+ providerCreateRequest,
+ createRequestSession.mHybridService
);
}
Log.i(TAG, "Unable to create provider session");
@@ -131,23 +130,20 @@ public final class ProviderCreateSession extends ProviderSession<
@UserIdInt int userId,
@NonNull RemoteCredentialService remoteCredentialService,
@NonNull BeginCreateCredentialRequest beginCreateRequest,
- @NonNull CreateCredentialRequest completeCreateRequest) {
+ @NonNull CreateCredentialRequest completeCreateRequest,
+ String hybridService) {
super(context, info, beginCreateRequest, callbacks, userId,
remoteCredentialService);
mCompleteRequest = completeCreateRequest;
setStatus(Status.PENDING);
- }
-
- /** Returns the save entry maintained in state by this provider session. */
- public CreateEntry getUiSaveEntry(String entryId) {
- return mUiSaveEntries.get(entryId);
+ mProviderResponseDataHandler = new ProviderResponseDataHandler(hybridService);
}
@Override
public void onProviderResponseSuccess(
@Nullable BeginCreateCredentialResponse response) {
Log.i(TAG, "in onProviderResponseSuccess");
- onUpdateResponse(response);
+ onSetInitialRemoteResponse(response);
}
/** Called when the provider response resulted in a failure. */
@@ -171,21 +167,18 @@ public final class ProviderCreateSession extends ProviderSession<
}
}
- private void onUpdateResponse(BeginCreateCredentialResponse response) {
- Log.i(TAG, "updateResponse with save entries");
+ private void onSetInitialRemoteResponse(BeginCreateCredentialResponse response) {
+ Log.i(TAG, "onSetInitialRemoteResponse with save entries");
mProviderResponse = response;
- if (isEmptyResponse(response)) {
+ mProviderResponseDataHandler.addResponseContent(response.getCreateEntries(),
+ response.getRemoteCreateEntry());
+ if (mProviderResponseDataHandler.isEmptyResponse(response)) {
updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE);
} else {
updateStatusAndInvokeCallback(Status.SAVE_ENTRIES_RECEIVED);
}
}
- private boolean isEmptyResponse(BeginCreateCredentialResponse response) {
- return (response.getCreateEntries() == null || response.getCreateEntries().isEmpty())
- && response.getRemoteCreateEntry() == null;
- }
-
@Override
@Nullable protected CreateCredentialProviderData prepareUiData()
throws IllegalArgumentException {
@@ -194,53 +187,37 @@ public final class ProviderCreateSession extends ProviderSession<
Log.i(TAG, "In prepareUiData not in uiInvokingStatus");
return null;
}
- final BeginCreateCredentialResponse response = getProviderResponse();
- if (response == null) {
- Log.i(TAG, "In prepareUiData response null");
- throw new IllegalStateException("Response must be in completion mode");
- }
- if (response.getCreateEntries() != null) {
+
+ if (mProviderResponse != null && !mProviderResponseDataHandler.isEmptyResponse()) {
Log.i(TAG, "In prepareUiData save entries not null");
- return prepareUiProviderData(
- prepareUiSaveEntries(response.getCreateEntries()),
- prepareUiRemoteEntry(response.getRemoteCreateEntry()));
+ return mProviderResponseDataHandler.toCreateCredentialProviderData();
}
return null;
}
- private Entry prepareUiRemoteEntry(CreateEntry remoteCreateEntry) {
- if (remoteCreateEntry == null) {
- return null;
- }
- String entryId = generateUniqueId();
- Entry remoteEntry = new Entry(REMOTE_ENTRY_KEY, entryId, remoteCreateEntry.getSlice(),
- setUpFillInIntent());
- mUiRemoteEntry = new Pair<>(entryId, remoteCreateEntry);
- return remoteEntry;
- }
-
@Override
public void onUiEntrySelected(String entryType, String entryKey,
ProviderPendingIntentResponse providerPendingIntentResponse) {
switch (entryType) {
case SAVE_ENTRY_KEY:
- if (mUiSaveEntries.containsKey(entryKey)) {
- onSaveEntrySelected(providerPendingIntentResponse);
- } else {
+ if (mProviderResponseDataHandler.getCreateEntry(entryKey) == null) {
Log.i(TAG, "Unexpected save entry key");
invokeCallbackOnInternalInvalidState();
+ return;
}
+ onCreateEntrySelected(providerPendingIntentResponse);
break;
case REMOTE_ENTRY_KEY:
- if (mUiRemoteEntry.first.equals(entryKey)) {
- onRemoteEntrySelected(providerPendingIntentResponse);
- } else {
+ if (mProviderResponseDataHandler.getRemoteEntry(entryKey) == null) {
Log.i(TAG, "Unexpected remote entry key");
invokeCallbackOnInternalInvalidState();
+ return;
}
+ onRemoteEntrySelected(providerPendingIntentResponse);
break;
default:
Log.i(TAG, "Unsupported entry type selected");
+ invokeCallbackOnInternalInvalidState();
}
}
@@ -248,24 +225,10 @@ public final class ProviderCreateSession extends ProviderSession<
protected void invokeSession() {
if (mRemoteCredentialService != null) {
mRemoteCredentialService.onCreateCredential(mProviderRequest, this);
+ mCandidateProviderMetric.setStartTimeNanoseconds(System.nanoTime());
}
}
- private List<Entry> prepareUiSaveEntries(@NonNull List<CreateEntry> saveEntries) {
- Log.i(TAG, "in populateUiSaveEntries");
- List<Entry> uiSaveEntries = new ArrayList<>();
-
- // Populate the save entries
- for (CreateEntry createEntry : saveEntries) {
- String entryId = generateUniqueId();
- mUiSaveEntries.put(entryId, createEntry);
- Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
- uiSaveEntries.add(new Entry(SAVE_ENTRY_KEY, entryId, createEntry.getSlice(),
- setUpFillInIntent()));
- }
- return uiSaveEntries;
- }
-
private Intent setUpFillInIntent() {
Intent intent = new Intent();
intent.putExtra(CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST,
@@ -273,16 +236,7 @@ public final class ProviderCreateSession extends ProviderSession<
return intent;
}
- private CreateCredentialProviderData prepareUiProviderData(List<Entry> saveEntries,
- Entry remoteEntry) {
- return new CreateCredentialProviderData.Builder(
- mComponentName.flattenToString())
- .setSaveEntries(saveEntries)
- .setRemoteEntry(remoteEntry)
- .build();
- }
-
- private void onSaveEntrySelected(ProviderPendingIntentResponse pendingIntentResponse) {
+ private void onCreateEntrySelected(ProviderPendingIntentResponse pendingIntentResponse) {
CreateCredentialException exception = maybeGetPendingIntentException(
pendingIntentResponse);
if (exception != null) {
@@ -296,7 +250,6 @@ public final class ProviderCreateSession extends ProviderSession<
pendingIntentResponse.getResultData());
if (credentialResponse != null) {
mCallbacks.onFinalResponseReceived(mComponentName, credentialResponse);
- return;
} else {
Log.i(TAG, "onSaveEntrySelected - no response or error found in pending "
+ "intent response");
@@ -304,6 +257,12 @@ public final class ProviderCreateSession extends ProviderSession<
}
}
+ private void onRemoteEntrySelected(ProviderPendingIntentResponse pendingIntentResponse) {
+ // Response from remote entry should be dealt with similar to a response from a
+ // create entry
+ onCreateEntrySelected(pendingIntentResponse);
+ }
+
@Nullable
private CreateCredentialException maybeGetPendingIntentException(
ProviderPendingIntentResponse pendingIntentResponse) {
@@ -335,4 +294,91 @@ public final class ProviderCreateSession extends ProviderSession<
CreateCredentialException.TYPE_UNKNOWN,
null);
}
+
+ private class ProviderResponseDataHandler {
+ private final ComponentName mExpectedRemoteEntryProviderService;
+
+ @NonNull
+ private final Map<String, Pair<CreateEntry, Entry>> mUiCreateEntries = new HashMap<>();
+
+ @Nullable private Pair<String, Pair<CreateEntry, Entry>> mUiRemoteEntry = null;
+
+ ProviderResponseDataHandler(String hybridService) {
+ mExpectedRemoteEntryProviderService = ComponentName.unflattenFromString(hybridService);
+ }
+
+ public void addResponseContent(List<CreateEntry> createEntries,
+ CreateEntry remoteEntry) {
+ createEntries.forEach(this::addCreateEntry);
+ setRemoteEntry(remoteEntry);
+ }
+ public void addCreateEntry(CreateEntry createEntry) {
+ String id = generateUniqueId();
+ Entry entry = new Entry(SAVE_ENTRY_KEY,
+ id, createEntry.getSlice(), setUpFillInIntent());
+ mUiCreateEntries.put(id, new Pair<>(createEntry, entry));
+ }
+
+ public void setRemoteEntry(@Nullable CreateEntry remoteEntry) {
+ if (remoteEntry == null) {
+ mUiRemoteEntry = null;
+ return;
+ }
+ if (!mComponentName.equals(mExpectedRemoteEntryProviderService)) {
+ Log.i(TAG, "Remote entry being dropped as it is not from the service "
+ + "configured by the OEM.");
+ return;
+ }
+ String id = generateUniqueId();
+ Entry entry = new Entry(REMOTE_ENTRY_KEY,
+ id, remoteEntry.getSlice(), setUpFillInIntent());
+ mUiRemoteEntry = new Pair<>(id, new Pair<>(remoteEntry, entry));
+ }
+
+ public CreateCredentialProviderData toCreateCredentialProviderData() {
+ return new CreateCredentialProviderData.Builder(
+ mComponentName.flattenToString())
+ .setSaveEntries(prepareUiCreateEntries())
+ .setRemoteEntry(prepareRemoteEntry())
+ .build();
+ }
+
+ private List<Entry> prepareUiCreateEntries() {
+ List<Entry> createEntries = new ArrayList<>();
+ for (String key : mUiCreateEntries.keySet()) {
+ createEntries.add(mUiCreateEntries.get(key).second);
+ }
+ return createEntries;
+ }
+
+ private Entry prepareRemoteEntry() {
+ if (mUiRemoteEntry == null || mUiRemoteEntry.first == null
+ || mUiRemoteEntry.second == null) {
+ return null;
+ }
+ return mUiRemoteEntry.second.second;
+ }
+
+ private boolean isEmptyResponse() {
+ return mUiCreateEntries.isEmpty() && mUiRemoteEntry == null;
+ }
+ @Nullable
+ public CreateEntry getRemoteEntry(String entryKey) {
+ return mUiRemoteEntry == null || mUiRemoteEntry
+ .first == null || !mUiRemoteEntry.first.equals(entryKey)
+ || mUiRemoteEntry.second == null
+ ? null : mUiRemoteEntry.second.first;
+ }
+
+ @Nullable
+ public CreateEntry getCreateEntry(String entryKey) {
+ return mUiCreateEntries.get(entryKey) == null
+ ? null : mUiCreateEntries.get(entryKey).first;
+ }
+
+ public boolean isEmptyResponse(BeginCreateCredentialResponse response) {
+ return (response.getCreateEntries() == null || response.getCreateEntries().isEmpty())
+ && response.getRemoteCreateEntry() == null;
+ }
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index c2a57a8d298b..12074c7494bf 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -19,6 +19,7 @@ package com.android.server.credentials;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.credentials.CredentialOption;
@@ -45,7 +46,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
+import java.util.Optional;
/**
* Central provider session that listens for provider callbacks, and maintains provider state.
@@ -69,14 +70,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
@NonNull
private final Map<String, CredentialOption> mBeginGetOptionToCredentialOptionMap;
- @NonNull
- private final Map<String, CredentialEntry> mUiCredentialEntries = new HashMap<>();
- @NonNull
- private final Map<String, Action> mUiActionsEntries = new HashMap<>();
- @Nullable
- private final Map<String, Action> mUiAuthenticationEntries = new HashMap<>();
- @Nullable protected Pair<String, CredentialEntry> mUiRemoteEntry;
/** The complete request to be used in the second round. */
private final android.credentials.GetCredentialRequest mCompleteRequest;
@@ -84,6 +78,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
private GetCredentialException mProviderException;
+ private final ProviderResponseDataHandler mProviderResponseDataHandler;
+
/** Creates a new provider session to be used by the request session. */
@Nullable public static ProviderGetSession createNewSession(
Context context,
@@ -109,7 +105,8 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
beginGetOptionToCredentialOptionMap),
filteredRequest,
getRequestSession.mClientAppInfo,
- beginGetOptionToCredentialOptionMap
+ beginGetOptionToCredentialOptionMap,
+ getRequestSession.mHybridService
);
}
Log.i(TAG, "Unable to create provider session");
@@ -137,7 +134,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
}
@Nullable
- protected static android.credentials.GetCredentialRequest filterOptions(
+ private static android.credentials.GetCredentialRequest filterOptions(
List<String> providerCapabilities,
android.credentials.GetCredentialRequest clientRequest
) {
@@ -169,19 +166,22 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
BeginGetCredentialRequest beginGetRequest,
android.credentials.GetCredentialRequest completeGetRequest,
CallingAppInfo callingAppInfo,
- Map<String, CredentialOption> beginGetOptionToCredentialOptionMap) {
+ Map<String, CredentialOption> beginGetOptionToCredentialOptionMap,
+ String hybridService) {
super(context, info, beginGetRequest, callbacks, userId, remoteCredentialService);
mCompleteRequest = completeGetRequest;
mCallingAppInfo = callingAppInfo;
setStatus(Status.PENDING);
mBeginGetOptionToCredentialOptionMap = new HashMap<>(beginGetOptionToCredentialOptionMap);
+ mProviderResponseDataHandler = new ProviderResponseDataHandler(
+ ComponentName.unflattenFromString(hybridService));
}
/** Called when the provider response has been updated by an external source. */
@Override // Callback from the remote provider
public void onProviderResponseSuccess(@Nullable BeginGetCredentialResponse response) {
Log.i(TAG, "in onProviderResponseSuccess");
- onUpdateResponse(response);
+ onSetInitialRemoteResponse(response);
}
/** Called when the provider response resulted in a failure. */
@@ -207,18 +207,20 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
@Override // Selection call from the request provider
protected void onUiEntrySelected(String entryType, String entryKey,
ProviderPendingIntentResponse providerPendingIntentResponse) {
+ Log.i(TAG, "onUiEntrySelected with entryKey: " + entryKey);
switch (entryType) {
case CREDENTIAL_ENTRY_KEY:
- CredentialEntry credentialEntry = mUiCredentialEntries.get(entryKey);
+ CredentialEntry credentialEntry = mProviderResponseDataHandler
+ .getCredentialEntry(entryKey);
if (credentialEntry == null) {
Log.i(TAG, "Unexpected credential entry key");
invokeCallbackOnInternalInvalidState();
return;
}
- onCredentialEntrySelected(credentialEntry, providerPendingIntentResponse);
+ onCredentialEntrySelected(providerPendingIntentResponse);
break;
case ACTION_ENTRY_KEY:
- Action actionEntry = mUiActionsEntries.get(entryKey);
+ Action actionEntry = mProviderResponseDataHandler.getActionEntry(entryKey);
if (actionEntry == null) {
Log.i(TAG, "Unexpected action entry key");
invokeCallbackOnInternalInvalidState();
@@ -227,16 +229,29 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
onActionEntrySelected(providerPendingIntentResponse);
break;
case AUTHENTICATION_ACTION_ENTRY_KEY:
- Action authenticationEntry = mUiAuthenticationEntries.get(entryKey);
+ Action authenticationEntry = mProviderResponseDataHandler
+ .getAuthenticationAction(entryKey);
if (authenticationEntry == null) {
Log.i(TAG, "Unexpected authenticationEntry key");
invokeCallbackOnInternalInvalidState();
return;
}
- onAuthenticationEntrySelected(providerPendingIntentResponse);
+ boolean additionalContentReceived =
+ onAuthenticationEntrySelected(providerPendingIntentResponse);
+ if (additionalContentReceived) {
+ Log.i(TAG, "Additional content received - removing authentication entry");
+ mProviderResponseDataHandler.removeAuthenticationAction(entryKey);
+ } else {
+ Log.i(TAG, "Additional content not received");
+ mProviderResponseDataHandler
+ .updateAuthEntryWithNoCredentialsReceived(entryKey);
+ }
+ if (!mProviderResponseDataHandler.isEmptyResponse()) {
+ updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED);
+ }
break;
case REMOTE_ENTRY_KEY:
- if (mUiRemoteEntry.first.equals(entryKey)) {
+ if (mProviderResponseDataHandler.getRemoteEntry(entryKey) != null) {
onRemoteEntrySelected(providerPendingIntentResponse);
} else {
Log.i(TAG, "Unexpected remote entry key");
@@ -245,6 +260,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
break;
default:
Log.i(TAG, "Unsupported entry type selected");
+ invokeCallbackOnInternalInvalidState();
}
}
@@ -252,6 +268,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
protected void invokeSession() {
if (mRemoteCredentialService != null) {
mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
+ mCandidateProviderMetric.setStartTimeNanoseconds(System.nanoTime());
}
}
@@ -263,61 +280,11 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
+ mComponentName.flattenToString());
return null;
}
- if (mProviderResponse == null) {
- Log.i(TAG, "In prepareUiData response null");
- throw new IllegalStateException("Response must be in completion mode");
- }
- return prepareUiProviderData(prepareUiActionEntries(
- mProviderResponse.getActions()),
- prepareUiCredentialEntries(mProviderResponse.getCredentialEntries()),
- prepareUiAuthenticationEntries(mProviderResponse.getAuthenticationActions()),
- prepareUiRemoteEntry(mProviderResponse.getRemoteCredentialEntry()));
- }
-
- private Entry prepareUiRemoteEntry(CredentialEntry remoteCredentialEntry) {
- if (remoteCredentialEntry == null) {
- return null;
+ if (mProviderResponse != null && !mProviderResponseDataHandler.isEmptyResponse()) {
+ return mProviderResponseDataHandler.toGetCredentialProviderData();
}
- String entryId = generateUniqueId();
- Entry remoteEntry = new Entry(REMOTE_ENTRY_KEY, entryId, remoteCredentialEntry.getSlice(),
- setUpFillInIntent(remoteCredentialEntry.getType()));
- mUiRemoteEntry = new Pair<>(entryId, remoteCredentialEntry);
- return remoteEntry;
- }
-
- private List<AuthenticationEntry> prepareUiAuthenticationEntries(
- @NonNull List<Action> authenticationEntries) {
- List<AuthenticationEntry> authenticationUiEntries = new ArrayList<>();
-
- // TODO: properly construct entries when they should have the unlocked status.
- for (Action authenticationAction : authenticationEntries) {
- String entryId = generateUniqueId();
- mUiAuthenticationEntries.put(entryId, authenticationAction);
- authenticationUiEntries.add(new AuthenticationEntry(
- AUTHENTICATION_ACTION_ENTRY_KEY, entryId,
- authenticationAction.getSlice(),
- AuthenticationEntry.STATUS_LOCKED,
- setUpFillInIntentForAuthentication()));
- }
- return authenticationUiEntries;
- }
-
- private List<Entry> prepareUiCredentialEntries(@NonNull
- List<CredentialEntry> credentialEntries) {
- Log.i(TAG, "in prepareUiProviderDataWithCredentials");
- List<Entry> credentialUiEntries = new ArrayList<>();
-
- // Populate the credential entries
- for (CredentialEntry credentialEntry : credentialEntries) {
- String entryId = generateUniqueId();
- mUiCredentialEntries.put(entryId, credentialEntry);
- Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
- credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId,
- credentialEntry.getSlice(),
- /*fillInIntent=*/setUpFillInIntent(credentialEntry
- .getBeginGetCredentialOption().getId())));
- }
- return credentialUiEntries;
+ Log.i(TAG, "In prepareUiData response null");
+ return null;
}
private Intent setUpFillInIntent(@NonNull String id) {
@@ -334,68 +301,47 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
mCallingAppInfo, mBeginGetOptionToCredentialOptionMap.get(id)));
}
- private Intent setUpFillInIntentForAuthentication() {
+ private Intent setUpFillInIntentWithQueryRequest() {
Intent intent = new Intent();
- intent.putExtra(
- CredentialProviderService
- .EXTRA_BEGIN_GET_CREDENTIAL_REQUEST,
+ intent.putExtra(CredentialProviderService.EXTRA_BEGIN_GET_CREDENTIAL_REQUEST,
mProviderRequest);
return intent;
}
- private List<Entry> prepareUiActionEntries(@Nullable List<Action> actions) {
- List<Entry> actionEntries = new ArrayList<>();
- for (Action action : actions) {
- String entryId = UUID.randomUUID().toString();
- mUiActionsEntries.put(entryId, action);
- // TODO : Remove conversion of string to int after change in Entry class
- actionEntries.add(new Entry(ACTION_ENTRY_KEY, entryId, action.getSlice()));
- }
- return actionEntries;
- }
-
- private GetCredentialProviderData prepareUiProviderData(List<Entry> actionEntries,
- List<Entry> credentialEntries, List<AuthenticationEntry> authenticationActionEntries,
- Entry remoteEntry) {
- return new GetCredentialProviderData.Builder(
- mComponentName.flattenToString()).setActionChips(actionEntries)
- .setCredentialEntries(credentialEntries)
- .setAuthenticationEntries(authenticationActionEntries)
- .setRemoteEntry(remoteEntry)
- .build();
+ private void onRemoteEntrySelected(
+ ProviderPendingIntentResponse providerPendingIntentResponse) {
+ onCredentialEntrySelected(providerPendingIntentResponse);
}
- private void onCredentialEntrySelected(CredentialEntry credentialEntry,
+ private void onCredentialEntrySelected(
ProviderPendingIntentResponse providerPendingIntentResponse) {
- if (providerPendingIntentResponse != null) {
- // Check if pending intent has an error
- GetCredentialException exception = maybeGetPendingIntentException(
- providerPendingIntentResponse);
- if (exception != null) {
- invokeCallbackWithError(exception.getType(),
- exception.getMessage());
- return;
- }
-
- // Check if pending intent has a credential
- GetCredentialResponse getCredentialResponse = PendingIntentResultHandler
- .extractGetCredentialResponse(
- providerPendingIntentResponse.getResultData());
- if (getCredentialResponse != null) {
- mCallbacks.onFinalResponseReceived(mComponentName,
- getCredentialResponse);
- return;
- }
-
- Log.i(TAG, "Pending intent response contains no credential, or error");
+ if (providerPendingIntentResponse == null) {
invokeCallbackOnInternalInvalidState();
+ return;
+ }
+ // Check if pending intent has an error
+ GetCredentialException exception = maybeGetPendingIntentException(
+ providerPendingIntentResponse);
+ if (exception != null) {
+ invokeCallbackWithError(exception.getType(), exception.getMessage());
+ return;
+ }
+
+ // Check if pending intent has a credential response
+ GetCredentialResponse getCredentialResponse = PendingIntentResultHandler
+ .extractGetCredentialResponse(
+ providerPendingIntentResponse.getResultData());
+ if (getCredentialResponse != null) {
+ mCallbacks.onFinalResponseReceived(mComponentName,
+ getCredentialResponse);
+ return;
}
- Log.i(TAG, "CredentialEntry does not have a credential or a pending intent result");
+ Log.i(TAG, "Pending intent response contains no credential, or error");
invokeCallbackOnInternalInvalidState();
}
@Nullable
- protected GetCredentialException maybeGetPendingIntentException(
+ private GetCredentialException maybeGetPendingIntentException(
ProviderPendingIntentResponse pendingIntentResponse) {
if (pendingIntentResponse == null) {
Log.i(TAG, "pendingIntentResponse is null");
@@ -416,13 +362,19 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
return null;
}
- private void onAuthenticationEntrySelected(
+ /**
+ * Returns true if either an exception or a response is retrieved from the result.
+ * Returns false if the response is not set at all, or set to null, or empty.
+ */
+ private boolean onAuthenticationEntrySelected(
@Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
- //TODO: Other provider intent statuses
+ Log.i(TAG, "onAuthenticationEntrySelected");
+ // Authentication entry is expected to have a BeginGetCredentialResponse instance. If it
+ // does not have it, we remove the authentication entry and do not add any more content.
if (providerPendingIntentResponse == null) {
Log.i(TAG, "providerPendingIntentResponse is null");
- onUpdateEmptyResponse();
- return;
+ // Nothing received. This is equivalent to no content received.
+ return false;
}
GetCredentialException exception = maybeGetPendingIntentException(
@@ -430,51 +382,69 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
if (exception != null) {
invokeCallbackWithError(exception.getType(),
exception.getMessage());
- return;
+ // Additional content received is in the form of an exception which ends the flow.
+ return true;
}
-
- // Check if pending intent has the content
- BeginGetCredentialResponse content = PendingIntentResultHandler
+ // Check if pending intent has the response. If yes, remove this auth entry and
+ // replace it with the response content received.
+ BeginGetCredentialResponse response = PendingIntentResultHandler
.extractResponseContent(providerPendingIntentResponse
.getResultData());
- if (content != null) {
- onUpdateResponse(content);
- return;
+ if (response != null && !mProviderResponseDataHandler.isEmptyResponse(response)) {
+ addToInitialRemoteResponse(response);
+ // Additional content received is in the form of new response content.
+ return true;
}
+ // No response or exception found.
+ return false;
+ }
- Log.i(TAG, "No error or respond found in pending intent response");
- onUpdateEmptyResponse();
+ private void addToInitialRemoteResponse(BeginGetCredentialResponse content) {
+ if (content == null) {
+ return;
+ }
+ mProviderResponseDataHandler.addResponseContent(
+ content.getCredentialEntries(),
+ content.getActions(),
+ content.getAuthenticationActions(),
+ content.getRemoteCredentialEntry()
+ );
}
+ /** Returns true if either an exception or a response is found. */
private void onActionEntrySelected(ProviderPendingIntentResponse
providerPendingIntentResponse) {
- //TODO: Implement if any result expected after an action
+ // Action entry is expected to either contain the final GetCredentialResponse, or it is
+ // also acceptable if it does not contain anything. In the second case, we re-show this
+ // action on the UI.
+ if (providerPendingIntentResponse == null) {
+ Log.i(TAG, "providerPendingIntentResponse is null");
+ return;
+ }
+
+ GetCredentialException exception = maybeGetPendingIntentException(
+ providerPendingIntentResponse);
+ if (exception != null) {
+ invokeCallbackWithError(exception.getType(), exception.getMessage());
+ }
+ GetCredentialResponse response = PendingIntentResultHandler
+ .extractGetCredentialResponse(
+ providerPendingIntentResponse.getResultData());
+ if (response != null) {
+ mCallbacks.onFinalResponseReceived(mComponentName, response);
+ }
}
/** Updates the response being maintained in state by this provider session. */
- private void onUpdateResponse(BeginGetCredentialResponse response) {
+ private void onSetInitialRemoteResponse(BeginGetCredentialResponse response) {
mProviderResponse = response;
- if (isEmptyResponse(response)) {
+ addToInitialRemoteResponse(response);
+ if (mProviderResponseDataHandler.isEmptyResponse(response)) {
updateStatusAndInvokeCallback(Status.EMPTY_RESPONSE);
- } else {
- updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED);
- }
- }
-
- private boolean isEmptyResponse(BeginGetCredentialResponse response) {
- if ((response.getCredentialEntries() == null || response.getCredentialEntries().isEmpty())
- && (response.getAuthenticationActions() == null || response
- .getAuthenticationActions().isEmpty())
- && (response.getActions() == null || response.getActions().isEmpty())
- && response.getRemoteCredentialEntry() == null) {
- return true;
+ return;
}
- return false;
- }
-
- private void onUpdateEmptyResponse() {
- updateStatusAndInvokeCallback(Status.NO_CREDENTIALS);
+ updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED);
}
/**
@@ -485,4 +455,201 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential
mCallbacks.onFinalErrorReceived(mComponentName,
GetCredentialException.TYPE_UNKNOWN, null);
}
+
+ private class ProviderResponseDataHandler {
+ private final ComponentName mExpectedRemoteEntryProviderService;
+ @NonNull
+ private final Map<String, Pair<CredentialEntry, Entry>> mUiCredentialEntries =
+ new HashMap<>();
+ @NonNull
+ private final Map<String, Pair<Action, Entry>> mUiActionsEntries = new HashMap<>();
+ @Nullable
+ private final Map<String, Pair<Action, AuthenticationEntry>> mUiAuthenticationEntries =
+ new HashMap<>();
+
+ @Nullable private Pair<String, Pair<CredentialEntry, Entry>> mUiRemoteEntry = null;
+
+ ProviderResponseDataHandler(ComponentName expectedRemoteEntryProviderService) {
+ mExpectedRemoteEntryProviderService = expectedRemoteEntryProviderService;
+ }
+
+ public void addResponseContent(List<CredentialEntry> credentialEntries,
+ List<Action> actions, List<Action> authenticationActions,
+ CredentialEntry remoteEntry) {
+ credentialEntries.forEach(this::addCredentialEntry);
+ actions.forEach(this::addAction);
+ authenticationActions.forEach(
+ authenticationAction -> addAuthenticationAction(authenticationAction,
+ AuthenticationEntry.STATUS_LOCKED));
+ setRemoteEntry(remoteEntry);
+ }
+ public void addCredentialEntry(CredentialEntry credentialEntry) {
+ String id = generateUniqueId();
+ Entry entry = new Entry(CREDENTIAL_ENTRY_KEY,
+ id, credentialEntry.getSlice(),
+ setUpFillInIntent(credentialEntry
+ .getBeginGetCredentialOption().getId()));
+ mUiCredentialEntries.put(id, new Pair<>(credentialEntry, entry));
+ }
+
+ public void addAction(Action action) {
+ String id = generateUniqueId();
+ Entry entry = new Entry(ACTION_ENTRY_KEY,
+ id, action.getSlice(),
+ setUpFillInIntentWithQueryRequest());
+ mUiActionsEntries.put(id, new Pair<>(action, entry));
+ }
+
+ public void addAuthenticationAction(Action authenticationAction,
+ @AuthenticationEntry.Status int status) {
+ Log.i(TAG, "In addAuthenticationAction");
+ String id = generateUniqueId();
+ Log.i(TAG, "In addAuthenticationAction, id : " + id);
+ AuthenticationEntry entry = new AuthenticationEntry(
+ AUTHENTICATION_ACTION_ENTRY_KEY,
+ id, authenticationAction.getSlice(),
+ status,
+ setUpFillInIntentWithQueryRequest());
+ mUiAuthenticationEntries.put(id, new Pair<>(authenticationAction, entry));
+ }
+
+ public void removeAuthenticationAction(String id) {
+ mUiAuthenticationEntries.remove(id);
+ }
+
+ public void setRemoteEntry(@Nullable CredentialEntry remoteEntry) {
+ if (remoteEntry == null) {
+ return;
+ }
+ if (!mComponentName.equals(mExpectedRemoteEntryProviderService)) {
+ Log.i(TAG, "Remote entry being dropped as it is not from the service "
+ + "configured by the OEM.");
+ return;
+ }
+ String id = generateUniqueId();
+ Entry entry = new Entry(REMOTE_ENTRY_KEY,
+ id, remoteEntry.getSlice(), setUpFillInIntent(
+ remoteEntry.getBeginGetCredentialOption().getId()));
+ mUiRemoteEntry = new Pair<>(generateUniqueId(), new Pair<>(remoteEntry, entry));
+ }
+
+ public GetCredentialProviderData toGetCredentialProviderData() {
+ return new GetCredentialProviderData.Builder(
+ mComponentName.flattenToString()).setActionChips(prepareActionEntries())
+ .setCredentialEntries(prepareCredentialEntries())
+ .setAuthenticationEntries(prepareAuthenticationEntries())
+ .setRemoteEntry(prepareRemoteEntry())
+ .build();
+ }
+
+ private List<Entry> prepareActionEntries() {
+ List<Entry> actionEntries = new ArrayList<>();
+ for (String key : mUiActionsEntries.keySet()) {
+ actionEntries.add(mUiActionsEntries.get(key).second);
+ }
+ return actionEntries;
+ }
+
+ private List<AuthenticationEntry> prepareAuthenticationEntries() {
+ List<AuthenticationEntry> authEntries = new ArrayList<>();
+ for (String key : mUiAuthenticationEntries.keySet()) {
+ authEntries.add(mUiAuthenticationEntries.get(key).second);
+ }
+ return authEntries;
+ }
+
+ private List<Entry> prepareCredentialEntries() {
+ List<Entry> credEntries = new ArrayList<>();
+ for (String key : mUiCredentialEntries.keySet()) {
+ credEntries.add(mUiCredentialEntries.get(key).second);
+ }
+ return credEntries;
+ }
+
+
+ private Entry prepareRemoteEntry() {
+ if (mUiRemoteEntry == null || mUiRemoteEntry.first == null
+ || mUiRemoteEntry.second == null) {
+ return null;
+ }
+ return mUiRemoteEntry.second.second;
+ }
+
+ private boolean isEmptyResponse() {
+ return mUiCredentialEntries.isEmpty() && mUiActionsEntries.isEmpty()
+ && mUiAuthenticationEntries.isEmpty() && mUiRemoteEntry == null;
+ }
+
+ private boolean isEmptyResponse(BeginGetCredentialResponse response) {
+ return response.getCredentialEntries().isEmpty() && response.getActions().isEmpty()
+ && response.getAuthenticationActions().isEmpty()
+ && response.getRemoteCredentialEntry() == null;
+ }
+
+ @Nullable
+ public Action getAuthenticationAction(String entryKey) {
+ return mUiAuthenticationEntries.get(entryKey) == null ? null :
+ mUiAuthenticationEntries.get(entryKey).first;
+ }
+
+ @Nullable
+ public Action getActionEntry(String entryKey) {
+ return mUiActionsEntries.get(entryKey) == null
+ ? null : mUiActionsEntries.get(entryKey).first;
+ }
+
+ @Nullable
+ public CredentialEntry getRemoteEntry(String entryKey) {
+ return mUiRemoteEntry.first.equals(entryKey) && mUiRemoteEntry.second != null
+ ? mUiRemoteEntry.second.first : null;
+ }
+
+ @Nullable
+ public CredentialEntry getCredentialEntry(String entryKey) {
+ return mUiCredentialEntries.get(entryKey) == null
+ ? null : mUiCredentialEntries.get(entryKey).first;
+ }
+
+ public void updateAuthEntryWithNoCredentialsReceived(String entryKey) {
+ updatePreviousMostRecentAuthEntry();
+ updateMostRecentAuthEntry(entryKey);
+ }
+
+ private void updateMostRecentAuthEntry(String entryKey) {
+ AuthenticationEntry previousAuthenticationEntry =
+ mUiAuthenticationEntries.get(entryKey).second;
+ Action previousAuthenticationAction = mUiAuthenticationEntries.get(entryKey).first;
+ mUiAuthenticationEntries.put(entryKey, new Pair<>(
+ previousAuthenticationAction,
+ copyAuthEntryAndChangeStatus(
+ previousAuthenticationEntry,
+ AuthenticationEntry.STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT)));
+ }
+
+ private void updatePreviousMostRecentAuthEntry() {
+ Optional<Map.Entry<String, Pair<Action, AuthenticationEntry>>>
+ previousMostRecentAuthEntry = mUiAuthenticationEntries
+ .entrySet().stream().filter(e -> e.getValue().second.getStatus()
+ == AuthenticationEntry.STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT)
+ .findFirst();
+ if (previousMostRecentAuthEntry.isEmpty()) {
+ Log.i(TAG, "In updatePreviousMostRecentAuthEntry - previous entry not found");
+ return;
+ }
+ String id = previousMostRecentAuthEntry.get().getKey();
+ mUiAuthenticationEntries.remove(id);
+ mUiAuthenticationEntries.put(id, new Pair<>(
+ previousMostRecentAuthEntry.get().getValue().first,
+ copyAuthEntryAndChangeStatus(
+ previousMostRecentAuthEntry.get().getValue().second,
+ AuthenticationEntry.STATUS_UNLOCKED_BUT_EMPTY_LESS_RECENT)));
+ }
+
+ private AuthenticationEntry copyAuthEntryAndChangeStatus(
+ AuthenticationEntry from, Integer toStatus) {
+ return new AuthenticationEntry(AUTHENTICATION_ACTION_ENTRY_KEY, from.getSubkey(),
+ from.getSlice(), toStatus,
+ from.getFrameworkExtrasIntent());
+ }
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
index dd9fcb62a8e3..5af8080df5c1 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
@@ -235,6 +235,7 @@ public class ProviderRegistryGetSession extends ProviderSession<GetCredentialReq
-> filterResult.mCredentialEntries.stream())
.collect(Collectors.toList());
setStatus(Status.CREDENTIALS_RECEIVED);
+ // TODO(use metric later)
}
@Nullable
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index 1aec9340e332..2f9d57872c3c 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -16,6 +16,9 @@
package com.android.server.credentials;
+import static com.android.server.credentials.MetricUtilities.METRICS_PROVIDER_STATUS_QUERY_FAILURE;
+import static com.android.server.credentials.MetricUtilities.METRICS_PROVIDER_STATUS_QUERY_SUCCESS;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
@@ -28,6 +31,8 @@ import android.os.RemoteException;
import android.service.credentials.CredentialProviderInfo;
import android.util.Log;
+import com.android.server.credentials.metrics.CandidateProviderMetric;
+
import java.util.UUID;
/**
@@ -52,16 +57,16 @@ public abstract class ProviderSession<T, R>
@NonNull protected final T mProviderRequest;
@Nullable protected R mProviderResponse;
@NonNull protected Boolean mProviderResponseSet = false;
-
-
+ // Specific candidate provider metric for the provider this session handles
+ @Nullable protected CandidateProviderMetric mCandidateProviderMetric;
+ @NonNull private int mProviderSessionUid;
/**
* Returns true if the given status reflects that the provider state is ready to be shown
* on the credMan UI.
*/
public static boolean isUiInvokingStatus(Status status) {
- return status == Status.CREDENTIALS_RECEIVED || status == Status.SAVE_ENTRIES_RECEIVED
- || status == Status.REQUIRES_AUTHENTICATION;
+ return status == Status.CREDENTIALS_RECEIVED || status == Status.SAVE_ENTRIES_RECEIVED;
}
/**
@@ -119,6 +124,8 @@ public abstract class ProviderSession<T, R>
mUserId = userId;
mComponentName = info.getServiceInfo().getComponentName();
mRemoteCredentialService = remoteCredentialService;
+ mCandidateProviderMetric = new CandidateProviderMetric();
+ mProviderSessionUid = MetricUtilities.getPackageUid(mContext, mComponentName);
}
/** Provider status at various states of the request session. */
@@ -185,12 +192,19 @@ public abstract class ProviderSession<T, R>
/** Updates the status .*/
protected void updateStatusAndInvokeCallback(@NonNull Status status) {
setStatus(status);
+ updateCandidateMetric(status);
mCallbacks.onProviderStatusChanged(status, mComponentName);
}
- protected void onRemoteEntrySelected(
- ProviderPendingIntentResponse providerPendingIntentResponse) {
- //TODO: Implement
+ private void updateCandidateMetric(Status status) {
+ mCandidateProviderMetric.setCandidateUid(mProviderSessionUid);
+ mCandidateProviderMetric
+ .setQueryFinishTimeNanoseconds(System.nanoTime());
+ if (isTerminatingStatus(status)) {
+ mCandidateProviderMetric.setProviderQueryStatus(METRICS_PROVIDER_STATUS_QUERY_FAILURE);
+ } else if (isCompletionStatus(status)) {
+ mCandidateProviderMetric.setProviderQueryStatus(METRICS_PROVIDER_STATUS_QUERY_SUCCESS);
+ }
}
/** Get the request to be sent to the provider. */
diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
index 2dea8bda78d5..702261ea43f5 100644
--- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
+++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.credentials.ClearCredentialStateException;
import android.credentials.CreateCredentialException;
import android.credentials.GetCredentialException;
+import android.os.Binder;
import android.os.Handler;
import android.os.ICancellationSignal;
import android.os.RemoteException;
@@ -55,7 +56,7 @@ import java.util.concurrent.atomic.AtomicReference;
*
* @hide
*/
-public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialProviderService>{
+public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialProviderService> {
private static final String TAG = "RemoteCredentialService";
/** Timeout for a single request. */
@@ -69,13 +70,16 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
/**
* Callbacks to be invoked when the provider remote service responds with a
* success or failure.
+ *
* @param <T> the type of response expected from the provider
*/
public interface ProviderCallbacks<T> {
/** Called when a successful response is received from the remote provider. */
void onProviderResponseSuccess(@Nullable T response);
+
/** Called when a failure response is received from the remote provider. */
void onProviderResponseFailure(int internalErrorCode, @Nullable Exception e);
+
/** Called when the remote provider service dies. */
void onProviderServiceDied(RemoteCredentialService service);
}
@@ -95,7 +99,8 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
}
/** Return the componentName of the service to be connected. */
- @NonNull public ComponentName getComponentName() {
+ @NonNull
+ public ComponentName getComponentName() {
return mComponentName;
}
@@ -104,9 +109,11 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
unbind();
}
- /** Main entry point to be called for executing a getCredential call on the remote
+ /**
+ * Main entry point to be called for executing a getCredential call on the remote
* provider service.
- * @param request the request to be sent to the provider
+ *
+ * @param request the request to be sent to the provider
* @param callback the callback to be used to send back the provider response to the
* {@link ProviderGetSession} class that maintains provider state
*/
@@ -120,30 +127,36 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
CompletableFuture<BeginGetCredentialResponse> connectThenExecute = postAsync(service -> {
CompletableFuture<BeginGetCredentialResponse> getCredentials =
new CompletableFuture<>();
- ICancellationSignal cancellationSignal =
- service.onBeginGetCredential(request,
- new IBeginGetCredentialCallback.Stub() {
- @Override
- public void onSuccess(BeginGetCredentialResponse response) {
- Log.i(TAG, "In onSuccess in RemoteCredentialService");
- getCredentials.complete(response);
- }
+ final long originalCallingUidToken = Binder.clearCallingIdentity();
+ try {
+ ICancellationSignal cancellationSignal =
+ service.onBeginGetCredential(request,
+ new IBeginGetCredentialCallback.Stub() {
+ @Override
+ public void onSuccess(BeginGetCredentialResponse response) {
+ Log.i(TAG, "In onSuccess in RemoteCredentialService");
+ getCredentials.complete(response);
+ }
- @Override
- public void onFailure(String errorType, CharSequence message) {
- Log.i(TAG, "In onFailure in RemoteCredentialService");
- String errorMsg = message == null ? "" : String.valueOf(message);
- getCredentials.completeExceptionally(
- new GetCredentialException(errorType, errorMsg));
- }
- });
- CompletableFuture<BeginGetCredentialResponse> future = futureRef.get();
- if (future != null && future.isCancelled()) {
- dispatchCancellationSignal(cancellationSignal);
- } else {
- cancellationSink.set(cancellationSignal);
+ @Override
+ public void onFailure(String errorType, CharSequence message) {
+ Log.i(TAG, "In onFailure in RemoteCredentialService");
+ String errorMsg = message == null ? "" : String.valueOf(
+ message);
+ getCredentials.completeExceptionally(
+ new GetCredentialException(errorType, errorMsg));
+ }
+ });
+ CompletableFuture<BeginGetCredentialResponse> future = futureRef.get();
+ if (future != null && future.isCancelled()) {
+ dispatchCancellationSignal(cancellationSignal);
+ } else {
+ cancellationSink.set(cancellationSignal);
+ }
+ return getCredentials;
+ } finally {
+ Binder.restoreCallingIdentity(originalCallingUidToken);
}
- return getCredentials;
}).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
futureRef.set(connectThenExecute);
@@ -153,9 +166,11 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
return cancellationSink.get();
}
- /** Main entry point to be called for executing a beginCreateCredential call on the remote
+ /**
+ * Main entry point to be called for executing a beginCreateCredential call on the remote
* provider service.
- * @param request the request to be sent to the provider
+ *
+ * @param request the request to be sent to the provider
* @param callback the callback to be used to send back the provider response to the
* {@link ProviderCreateSession} class that maintains provider state
*/
@@ -168,32 +183,39 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
CompletableFuture<BeginCreateCredentialResponse> connectThenExecute =
postAsync(service -> {
- CompletableFuture<BeginCreateCredentialResponse> createCredentialFuture =
- new CompletableFuture<>();
- ICancellationSignal cancellationSignal = service.onBeginCreateCredential(
- request, new IBeginCreateCredentialCallback.Stub() {
- @Override
- public void onSuccess(BeginCreateCredentialResponse response) {
- Log.i(TAG, "In onSuccess onBeginCreateCredential "
- + "in RemoteCredentialService");
- createCredentialFuture.complete(response);
- }
+ CompletableFuture<BeginCreateCredentialResponse> createCredentialFuture =
+ new CompletableFuture<>();
+ final long originalCallingUidToken = Binder.clearCallingIdentity();
+ try {
+ ICancellationSignal cancellationSignal = service.onBeginCreateCredential(
+ request, new IBeginCreateCredentialCallback.Stub() {
+ @Override
+ public void onSuccess(BeginCreateCredentialResponse response) {
+ Log.i(TAG, "In onSuccess onBeginCreateCredential "
+ + "in RemoteCredentialService");
+ createCredentialFuture.complete(response);
+ }
- @Override
- public void onFailure(String errorType, CharSequence message) {
- Log.i(TAG, "In onFailure in RemoteCredentialService");
- String errorMsg = message == null ? "" : String.valueOf(message);
- createCredentialFuture.completeExceptionally(
- new CreateCredentialException(errorType, errorMsg));
- }});
- CompletableFuture<BeginCreateCredentialResponse> future = futureRef.get();
- if (future != null && future.isCancelled()) {
- dispatchCancellationSignal(cancellationSignal);
- } else {
- cancellationSink.set(cancellationSignal);
- }
- return createCredentialFuture;
- }).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
+ @Override
+ public void onFailure(String errorType, CharSequence message) {
+ Log.i(TAG, "In onFailure in RemoteCredentialService");
+ String errorMsg = message == null ? "" : String.valueOf(
+ message);
+ createCredentialFuture.completeExceptionally(
+ new CreateCredentialException(errorType, errorMsg));
+ }
+ });
+ CompletableFuture<BeginCreateCredentialResponse> future = futureRef.get();
+ if (future != null && future.isCancelled()) {
+ dispatchCancellationSignal(cancellationSignal);
+ } else {
+ cancellationSink.set(cancellationSignal);
+ }
+ return createCredentialFuture;
+ } finally {
+ Binder.restoreCallingIdentity(originalCallingUidToken);
+ }
+ }).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
futureRef.set(connectThenExecute);
connectThenExecute.whenComplete((result, error) -> Handler.getMain().post(() ->
@@ -202,9 +224,11 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
return cancellationSink.get();
}
- /** Main entry point to be called for executing a clearCredentialState call on the remote
+ /**
+ * Main entry point to be called for executing a clearCredentialState call on the remote
* provider service.
- * @param request the request to be sent to the provider
+ *
+ * @param request the request to be sent to the provider
* @param callback the callback to be used to send back the provider response to the
* {@link ProviderClearSession} class that maintains provider state
*/
@@ -218,30 +242,37 @@ public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialPr
postAsync(service -> {
CompletableFuture<Void> clearCredentialFuture =
new CompletableFuture<>();
- ICancellationSignal cancellationSignal = service.onClearCredentialState(
- request, new IClearCredentialStateCallback.Stub() {
- @Override
- public void onSuccess() {
- Log.i(TAG, "In onSuccess onClearCredentialState "
- + "in RemoteCredentialService");
- clearCredentialFuture.complete(null);
- }
+ final long originalCallingUidToken = Binder.clearCallingIdentity();
+ try {
+ ICancellationSignal cancellationSignal = service.onClearCredentialState(
+ request, new IClearCredentialStateCallback.Stub() {
+ @Override
+ public void onSuccess() {
+ Log.i(TAG, "In onSuccess onClearCredentialState "
+ + "in RemoteCredentialService");
+ clearCredentialFuture.complete(null);
+ }
- @Override
- public void onFailure(String errorType, CharSequence message) {
- Log.i(TAG, "In onFailure in RemoteCredentialService");
- String errorMsg = message == null ? "" :
- String.valueOf(message);
- clearCredentialFuture.completeExceptionally(
- new ClearCredentialStateException(errorType, errorMsg));
- }});
- CompletableFuture<Void> future = futureRef.get();
- if (future != null && future.isCancelled()) {
- dispatchCancellationSignal(cancellationSignal);
- } else {
- cancellationSink.set(cancellationSignal);
+ @Override
+ public void onFailure(String errorType, CharSequence message) {
+ Log.i(TAG, "In onFailure in RemoteCredentialService");
+ String errorMsg = message == null ? "" :
+ String.valueOf(message);
+ clearCredentialFuture.completeExceptionally(
+ new ClearCredentialStateException(errorType,
+ errorMsg));
+ }
+ });
+ CompletableFuture<Void> future = futureRef.get();
+ if (future != null && future.isCancelled()) {
+ dispatchCancellationSignal(cancellationSignal);
+ } else {
+ cancellationSink.set(cancellationSignal);
+ }
+ return clearCredentialFuture;
+ } finally {
+ Binder.restoreCallingIdentity(originalCallingUidToken);
}
- return clearCredentialFuture;
}).orTimeout(TIMEOUT_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
futureRef.set(connectThenExecute);
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index fdd0e81db9d9..862266564c00 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -16,15 +16,16 @@
package com.android.server.credentials;
-import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CLEAR_CREDENTIAL;
-import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CREATE_CREDENTIAL;
-import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_GET_CREDENTIAL;
-import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_UNKNOWN;
-import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_FAILURE;
-import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_SUCCESS;
+import static com.android.server.credentials.MetricUtilities.METRICS_API_NAME_CLEAR_CREDENTIAL;
+import static com.android.server.credentials.MetricUtilities.METRICS_API_NAME_CREATE_CREDENTIAL;
+import static com.android.server.credentials.MetricUtilities.METRICS_API_NAME_GET_CREDENTIAL;
+import static com.android.server.credentials.MetricUtilities.METRICS_API_NAME_UNKNOWN;
+import static com.android.server.credentials.MetricUtilities.METRICS_API_STATUS_FAILURE;
+import static com.android.server.credentials.MetricUtilities.METRICS_API_STATUS_SUCCESS;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
+import android.content.ComponentName;
import android.content.Context;
import android.credentials.ui.ProviderData;
import android.credentials.ui.UserSelectionDialogResult;
@@ -37,7 +38,10 @@ import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialProviderInfo;
import android.util.Log;
+import com.android.internal.R;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.credentials.metrics.CandidateProviderMetric;
+import com.android.server.credentials.metrics.ChosenProviderMetric;
import java.util.ArrayList;
import java.util.HashMap;
@@ -50,20 +54,6 @@ import java.util.Map;
abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialManagerUiCallback {
private static final String TAG = "RequestSession";
- // Metrics constants
- private static final int METRICS_API_NAME_UNKNOWN =
- CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_UNKNOWN;
- private static final int METRICS_API_NAME_GET_CREDENTIAL =
- CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_GET_CREDENTIAL;
- private static final int METRICS_API_NAME_CREATE_CREDENTIAL =
- CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CREATE_CREDENTIAL;
- private static final int METRICS_API_NAME_CLEAR_CREDENTIAL =
- CREDENTIAL_MANAGER_API_CALLED__API_NAME__API_NAME_CLEAR_CREDENTIAL;
- private static final int METRICS_API_STATUS_SUCCESS =
- CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_SUCCESS;
- private static final int METRICS_API_STATUS_FAILURE =
- CREDENTIAL_MANAGER_API_CALLED__API_STATUS__API_STATUS_FAILURE;
-
// TODO: Revise access levels of attributes
@NonNull
protected final T mClientRequest;
@@ -88,6 +78,9 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
protected final CancellationSignal mCancellationSignal;
protected final Map<String, ProviderSession> mProviders = new HashMap<>();
+ protected ChosenProviderMetric mChosenProviderMetric = new ChosenProviderMetric();
+ //TODO improve design to allow grouped metrics per request
+ protected final String mHybridService;
protected RequestSession(@NonNull Context context,
@UserIdInt int userId, int callingUid, @NonNull T clientRequest, U clientCallback,
@@ -106,6 +99,8 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
mRequestId = new Binder();
mCredentialManagerUi = new CredentialManagerUi(mContext,
mUserId, this);
+ mHybridService = context.getResources().getString(
+ R.string.config_defaultCredentialManagerHybridService);
}
public abstract ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo,
@@ -165,7 +160,6 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
}
return false;
}
-
// TODO: move these definitions to a separate logging focused class.
enum RequestType {
GET_CREDENTIALS,
@@ -186,11 +180,30 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
}
}
- protected void logApiCalled(RequestType requestType, boolean isSuccessful) {
+ protected void logApiCalled(RequestType requestType, boolean isSuccessfulOverall) {
+ var providerSessions = mProviders.values();
+ int providerSize = providerSessions.size();
+ int[] candidateUidList = new int[providerSize];
+ int[] candidateQueryRoundTripTimeList = new int[providerSize];
+ int[] candidateStatusList = new int[providerSize];
+ int index = 0;
+ for (var session : providerSessions) {
+ CandidateProviderMetric metric = session.mCandidateProviderMetric;
+ candidateUidList[index] = metric.getCandidateUid();
+ candidateQueryRoundTripTimeList[index] = metric.getQueryLatencyMs();
+ candidateStatusList[index] = metric.getProviderQueryStatus();
+ index++;
+ }
FrameworkStatsLog.write(FrameworkStatsLog.CREDENTIAL_MANAGER_API_CALLED,
/* api_name */getApiNameFromRequestType(requestType), /* caller_uid */
mCallingUid, /* api_status */
- isSuccessful ? METRICS_API_STATUS_SUCCESS : METRICS_API_STATUS_FAILURE);
+ isSuccessfulOverall ? METRICS_API_STATUS_SUCCESS : METRICS_API_STATUS_FAILURE,
+ candidateUidList,
+ candidateQueryRoundTripTimeList,
+ candidateStatusList, mChosenProviderMetric.getChosenUid(),
+ mChosenProviderMetric.getEntireProviderLatencyMs(),
+ mChosenProviderMetric.getFinalPhaseLatencyMs(),
+ mChosenProviderMetric.getChosenProviderStatus());
}
protected boolean isSessionCancelled() {
@@ -239,4 +252,18 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
}
}
}
+
+ /**
+ * Called by RequestSession's upon chosen metric determination.
+ * @param componentName the componentName to associate with a provider
+ */
+ protected void setChosenMetric(ComponentName componentName) {
+ CandidateProviderMetric metric = this.mProviders.get(componentName.flattenToString())
+ .mCandidateProviderMetric;
+ mChosenProviderMetric.setChosenUid(metric.getCandidateUid());
+ mChosenProviderMetric.setFinalFinishTimeNanoseconds(System.nanoTime());
+ mChosenProviderMetric.setQueryFinishTimeNanoseconds(
+ metric.getQueryFinishTimeNanoseconds());
+ mChosenProviderMetric.setStartTimeNanoseconds(metric.getStartTimeNanoseconds());
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java b/services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java
new file mode 100644
index 000000000000..acfb4a4e3e39
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/metrics/CandidateProviderMetric.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.credentials.metrics;
+
+/**
+ * The central candidate provider metric object that mimics our defined metric setup.
+ */
+public class CandidateProviderMetric {
+
+ private int mCandidateUid = -1;
+ private long mStartTimeNanoseconds = -1;
+ private long mQueryFinishTimeNanoseconds = -1;
+
+ private int mProviderQueryStatus = -1;
+
+ public CandidateProviderMetric(long startTime, long queryFinishTime, int providerQueryStatus,
+ int candidateUid) {
+ this.mStartTimeNanoseconds = startTime;
+ this.mQueryFinishTimeNanoseconds = queryFinishTime;
+ this.mProviderQueryStatus = providerQueryStatus;
+ this.mCandidateUid = candidateUid;
+ }
+
+ public CandidateProviderMetric(){}
+
+ public void setStartTimeNanoseconds(long startTimeNanoseconds) {
+ this.mStartTimeNanoseconds = startTimeNanoseconds;
+ }
+
+ public void setQueryFinishTimeNanoseconds(long queryFinishTimeNanoseconds) {
+ this.mQueryFinishTimeNanoseconds = queryFinishTimeNanoseconds;
+ }
+
+ public void setProviderQueryStatus(int providerQueryStatus) {
+ this.mProviderQueryStatus = providerQueryStatus;
+ }
+
+ public void setCandidateUid(int candidateUid) {
+ this.mCandidateUid = candidateUid;
+ }
+
+ public long getStartTimeNanoseconds() {
+ return this.mStartTimeNanoseconds;
+ }
+
+ public long getQueryFinishTimeNanoseconds() {
+ return this.mQueryFinishTimeNanoseconds;
+ }
+
+ public int getProviderQueryStatus() {
+ return this.mProviderQueryStatus;
+ }
+
+ public int getCandidateUid() {
+ return this.mCandidateUid;
+ }
+
+ /**
+ * Returns the latency in microseconds for the query phase.
+ */
+ public int getQueryLatencyMs() {
+ return (int) ((this.getQueryFinishTimeNanoseconds()
+ - this.getStartTimeNanoseconds()) / 1000);
+ }
+
+}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java
new file mode 100644
index 000000000000..c4d0b3c7254d
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/metrics/ChosenProviderMetric.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.credentials.metrics;
+
+/**
+ * The central chosen provider metric object that mimics our defined metric setup.
+ */
+public class ChosenProviderMetric {
+
+ private int mChosenUid = -1;
+ private long mStartTimeNanoseconds = -1;
+ private long mQueryFinishTimeNanoseconds = -1;
+ private long mFinalFinishTimeNanoseconds = -1;
+ private int mChosenProviderStatus = -1;
+
+ public ChosenProviderMetric() {}
+
+ public int getChosenUid() {
+ return mChosenUid;
+ }
+
+ public void setChosenUid(int chosenUid) {
+ mChosenUid = chosenUid;
+ }
+
+ public long getStartTimeNanoseconds() {
+ return mStartTimeNanoseconds;
+ }
+
+ public void setStartTimeNanoseconds(long startTimeNanoseconds) {
+ mStartTimeNanoseconds = startTimeNanoseconds;
+ }
+
+ public long getQueryFinishTimeNanoseconds() {
+ return mQueryFinishTimeNanoseconds;
+ }
+
+ public void setQueryFinishTimeNanoseconds(long queryFinishTimeNanoseconds) {
+ mQueryFinishTimeNanoseconds = queryFinishTimeNanoseconds;
+ }
+
+ public long getFinalFinishTimeNanoseconds() {
+ return mFinalFinishTimeNanoseconds;
+ }
+
+ public void setFinalFinishTimeNanoseconds(long finalFinishTimeNanoseconds) {
+ mFinalFinishTimeNanoseconds = finalFinishTimeNanoseconds;
+ }
+
+ public int getChosenProviderStatus() {
+ return mChosenProviderStatus;
+ }
+
+ public void setChosenProviderStatus(int chosenProviderStatus) {
+ mChosenProviderStatus = chosenProviderStatus;
+ }
+
+ /**
+ * Returns the full provider (invocation to response) latency in microseconds.
+ */
+ public int getEntireProviderLatencyMs() {
+ return (int) ((this.getFinalFinishTimeNanoseconds()
+ - this.getStartTimeNanoseconds()) / 1000);
+ }
+
+ // TODO get post click final phase and re-add the query phase time to metric
+
+ /**
+ * Returns the end of query to response phase latency in microseconds.
+ */
+ public int getFinalPhaseLatencyMs() {
+ return (int) ((this.getFinalFinishTimeNanoseconds()
+ - this.getQueryFinishTimeNanoseconds()) / 1000);
+ }
+
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index d7a20953e156..88b82d798ba9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -176,7 +176,8 @@ class ActiveAdmin {
private static final String ATTR_PACKAGE_POLICY_MODE = "package-policy-type";
private static final String TAG_CREDENTIAL_MANAGER_POLICY = "credential-manager-policy";
-
+ // If the ActiveAdmin is a permission-based admin, then info will be null because the
+ // permission-based admin is not mapped to a device administrator component.
DeviceAdminInfo info;
static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
@@ -378,9 +379,11 @@ class ActiveAdmin {
void writeToXml(TypedXmlSerializer out)
throws IllegalArgumentException, IllegalStateException, IOException {
- out.startTag(null, TAG_POLICIES);
- info.writePoliciesToXml(out);
- out.endTag(null, TAG_POLICIES);
+ if (info != null) {
+ out.startTag(null, TAG_POLICIES);
+ info.writePoliciesToXml(out);
+ out.endTag(null, TAG_POLICIES);
+ }
if (mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED) {
writeAttributeValueToXml(
out, TAG_PASSWORD_QUALITY, mPasswordPolicy.quality);
@@ -1188,14 +1191,16 @@ class ActiveAdmin {
pw.print("testOnlyAdmin=");
pw.println(testOnlyAdmin);
- pw.println("policies:");
- ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
- if (pols != null) {
- pw.increaseIndent();
- for (int i = 0; i < pols.size(); i++) {
- pw.println(pols.get(i).tag);
+ if (info != null) {
+ pw.println("policies:");
+ ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
+ if (pols != null) {
+ pw.increaseIndent();
+ for (int i = 0; i < pols.size(); i++) {
+ pw.println(pols.get(i).tag);
+ }
+ pw.decreaseIndent();
}
- pw.decreaseIndent();
}
pw.print("passwordQuality=0x");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 8e430b3d169e..a5b9d4397eaf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -123,6 +123,23 @@ class DevicePolicyData {
final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
+ // Some DevicePolicyManager APIs can be called by (1) a DPC or (2) an app with permissions that
+ // isn't a DPC. For the latter, the caller won't have to provide a ComponentName and won't be
+ // mapped to an ActiveAdmin. This permission-based admin should be used to persist policies
+ // set by the permission-based caller. This admin should not be added to mAdminMap or mAdminList
+ // since a lot of methods in DPMS assume the ActiveAdmins here have a valid ComponentName.
+ // Instead, use variants of DPMS active admin getters to include the permission-based admin.
+ ActiveAdmin mPermissionBasedAdmin;
+
+ // Create or get the permission-based admin. The permission-based admin will not have a
+ // DeviceAdminInfo or ComponentName.
+ ActiveAdmin createOrGetPermissionBasedAdmin() {
+ if (mPermissionBasedAdmin == null) {
+ mPermissionBasedAdmin = new ActiveAdmin(/* info= */ null, /* parent= */ false);
+ }
+ return mPermissionBasedAdmin;
+ }
+
// TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead.
final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>();
@@ -256,6 +273,12 @@ class DevicePolicyData {
}
}
+ if (policyData.mPermissionBasedAdmin != null) {
+ out.startTag(null, "permission-based-admin");
+ policyData.mPermissionBasedAdmin.writeToXml(out);
+ out.endTag(null, "permission-based-admin");
+ }
+
if (policyData.mPasswordOwner >= 0) {
out.startTag(null, "password-owner");
out.attributeInt(null, "value", policyData.mPasswordOwner);
@@ -457,6 +480,7 @@ class DevicePolicyData {
policy.mLockTaskPackages.clear();
policy.mAdminList.clear();
policy.mAdminMap.clear();
+ policy.mPermissionBasedAdmin = null;
policy.mAffiliationIds.clear();
policy.mOwnerInstalledCaCerts.clear();
policy.mUserControlDisabledPackages = null;
@@ -484,6 +508,10 @@ class DevicePolicyData {
} catch (RuntimeException e) {
Slogf.w(TAG, e, "Failed loading admin %s", name);
}
+ } else if ("permission-based-admin".equals(tag)) {
+ ActiveAdmin ap = new ActiveAdmin(/* info= */ null, /* parent= */ false);
+ ap.readFromXml(parser, /* overwritePolicies= */ false);
+ policy.mPermissionBasedAdmin = ap;
} else if ("delegation".equals(tag)) {
// Parse delegation info.
final String delegatePackage = parser.getAttributeValue(null,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 71764dc45462..8f16737404c0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -555,8 +555,9 @@ final class DevicePolicyEngine {
if (!hasLocalPolicyLocked(policyDefinition, userId)) {
return null;
}
- return getLocalPolicyStateLocked(policyDefinition, userId)
- .getPoliciesSetByAdmins().get(enforcingAdmin).getValue();
+ PolicyValue<V> value = getLocalPolicyStateLocked(policyDefinition, userId)
+ .getPoliciesSetByAdmins().get(enforcingAdmin);
+ return value == null ? null : value.getValue();
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f5a1b80c9b96..40e047f3a990 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21,6 +21,7 @@ import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_CAMERA;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY;
import static android.Manifest.permission.QUERY_ADMIN_POLICY;
import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
@@ -33,9 +34,11 @@ import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_APP_STANDBY;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS;
+import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
+import static android.app.admin.DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
import static android.app.admin.DevicePolicyManager.ACTION_MANAGED_PROFILE_PROVISIONED;
@@ -43,7 +46,6 @@ import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEV
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
import static android.app.admin.DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED;
-import static android.app.admin.DevicePolicyManager.AUTO_TIMEZONE_POLICY;
import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
@@ -61,6 +63,7 @@ import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_APP_STANDBY;
import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS;
+import static android.app.admin.DevicePolicyManager.EXEMPT_FROM_HIBERNATION;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_IDS;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
@@ -235,6 +238,7 @@ import android.app.admin.IDevicePolicyManager;
import android.app.admin.IntegerPolicyValue;
import android.app.admin.IntentFilterPolicyKey;
import android.app.admin.LockTaskPolicy;
+import android.app.admin.LongPolicyValue;
import android.app.admin.ManagedProfileProvisioningParams;
import android.app.admin.ManagedSubscriptionsPolicy;
import android.app.admin.NetworkEvent;
@@ -726,6 +730,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION,
OPSTR_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION);
+ APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS.put(
+ EXEMPT_FROM_HIBERNATION, OPSTR_SYSTEM_EXEMPT_FROM_HIBERNATION);
}
/**
@@ -4163,6 +4169,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
/**
+ * Get the list of active admins for an affected user:
+ * <ul>
+ * <li>The active admins associated with the userHandle itself</li>
+ * <li>The parent active admins for each managed profile associated with the userHandle</li>
+ * <li>The permission based admin associated with the userHandle itself</li>
+ * </ul>
+ *
+ * @param userHandle the affected user for whom to get the active admins
+ * @return the list of active admins for the affected user
+ */
+ @GuardedBy("getLockObject()")
+ private List<ActiveAdmin> getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(
+ int userHandle) {
+ List<ActiveAdmin> list = getActiveAdminsForAffectedUserLocked(userHandle);
+ if (getUserData(userHandle).mPermissionBasedAdmin != null) {
+ list.add(getUserData(userHandle).mPermissionBasedAdmin);
+ }
+ return list;
+ }
+
+ /**
* Returns the list of admins on the given user, as well as parent admins for each managed
* profile associated with the given user. Optionally also include the admin of each managed
* profile.
@@ -8467,24 +8494,39 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* Disables all device cameras according to the specified admin.
*/
@Override
- public void setCameraDisabled(ComponentName who, boolean disabled, boolean parent) {
+ public void setCameraDisabled(ComponentName who, String callerPackageName, boolean disabled,
+ boolean parent) {
if (!mHasFeature) {
return;
}
- Objects.requireNonNull(who, "ComponentName is null");
- final CallerIdentity caller = getCallerIdentity(who);
- if (parent) {
- Preconditions.checkCallAuthorization(isProfileOwnerOfOrganizationOwnedDevice(caller));
- }
+ final CallerIdentity caller = getCallerIdentity(who, callerPackageName);
+ final int userHandle = caller.getUserId();
checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_CAMERA_DISABLED);
- final int userHandle = caller.getUserId();
+ ActiveAdmin admin = null;
+ if (isPermissionCheckFlagEnabled()) {
+ EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+ who,
+ MANAGE_DEVICE_POLICY_CAMERA,
+ callerPackageName,
+ getProfileParentUserIfRequested(userHandle, parent));
+ admin = enforcingAdmin.getActiveAdmin();
+ } else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ if (parent) {
+ Preconditions.checkCallAuthorization(
+ isProfileOwnerOfOrganizationOwnedDevice(caller));
+ }
+ synchronized (getLockObject()) {
+ admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent);
+ }
+ }
+
synchronized (getLockObject()) {
- ActiveAdmin ap = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA, parent);
- if (ap.disableCamera != disabled) {
- ap.disableCamera = disabled;
+ if (admin.disableCamera != disabled) {
+ admin.disableCamera = disabled;
saveSettingsLocked(userHandle);
}
}
@@ -8513,14 +8555,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!mHasFeature) {
return false;
}
-
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle)
- || isCameraServerUid(caller));
-
- if (parent) {
+ if (isPermissionCheckFlagEnabled()) {
+ Preconditions.checkCallAuthorization(
+ hasFullCrossUsersPermission(caller, userHandle) || isCameraServerUid(caller)
+ || hasPermission(MANAGE_DEVICE_POLICY_CAMERA, userHandle)
+ || hasPermission(QUERY_ADMIN_POLICY));
+ } else {
Preconditions.checkCallAuthorization(
- isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId()));
+ hasFullCrossUsersPermission(caller, userHandle) || isCameraServerUid(caller));
+ if (parent) {
+ Preconditions.checkCallAuthorization(
+ isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId()));
+ }
}
synchronized (getLockObject()) {
@@ -8533,12 +8580,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (deviceOwner != null && deviceOwner.disableCamera) {
return true;
}
- final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+
// Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins = getActiveAdminsForAffectedUserLocked(affectedUserId);
+ List<ActiveAdmin> admins;
+ final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle;
+ if (isPermissionCheckFlagEnabled()) {
+ admins = getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(
+ affectedUserId);
+ } else {
+ admins = getActiveAdminsForAffectedUserLocked(affectedUserId);
+ }
// Determine whether or not the device camera is disabled for any active admins.
- for (ActiveAdmin admin : admins) {
- if (admin.disableCamera) {
+ for (ActiveAdmin activeAdmin : admins) {
+ if (activeAdmin.disableCamera) {
return true;
}
}
@@ -9038,12 +9092,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private @UserIdInt int getMainUserId() {
- UserHandle mainUser = mUserManager.getMainUser();
- if (mainUser == null) {
+ int mainUserId = mUserManagerInternal.getMainUserId();
+ if (mainUserId == UserHandle.USER_NULL) {
Slogf.d(LOG_TAG, "getMainUserId(): no main user, returning USER_SYSTEM");
return UserHandle.USER_SYSTEM;
}
- return mainUser.getIdentifier();
+ return mainUserId;
}
// TODO(b/240562946): Remove api as owner name is not used.
@@ -12019,10 +12073,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
}
- int userHandle = caller.getUserId();
+ int userId = caller.getUserId();
synchronized (getLockObject()) {
final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
- getProfileOwnerOrDeviceOwnerLocked(userHandle), parent);
+ getProfileOwnerOrDeviceOwnerLocked(userId), parent);
if (isDefaultDeviceOwner(caller)) {
if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) {
@@ -12039,7 +12093,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"Cannot use the parent instance in Financed Device Owner mode");
} else {
boolean profileOwnerCanChangeOnItself = !parent
- && UserRestrictionsUtils.canProfileOwnerChange(key, userHandle);
+ && UserRestrictionsUtils.canProfileOwnerChange(
+ key, userId == getMainUserId());
boolean orgOwnedProfileOwnerCanChangesGlobally = parent
&& isProfileOwnerOfOrganizationOwnedDevice(caller)
&& UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange(
@@ -12058,7 +12113,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} else {
restrictions.remove(key);
}
- saveUserRestrictionsLocked(userHandle);
+ saveUserRestrictionsLocked(userId);
}
final int eventId = enabledFromThisOwner
? DevicePolicyEnums.ADD_USER_RESTRICTION
@@ -12072,7 +12127,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final int eventTag = enabledFromThisOwner
? SecurityLog.TAG_USER_RESTRICTION_ADDED
: SecurityLog.TAG_USER_RESTRICTION_REMOVED;
- SecurityLog.writeEvent(eventTag, who.getPackageName(), userHandle, key);
+ SecurityLog.writeEvent(eventTag, who.getPackageName(), userId, key);
}
}
@@ -13770,6 +13825,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
+ @Override
+ public boolean isStatusBarDisabled(String callerPackage) {
+ final CallerIdentity caller = getCallerIdentity(callerPackage);
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+
+ int userId = caller.getUserId();
+ synchronized (getLockObject()) {
+ Preconditions.checkCallAuthorization(isUserAffiliatedWithDeviceLocked(userId),
+ "Admin " + callerPackage
+ + " is neither the device owner or affiliated user's profile owner.");
+ if (isManagedProfile(userId)) {
+ throw new SecurityException("Managed profile cannot disable status bar");
+ }
+ DevicePolicyData policy = getUserData(userId);
+ return policy.mStatusBarDisabled;
+ }
+ }
+
+
/**
* We need to update the internal state of whether a user has completed setup or a
* device has paired once. After that, we ignore any changes that reset the
@@ -15595,6 +15670,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ caller.getPackageName(),
caller.getUserId());
admin = enforcingAdmin.getActiveAdmin();
} else {
@@ -15625,6 +15701,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ caller.getPackageName(),
caller.getUserId());
admin = enforcingAdmin.getActiveAdmin();
} else {
@@ -16996,23 +17073,52 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final CallerIdentity caller = getCallerIdentity(admin);
Preconditions.checkCallAuthorization(
isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ final int userId = caller.getUserId();
- synchronized (getLockObject()) {
- final int userHandle = caller.getUserId();
-
- DevicePolicyData policy = getUserData(userHandle);
- return mInjector.binderWithCleanCallingIdentity(() -> {
- if (policy.mPasswordTokenHandle != 0) {
- mLockPatternUtils.removeEscrowToken(policy.mPasswordTokenHandle, userHandle);
- }
- policy.mPasswordTokenHandle = mLockPatternUtils.addEscrowToken(token,
- userHandle, /*EscrowTokenStateChangeCallback*/ null);
- saveSettingsLocked(userHandle);
+ if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ EnforcingAdmin enforcingAdmin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ admin, userId);
+ Long currentTokenHandle = mDevicePolicyEngine.getLocalPolicySetByAdmin(
+ PolicyDefinition.RESET_PASSWORD_TOKEN,
+ enforcingAdmin,
+ userId);
+ long tokenHandle = addEscrowToken(
+ token, currentTokenHandle == null ? 0 : currentTokenHandle, userId);
+ if (tokenHandle == 0) {
+ return false;
+ }
+ mDevicePolicyEngine.setLocalPolicy(
+ PolicyDefinition.RESET_PASSWORD_TOKEN,
+ enforcingAdmin,
+ new LongPolicyValue(tokenHandle),
+ userId);
+ return true;
+ } else {
+ synchronized (getLockObject()) {
+ DevicePolicyData policy = getUserData(userId);
+ policy.mPasswordTokenHandle = addEscrowToken(
+ token, policy.mPasswordTokenHandle, userId);
+ saveSettingsLocked(userId);
return policy.mPasswordTokenHandle != 0;
- });
+ }
}
}
+ private long addEscrowToken(byte[] token, long currentPasswordTokenHandle, int userId) {
+ resetEscrowToken(currentPasswordTokenHandle, userId);
+ return mInjector.binderWithCleanCallingIdentity(() -> mLockPatternUtils.addEscrowToken(
+ token, userId, /* EscrowTokenStateChangeCallback= */ null));
+ }
+
+ private boolean resetEscrowToken(long tokenHandle, int userId) {
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ if (tokenHandle != 0) {
+ return mLockPatternUtils.removeEscrowToken(tokenHandle, userId);
+ }
+ return false;
+ });
+ }
+
@Override
public boolean clearResetPasswordToken(ComponentName admin) {
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
@@ -17021,22 +17127,34 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final CallerIdentity caller = getCallerIdentity(admin);
Preconditions.checkCallAuthorization(
isProfileOwner(caller) || isDefaultDeviceOwner(caller));
+ final int userId = caller.getUserId();
+ boolean result = false;
- synchronized (getLockObject()) {
- final int userHandle = caller.getUserId();
-
- DevicePolicyData policy = getUserData(userHandle);
- if (policy.mPasswordTokenHandle != 0) {
- return mInjector.binderWithCleanCallingIdentity(() -> {
- boolean result = mLockPatternUtils.removeEscrowToken(
- policy.mPasswordTokenHandle, userHandle);
+ if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ EnforcingAdmin enforcingAdmin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ admin, userId);
+ Long currentTokenHandle = mDevicePolicyEngine.getLocalPolicySetByAdmin(
+ PolicyDefinition.RESET_PASSWORD_TOKEN,
+ enforcingAdmin,
+ userId);
+ if (currentTokenHandle != null) {
+ result = resetEscrowToken(currentTokenHandle, userId);
+ mDevicePolicyEngine.removeLocalPolicy(
+ PolicyDefinition.RESET_PASSWORD_TOKEN,
+ enforcingAdmin,
+ userId);
+ }
+ } else {
+ synchronized (getLockObject()) {
+ DevicePolicyData policy = getUserData(userId);
+ if (policy.mPasswordTokenHandle != 0) {
+ result = resetEscrowToken(policy.mPasswordTokenHandle, userId);
policy.mPasswordTokenHandle = 0;
- saveSettingsLocked(userHandle);
- return result;
- });
+ saveSettingsLocked(userId);
+ }
}
}
- return false;
+ return result;
}
@Override
@@ -17048,16 +17166,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Preconditions.checkCallAuthorization(
isProfileOwner(caller) || isDefaultDeviceOwner(caller));
- synchronized (getLockObject()) {
- return isResetPasswordTokenActiveForUserLocked(caller.getUserId());
+ int userId = caller.getUserId();
+
+ if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ EnforcingAdmin enforcingAdmin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ admin, userId);
+ Long currentTokenHandle = mDevicePolicyEngine.getLocalPolicySetByAdmin(
+ PolicyDefinition.RESET_PASSWORD_TOKEN,
+ enforcingAdmin,
+ userId);
+ return isResetPasswordTokenActiveForUserLocked(
+ currentTokenHandle == null ? 0 : currentTokenHandle, userId);
+ } else {
+ synchronized (getLockObject()) {
+ DevicePolicyData policy = getUserData(userId);
+ return isResetPasswordTokenActiveForUserLocked(policy.mPasswordTokenHandle, userId);
+ }
}
}
- private boolean isResetPasswordTokenActiveForUserLocked(int userHandle) {
- DevicePolicyData policy = getUserData(userHandle);
- if (policy.mPasswordTokenHandle != 0) {
+ private boolean isResetPasswordTokenActiveForUserLocked(
+ long passwordTokenHandle, int userHandle) {
+ if (passwordTokenHandle != 0) {
return mInjector.binderWithCleanCallingIdentity(() ->
- mLockPatternUtils.isEscrowTokenActive(policy.mPasswordTokenHandle, userHandle));
+ mLockPatternUtils.isEscrowTokenActive(passwordTokenHandle, userHandle));
}
return false;
}
@@ -17074,24 +17206,41 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Preconditions.checkCallAuthorization(
isProfileOwner(caller) || isDefaultDeviceOwner(caller));
- synchronized (getLockObject()) {
- DevicePolicyData policy = getUserData(caller.getUserId());
- if (policy.mPasswordTokenHandle != 0) {
- final String password = passwordOrNull != null ? passwordOrNull : "";
- final boolean result = resetPasswordInternal(password, policy.mPasswordTokenHandle,
- token, flags, caller);
- if (result) {
- DevicePolicyEventLogger
- .createEvent(DevicePolicyEnums.RESET_PASSWORD_WITH_TOKEN)
- .setAdmin(caller.getComponentName())
- .write();
- }
- return result;
+ int userId = caller.getUserId();
+ boolean result = false;
+ final String password = passwordOrNull != null ? passwordOrNull : "";
+
+ if (useDevicePolicyEngine(caller, /* delegateScope= */ null)) {
+ EnforcingAdmin enforcingAdmin = EnforcingAdmin.createEnterpriseEnforcingAdmin(
+ admin, userId);
+ Long currentTokenHandle = mDevicePolicyEngine.getLocalPolicySetByAdmin(
+ PolicyDefinition.RESET_PASSWORD_TOKEN,
+ enforcingAdmin,
+ userId);
+ if (currentTokenHandle != null && currentTokenHandle != 0) {
+ result = resetPasswordInternal(password, currentTokenHandle, token, flags, caller);
} else {
Slogf.w(LOG_TAG, "No saved token handle");
}
+ } else {
+ synchronized (getLockObject()) {
+ DevicePolicyData policy = getUserData(userId);
+ if (policy.mPasswordTokenHandle != 0) {
+ result = resetPasswordInternal(
+ password, policy.mPasswordTokenHandle, token, flags, caller);
+ } else {
+ Slogf.w(LOG_TAG, "No saved token handle");
+ }
+ }
}
- return false;
+
+ if (result) {
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.RESET_PASSWORD_WITH_TOKEN)
+ .setAdmin(caller.getComponentName())
+ .write();
+ }
+ return result;
}
@Override
@@ -18784,9 +18933,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
"call canProfileOwnerResetPasswordWhenLocked"));
synchronized (getLockObject()) {
final ActiveAdmin poAdmin = getProfileOwnerAdminLocked(userId);
+ DevicePolicyData policy = getUserData(userId);
if (poAdmin == null
|| getEncryptionStatus() != ENCRYPTION_STATUS_ACTIVE_PER_USER
- || !isResetPasswordTokenActiveForUserLocked(userId)) {
+ || !isResetPasswordTokenActiveForUserLocked(
+ policy.mPasswordTokenHandle, userId)) {
return false;
}
final ApplicationInfo poAppInfo;
@@ -20324,9 +20475,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* the associated cross-user permission if the caller's user is different to the target user.
*/
private EnforcingAdmin enforcePermissionAndGetEnforcingAdmin(@Nullable ComponentName admin,
- String permission, int targetUserId) {
+ String permission, String callerPackageName, int targetUserId) {
enforcePermission(permission, targetUserId);
- return getEnforcingAdminForCaller(admin, getCallerIdentity());
+ return getEnforcingAdminForCaller(admin, callerPackageName);
}
/**
@@ -20341,9 +20492,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* the associated cross-user permission if the caller's user is different to the target user.
*/
private EnforcingAdmin enforceCanQueryAndGetEnforcingAdmin(@Nullable ComponentName admin,
- String permission, int targetUserId) {
+ String permission, String callerPackageName, int targetUserId) {
enforceCanQuery(permission, targetUserId);
- return getEnforcingAdminForCaller(admin, getCallerIdentity());
+ return getEnforcingAdminForCaller(admin, callerPackageName);
}
private static final HashMap<String, String> POLICY_IDENTIFIER_TO_PERMISSION = new HashMap<>();
@@ -20487,7 +20638,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
private EnforcingAdmin getEnforcingAdminForCaller(@Nullable ComponentName who,
- CallerIdentity caller) {
+ String callerPackageName) {
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
int userId = caller.getUserId();
ActiveAdmin admin = null;
synchronized (getLockObject()) {
@@ -20499,7 +20651,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (getActiveAdminUncheckedLocked(who, userId) != null) {
return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
}
- return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId);
+ if (admin == null) {
+ admin = getUserData(userId).createOrGetPermissionBasedAdmin();
+ }
+ return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
}
private boolean isPermissionCheckFlagEnabled() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
index 10e972d3698a..a303fde1524d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java
@@ -19,10 +19,10 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.Authority;
-import android.app.admin.UnknownAuthority;
import android.app.admin.DeviceAdminAuthority;
import android.app.admin.DpcAuthority;
import android.app.admin.RoleAuthority;
+import android.app.admin.UnknownAuthority;
import android.content.ComponentName;
import android.os.UserHandle;
@@ -71,9 +71,10 @@ final class EnforcingAdmin {
private final boolean mIsRoleAuthority;
private final ActiveAdmin mActiveAdmin;
- static EnforcingAdmin createEnforcingAdmin(@NonNull String packageName, int userId) {
+ static EnforcingAdmin createEnforcingAdmin(@NonNull String packageName, int userId,
+ ActiveAdmin admin) {
Objects.requireNonNull(packageName);
- return new EnforcingAdmin(packageName, userId);
+ return new EnforcingAdmin(packageName, userId, admin);
}
static EnforcingAdmin createEnterpriseEnforcingAdmin(
@@ -111,6 +112,23 @@ final class EnforcingAdmin {
return ROLE_AUTHORITY_PREFIX + roleName;
}
+ static Authority getParcelableAuthority(String authority) {
+ if (authority == null || authority.isEmpty()) {
+ return UnknownAuthority.UNKNOWN_AUTHORITY;
+ }
+ if (DPC_AUTHORITY.equals(authority)) {
+ return DpcAuthority.DPC_AUTHORITY;
+ }
+ if (DEVICE_ADMIN_AUTHORITY.equals(authority)) {
+ return DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY;
+ }
+ if (authority.startsWith(ROLE_AUTHORITY_PREFIX)) {
+ String role = authority.substring(ROLE_AUTHORITY_PREFIX.length());
+ return new RoleAuthority(Set.of(role));
+ }
+ return UnknownAuthority.UNKNOWN_AUTHORITY;
+ }
+
private EnforcingAdmin(
String packageName, ComponentName componentName, Set<String> authorities, int userId,
ActiveAdmin activeAdmin) {
@@ -127,7 +145,7 @@ final class EnforcingAdmin {
mActiveAdmin = activeAdmin;
}
- private EnforcingAdmin(String packageName, int userId) {
+ private EnforcingAdmin(String packageName, int userId, ActiveAdmin activeAdmin) {
Objects.requireNonNull(packageName);
// Only role authorities use this constructor.
@@ -137,7 +155,7 @@ final class EnforcingAdmin {
mComponentName = null;
// authorities will be loaded when needed
mAuthorities = null;
- mActiveAdmin = null;
+ mActiveAdmin = activeAdmin;
}
private static Set<String> getRoleAuthoritiesOrDefault(String packageName, int userId) {
@@ -274,7 +292,7 @@ final class EnforcingAdmin {
int userId = parser.getAttributeInt(/* namespace= */ null, ATTR_USER_ID);
if (isRoleAuthority) {
- return new EnforcingAdmin(packageName, userId);
+ return new EnforcingAdmin(packageName, userId, null);
} else {
String className = parser.getAttributeValue(/* namespace= */ null, ATTR_CLASS_NAME);
ComponentName componentName = new ComponentName(packageName, className);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java
new file mode 100644
index 000000000000..f77d051cab86
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/LongPolicySerializer.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.admin.LongPolicyValue;
+import android.app.admin.PolicyKey;
+import android.util.Log;
+
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+final class LongPolicySerializer extends PolicySerializer<Long> {
+
+ @Override
+ void saveToXml(PolicyKey policyKey, TypedXmlSerializer serializer, String attributeName,
+ @NonNull Long value) throws IOException {
+ Objects.requireNonNull(value);
+ serializer.attributeLong(/* namespace= */ null, attributeName, value);
+ }
+
+ @Nullable
+ @Override
+ LongPolicyValue readFromXml(TypedXmlPullParser parser, String attributeName) {
+ try {
+ return new LongPolicyValue(
+ parser.getAttributeLong(/* namespace= */ null, attributeName));
+ } catch (XmlPullParserException e) {
+ Log.e(DevicePolicyEngine.TAG, "Error parsing Long policy value", e);
+ return null;
+ }
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index ab6f7327b0c2..21c9434636c2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -19,6 +19,7 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.BooleanPolicyValue;
+import android.app.admin.DevicePolicyIdentifiers;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IntegerPolicyValue;
import android.app.admin.IntentFilterPolicyKey;
@@ -73,7 +74,7 @@ final class PolicyDefinition<V> {
List.of(new BooleanPolicyValue(true), new BooleanPolicyValue(false)));
static PolicyDefinition<Boolean> AUTO_TIMEZONE = new PolicyDefinition<>(
- new NoArgsPolicyKey(DevicePolicyManager.AUTO_TIMEZONE_POLICY),
+ new NoArgsPolicyKey(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY),
// auto timezone is disabled by default, hence enabling it is more restrictive.
TRUE_MORE_RESTRICTIVE,
POLICY_FLAG_GLOBAL_ONLY_POLICY,
@@ -86,7 +87,7 @@ final class PolicyDefinition<V> {
// when reading the policies from xml.
static final PolicyDefinition<Integer> GENERIC_PERMISSION_GRANT =
new PolicyDefinition<>(
- new PackagePermissionPolicyKey(DevicePolicyManager.PERMISSION_GRANT_POLICY),
+ new PackagePermissionPolicyKey(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY),
// TODO: is this really the best mechanism, what makes denied more
// restrictive than
// granted?
@@ -113,16 +114,17 @@ final class PolicyDefinition<V> {
}
return GENERIC_PERMISSION_GRANT.createPolicyDefinition(
new PackagePermissionPolicyKey(
- DevicePolicyManager.PERMISSION_GRANT_POLICY,
+ DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
packageName,
permissionName));
}
static PolicyDefinition<LockTaskPolicy> LOCK_TASK = new PolicyDefinition<>(
- new NoArgsPolicyKey(DevicePolicyManager.LOCK_TASK_POLICY),
+ new NoArgsPolicyKey(DevicePolicyIdentifiers.LOCK_TASK_POLICY),
new TopPriority<>(List.of(
// TODO(b/258166155): add correct device lock role name
- EnforcingAdmin.getRoleAuthorityOf("DeviceLock"),
+ EnforcingAdmin.getRoleAuthorityOf(
+ "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER"),
EnforcingAdmin.DPC_AUTHORITY)),
POLICY_FLAG_LOCAL_ONLY_POLICY,
(LockTaskPolicy value, Context context, Integer userId, PolicyKey policyKey) ->
@@ -131,7 +133,8 @@ final class PolicyDefinition<V> {
static PolicyDefinition<Set<String>> USER_CONTROLLED_DISABLED_PACKAGES =
new PolicyDefinition<>(
- new NoArgsPolicyKey(DevicePolicyManager.USER_CONTROL_DISABLED_PACKAGES_POLICY),
+ new NoArgsPolicyKey(
+ DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY),
new StringSetUnion(),
(Set<String> value, Context context, Integer userId, PolicyKey policyKey) ->
PolicyEnforcerCallbacks.setUserControlDisabledPackages(value, userId),
@@ -143,10 +146,11 @@ final class PolicyDefinition<V> {
static PolicyDefinition<ComponentName> GENERIC_PERSISTENT_PREFERRED_ACTIVITY =
new PolicyDefinition<>(
new IntentFilterPolicyKey(
- DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY),
+ DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY),
new TopPriority<>(List.of(
// TODO(b/258166155): add correct device lock role name
- EnforcingAdmin.getRoleAuthorityOf("DeviceLock"),
+ EnforcingAdmin.getRoleAuthorityOf(
+ "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER"),
EnforcingAdmin.DPC_AUTHORITY)),
POLICY_FLAG_LOCAL_ONLY_POLICY,
PolicyEnforcerCallbacks::addPersistentPreferredActivity,
@@ -163,7 +167,8 @@ final class PolicyDefinition<V> {
}
return GENERIC_PERSISTENT_PREFERRED_ACTIVITY.createPolicyDefinition(
new IntentFilterPolicyKey(
- DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY, intentFilter));
+ DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
+ intentFilter));
}
// This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
@@ -172,7 +177,7 @@ final class PolicyDefinition<V> {
static PolicyDefinition<Boolean> GENERIC_PACKAGE_UNINSTALL_BLOCKED =
new PolicyDefinition<>(
new PackagePolicyKey(
- DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY),
+ DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY),
TRUE_MORE_RESTRICTIVE,
POLICY_FLAG_LOCAL_ONLY_POLICY,
PolicyEnforcerCallbacks::setUninstallBlocked,
@@ -189,7 +194,7 @@ final class PolicyDefinition<V> {
}
return GENERIC_PACKAGE_UNINSTALL_BLOCKED.createPolicyDefinition(
new PackagePolicyKey(
- DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY, packageName));
+ DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY, packageName));
}
// This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
@@ -198,7 +203,9 @@ final class PolicyDefinition<V> {
static PolicyDefinition<Bundle> GENERIC_APPLICATION_RESTRICTIONS =
new PolicyDefinition<>(
new PackagePolicyKey(
- DevicePolicyManager.APPLICATION_RESTRICTIONS_POLICY),
+ DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY),
+ // Don't need to take in a resolution mechanism since its never used, but might
+ // need some refactoring to not always assume a non-null mechanism.
new MostRecent<>(),
POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_NON_COEXISTABLE_POLICY,
// Application restrictions are now stored and retrieved from DPMS, so no
@@ -218,22 +225,35 @@ final class PolicyDefinition<V> {
}
return GENERIC_APPLICATION_RESTRICTIONS.createPolicyDefinition(
new PackagePolicyKey(
- DevicePolicyManager.APPLICATION_RESTRICTIONS_POLICY, packageName));
+ DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY, packageName));
}
+ static PolicyDefinition<Long> RESET_PASSWORD_TOKEN = new PolicyDefinition<>(
+ new NoArgsPolicyKey(DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY),
+ // Don't need to take in a resolution mechanism since its never used, but might
+ // need some refactoring to not always assume a non-null mechanism.
+ new MostRecent<>(),
+ POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_NON_COEXISTABLE_POLICY,
+ // DevicePolicyManagerService handles the enforcement, this just takes care of storage
+ (Long value, Context context, Integer userId, PolicyKey policyKey) -> true,
+ new LongPolicySerializer());
+
private static final Map<String, PolicyDefinition<?>> sPolicyDefinitions = Map.of(
- DevicePolicyManager.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE,
- DevicePolicyManager.PERMISSION_GRANT_POLICY, GENERIC_PERMISSION_GRANT,
- DevicePolicyManager.LOCK_TASK_POLICY, LOCK_TASK,
- DevicePolicyManager.USER_CONTROL_DISABLED_PACKAGES_POLICY,
+ DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE,
+ DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY, GENERIC_PERMISSION_GRANT,
+ DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK,
+ DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY,
USER_CONTROLLED_DISABLED_PACKAGES,
- DevicePolicyManager.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
+ DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
GENERIC_PERSISTENT_PREFERRED_ACTIVITY,
- DevicePolicyManager.PACKAGE_UNINSTALL_BLOCKED_POLICY, GENERIC_PACKAGE_UNINSTALL_BLOCKED,
- DevicePolicyManager.APPLICATION_RESTRICTIONS_POLICY, GENERIC_APPLICATION_RESTRICTIONS
+ DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY,
+ GENERIC_PACKAGE_UNINSTALL_BLOCKED,
+ DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY,
+ GENERIC_APPLICATION_RESTRICTIONS,
+ DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY,
+ RESET_PASSWORD_TOKEN
);
-
private final PolicyKey mPolicyKey;
private final ResolutionMechanism<V> mResolutionMechanism;
private final int mPolicyFlags;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java b/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java
index 839840b33a03..825157f05ac5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/TopPriority.java
@@ -17,8 +17,10 @@
package com.android.server.devicepolicy;
import android.annotation.NonNull;
+import android.app.admin.Authority;
import android.app.admin.PolicyValue;
+import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -54,7 +56,15 @@ final class TopPriority<V> extends ResolutionMechanism<V> {
@Override
android.app.admin.TopPriority<V> getParcelableResolutionMechanism() {
- return new android.app.admin.TopPriority<>(mHighestToLowestPriorityAuthorities);
+ return new android.app.admin.TopPriority<>(getParcelableAuthorities());
+ }
+
+ private List<Authority> getParcelableAuthorities() {
+ List<Authority> authorities = new ArrayList<>();
+ for (String authority : mHighestToLowestPriorityAuthorities) {
+ authorities.add(EnforcingAdmin.getParcelableAuthority(authority));
+ }
+ return authorities;
}
@Override
diff --git a/services/java/com/android/server/HsumBootUserInitializer.java b/services/java/com/android/server/HsumBootUserInitializer.java
index a1853b4632fc..50113feb558b 100644
--- a/services/java/com/android/server/HsumBootUserInitializer.java
+++ b/services/java/com/android/server/HsumBootUserInitializer.java
@@ -113,11 +113,7 @@ final class HsumBootUserInitializer {
UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN,
/* disallowedPackages= */ null,
/* token= */ null);
- if (newInitialUser == null) {
- Slogf.wtf(TAG, "Initial bootable MainUser creation failed: returned null");
- } else {
- Slogf.i(TAG, "Successfully created MainUser, userId=%d", newInitialUser.id);
- }
+ Slogf.i(TAG, "Successfully created MainUser, userId=%d", newInitialUser.id);
} catch (UserManager.CheckedUserOperationException e) {
Slogf.wtf(TAG, "Initial bootable MainUser creation failed", e);
}
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 61f868198978..ef35010c1da2 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -18,6 +18,7 @@ package com.android.server.permission.access.permission
import android.Manifest
import android.app.ActivityManager
+import android.app.AppOpsManager
import android.compat.annotation.ChangeId
import android.compat.annotation.EnabledAfter
import android.content.Context
@@ -59,10 +60,12 @@ import com.android.server.PermissionThread
import com.android.server.ServiceThread
import com.android.server.SystemConfig
import com.android.server.permission.access.AccessCheckingService
+import com.android.server.permission.access.AppOpUri
import com.android.server.permission.access.GetStateScope
import com.android.server.permission.access.MutateStateScope
import com.android.server.permission.access.PermissionUri
import com.android.server.permission.access.UidUri
+import com.android.server.permission.access.appop.UidAppOpPolicy
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.util.andInv
import com.android.server.permission.access.util.hasAnyBit
@@ -733,18 +736,46 @@ class PermissionService(
}
}
- private fun grantRequestedRuntimePermissions(
+ private fun setRequestedPermissionStates(
packageState: PackageState,
userId: Int,
- permissionNames: IndexedList<String>
+ permissionStates: IndexedMap<String, Int>
) {
service.mutateState {
- permissionNames.forEachIndexed { _, permissionName ->
- setRuntimePermissionGranted(
- packageState, userId, permissionName, isGranted = true,
- canManageRolePermission = false, overridePolicyFixed = false,
- reportError = false, "grantRequestedRuntimePermissions"
- )
+ permissionStates.forEachIndexed { _, permissionName, permissionState ->
+ when (permissionState) {
+ PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED,
+ PackageInstaller.SessionParams.PERMISSION_STATE_DENIED -> {}
+ else -> {
+ Log.w(
+ LOG_TAG, "setRequestedPermissionStates: Unknown permission state" +
+ " $permissionState for permission $permissionName"
+ )
+ return@forEachIndexed
+ }
+ }
+ if (permissionName !in packageState.androidPackage!!.requestedPermissions) {
+ return@forEachIndexed
+ }
+ val permission = with(policy) { getPermissions()[permissionName] }
+ ?: return@forEachIndexed
+ when {
+ permission.isDevelopment || permission.isRuntime -> {
+ if (permissionState ==
+ PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED) {
+ setRuntimePermissionGranted(
+ packageState, userId, permissionName, isGranted = true,
+ canManageRolePermission = false, overridePolicyFixed = false,
+ reportError = false, "setRequestedPermissionStates"
+ )
+ }
+ }
+ permission.isAppOp -> setAppOpPermissionGranted(
+ packageState, userId, permissionName,
+ permissionState == PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
+ )
+ else -> {}
+ }
}
}
}
@@ -890,6 +921,18 @@ class PermissionService(
}
}
+ private fun MutateStateScope.setAppOpPermissionGranted(
+ packageState: PackageState,
+ userId: Int,
+ permissionName: String,
+ isGranted: Boolean
+ ) {
+ val appOpPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as UidAppOpPolicy
+ val appOpName = AppOpsManager.permissionToOp(permissionName)
+ val mode = if (isGranted) AppOpsManager.MODE_ALLOWED else AppOpsManager.MODE_ERRORED
+ with(appOpPolicy) { setAppOpMode(packageState.appId, userId, appOpName, mode) }
+ }
+
override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
if (!userManagerInternal.exists(userId)) {
Log.w(LOG_TAG, "getPermissionFlags: Unknown user $userId")
@@ -1814,15 +1857,7 @@ class PermissionService(
val packageState =
packageManagerInternal.getPackageStateInternal(androidPackage.packageName)!!
// TODO: Add allowlisting
- grantRequestedRuntimePermissions(
- packageState,
- userId,
- params.permissionStates.mapNotNullIndexed { _, permissionName, permissionState ->
- permissionName.takeIf {
- permissionState == PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
- }
- }
- )
+ setRequestedPermissionStates(packageState, userId, params.permissionStates)
}
}
diff --git a/services/proguard.flags b/services/proguard.flags
index c13304430d98..c31abbb5c0d6 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -95,7 +95,7 @@
-keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.GnssPowerStats { *; }
-keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.hal.GnssNative { *; }
-keep,allowoptimization,allowaccessmodification class com.android.server.pm.PackageManagerShellCommandDataLoader { *; }
--keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorManagerInternal$RuntimeSensorStateChangeCallback { *; }
+-keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorManagerInternal$RuntimeSensorCallback { *; }
-keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorManagerInternal$ProximityActiveListener { *; }
-keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorService { *; }
-keep,allowoptimization,allowaccessmodification class com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareImpl$AudioSessionProvider$AudioSession { *; }
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
index 31c49b3fab0a..9c4e6fd66ceb 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
+++ b/services/tests/PackageManagerServiceTests/appenumeration/Android.bp
@@ -33,6 +33,7 @@ android_test {
"Harrier",
],
platform_apis: true,
+ certificate: "platform",
test_suites: ["device-tests"],
data: [
":AppEnumerationCrossUserPackageVisibilityTestApp",
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
index 0395aa8a1db6..47494195c778 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
+++ b/services/tests/PackageManagerServiceTests/appenumeration/AndroidManifest.xml
@@ -25,6 +25,7 @@
<!-- It's merged from Harrier library. Remove it since this test should not hold it. -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:node="remove" />
+ <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.server.pm.test.appenumeration"
diff --git a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
index 31fe18410182..4012d8e4af96 100644
--- a/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
+++ b/services/tests/PackageManagerServiceTests/appenumeration/src/com/android/server/pm/test/appenumeration/AppEnumerationInternalTests.java
@@ -16,6 +16,8 @@
package com.android.server.pm.test.appenumeration;
+import static android.content.Context.MEDIA_PROJECTION_SERVICE;
+
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import static com.google.common.truth.Truth.assertThat;
@@ -26,7 +28,10 @@ import android.content.Context;
import android.content.IntentSender;
import android.content.pm.IPackageManager;
import android.content.pm.ProviderInfo;
+import android.media.projection.IMediaProjectionManager;
+import android.media.projection.MediaProjectionManager;
import android.os.Process;
+import android.os.ServiceManager;
import android.os.UserHandle;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -160,6 +165,31 @@ public class AppEnumerationInternalTests {
null /* onFinished */, null /* handler */));
}
+ @Test
+ public void mediaProjectionManager_createProjection_canSeeForceQueryable()
+ throws Exception {
+ installPackage(SHARED_USER_APK_PATH, true /* forceQueryable */);
+ final IMediaProjectionManager mediaProjectionManager =
+ IMediaProjectionManager.Stub.asInterface(
+ ServiceManager.getService(MEDIA_PROJECTION_SERVICE));
+
+ assertThat(mediaProjectionManager.createProjection(0 /* uid */, TARGET_SHARED_USER,
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */))
+ .isNotNull();
+ }
+
+ @Test
+ public void mediaProjectionManager_createProjection_cannotSeeTarget() {
+ installPackage(SHARED_USER_APK_PATH, false /* forceQueryable */);
+ final IMediaProjectionManager mediaProjectionManager =
+ IMediaProjectionManager.Stub.asInterface(
+ ServiceManager.getService(MEDIA_PROJECTION_SERVICE));
+
+ Assert.assertThrows(IllegalArgumentException.class,
+ () -> mediaProjectionManager.createProjection(0 /* uid */, TARGET_SHARED_USER,
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */));
+ }
+
private static void installPackage(String apkPath, boolean forceQueryable) {
final StringBuilder cmd = new StringBuilder("pm install ");
if (forceQueryable) {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
index d760dc7c1a66..811b0860ea64 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt
@@ -15,7 +15,6 @@
*/
package com.android.server.pm
-import android.Manifest
import android.content.Context
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionParams
@@ -122,12 +121,10 @@ class PackageInstallerSessionTest {
writeRestoreAssert(sessions).single().params.run {
assertThat(legacyGrantedRuntimePermissions).asList()
.containsExactly("grantPermission", "denyToGrantPermission")
- assertThat(finalPermissionStates)
+ assertThat(permissionStates)
.containsExactlyEntriesIn(mapOf(
"grantPermission" to PERMISSION_STATE_GRANTED,
"denyToGrantPermission" to PERMISSION_STATE_GRANTED,
- // Fullscreen Intent is auto-granted if the caller has no opinion
- Manifest.permission.USE_FULL_SCREEN_INTENT to PERMISSION_STATE_GRANTED,
"denyPermission" to PERMISSION_STATE_DENIED,
"grantToDenyPermission" to PERMISSION_STATE_DENIED,
))
@@ -282,7 +279,7 @@ class PackageInstallerSessionTest {
assertThat(expected.referrerUri).isEqualTo(actual.referrerUri)
assertThat(expected.abiOverride).isEqualTo(actual.abiOverride)
assertThat(expected.volumeUuid).isEqualTo(actual.volumeUuid)
- assertThat(expected.finalPermissionStates).isEqualTo(actual.finalPermissionStates)
+ assertThat(expected.permissionStates).isEqualTo(actual.permissionStates)
assertThat(expected.installerPackageName).isEqualTo(actual.installerPackageName)
assertThat(expected.isMultiPackage).isEqualTo(actual.isMultiPackage)
assertThat(expected.isStaged).isEqualTo(actual.isStaged)
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index 9895e7ccdac1..c7fb32c2aa17 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -753,7 +753,7 @@ public class PackageParserTest {
.setPVersionCode(pkg.getLongVersionCode())
.setPkgFlags(PackageInfoUtils.appInfoFlags(pkg, null))
.setPrivateFlags(PackageInfoUtils.appInfoPrivateFlags(pkg, null))
- .setSharedUserId(pkg.getSharedUserLabelRes())
+ .setSharedUserId(pkg.getSharedUserLabelResourceId())
.build();
}
@@ -763,13 +763,13 @@ public class PackageParserTest {
assertEquals(a.getBaseRevisionCode(), b.getBaseRevisionCode());
assertEquals(a.isHardwareAccelerated(), b.isHardwareAccelerated());
assertEquals(a.getLongVersionCode(), b.getLongVersionCode());
- assertEquals(a.getSharedUserLabelRes(), b.getSharedUserLabelRes());
+ assertEquals(a.getSharedUserLabelResourceId(), b.getSharedUserLabelResourceId());
assertEquals(a.getInstallLocation(), b.getInstallLocation());
assertEquals(a.isCoreApp(), b.isCoreApp());
assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers());
assertEquals(a.getCompileSdkVersion(), b.getCompileSdkVersion());
assertEquals(a.getCompileSdkVersionCodeName(), b.getCompileSdkVersionCodeName());
- assertEquals(a.isUse32BitAbi(), b.isUse32BitAbi());
+ assertEquals(a.is32BitAbiPreferred(), b.is32BitAbiPreferred());
assertEquals(a.getPackageName(), b.getPackageName());
assertArrayEquals(a.getSplitNames(), b.getSplitNames());
assertEquals(a.getVolumeUuid(), b.getVolumeUuid());
@@ -1039,7 +1039,7 @@ public class PackageParserTest {
((ParsedPackage) pkg.setBaseRevisionCode(100)
.setHardwareAccelerated(true)
- .setSharedUserLabelRes(100)
+ .setSharedUserLabelResourceId(100)
.setInstallLocation(100)
.setRequiredForAllUsers(true)
.asSplit(
@@ -1048,7 +1048,7 @@ public class PackageParserTest {
new int[]{100},
null
)
- .setUse32BitAbi(true)
+ .set32BitAbiPreferred(true)
.setVolumeUuid("d52ef59a-7def-4541-bf21-4c28ed4b65a0")
.addPermission(permission)
.addPermissionGroup(new ParsedPermissionGroupImpl())
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 0b7020c74f66..6d3cdffda837 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -155,7 +155,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::getAppComponentFactory,
AndroidPackage::getAutoRevokePermissions,
AndroidPackage::getBackupAgentName,
- AndroidPackage::getBannerRes,
+ AndroidPackage::getBannerResourceId,
AndroidPackage::getBaseApkPath,
AndroidPackage::getBaseRevisionCode,
AndroidPackage::getCategory,
@@ -163,16 +163,16 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::getCompatibleWidthLimitDp,
AndroidPackage::getCompileSdkVersion,
AndroidPackage::getCompileSdkVersionCodeName,
- AndroidPackage::getDataExtractionRulesRes,
- AndroidPackage::getDescriptionRes,
- AndroidPackage::getFullBackupContentRes,
+ AndroidPackage::getDataExtractionRulesResourceId,
+ AndroidPackage::getDescriptionResourceId,
+ AndroidPackage::getFullBackupContentResourceId,
AndroidPackage::getGwpAsanMode,
- AndroidPackage::getIconRes,
+ AndroidPackage::getIconResourceId,
AndroidPackage::getInstallLocation,
- AndroidPackage::getLabelRes,
+ AndroidPackage::getLabelResourceId,
AndroidPackage::getLargestWidthLimitDp,
- AndroidPackage::getLogoRes,
- AndroidPackage::getLocaleConfigRes,
+ AndroidPackage::getLogoResourceId,
+ AndroidPackage::getLocaleConfigResourceId,
AndroidPackage::getManageSpaceActivityName,
AndroidPackage::getMaxSdkVersion,
AndroidPackage::getMemtagMode,
@@ -180,7 +180,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::getNativeHeapZeroInitialized,
AndroidPackage::getNativeLibraryDir,
AndroidPackage::getNativeLibraryRootDir,
- AndroidPackage::getNetworkSecurityConfigRes,
+ AndroidPackage::getNetworkSecurityConfigResourceId,
AndroidPackage::getNonLocalizedLabel,
AndroidPackage::getOverlayCategory,
AndroidPackage::getOverlayPriority,
@@ -195,11 +195,11 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::getRequiresSmallestWidthDp,
AndroidPackage::getResizeableActivity,
AndroidPackage::getRestrictedAccountType,
- AndroidPackage::getRoundIconRes,
+ AndroidPackage::getRoundIconResourceId,
PackageImpl::getSecondaryCpuAbi,
AndroidPackage::getSecondaryNativeLibraryDir,
AndroidPackage::getSharedUserId,
- AndroidPackage::getSharedUserLabelRes,
+ AndroidPackage::getSharedUserLabelResourceId,
AndroidPackage::getSdkLibraryName,
AndroidPackage::getSdkLibVersionMajor,
AndroidPackage::getStaticSharedLibraryName,
@@ -207,21 +207,21 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::getTargetSandboxVersion,
AndroidPackage::getTargetSdkVersion,
AndroidPackage::getTaskAffinity,
- AndroidPackage::getThemeRes,
+ AndroidPackage::getThemeResourceId,
AndroidPackage::getUiOptions,
AndroidPackage::getUid,
AndroidPackage::getVersionName,
AndroidPackage::getZygotePreloadName,
AndroidPackage::isAllowAudioPlaybackCapture,
- AndroidPackage::isAllowBackup,
- AndroidPackage::isAllowClearUserData,
- AndroidPackage::isAllowClearUserDataOnFailedRestore,
+ AndroidPackage::isBackupAllowed,
+ AndroidPackage::isClearUserDataAllowed,
+ AndroidPackage::isClearUserDataOnFailedRestoreAllowed,
AndroidPackage::isAllowNativeHeapPointerTagging,
- AndroidPackage::isAllowTaskReparenting,
+ AndroidPackage::isTaskReparentingAllowed,
AndroidPackage::isAllowUpdateOwnership,
AndroidPackage::isBackupInForeground,
AndroidPackage::isHardwareAccelerated,
- AndroidPackage::isCantSaveState,
+ AndroidPackage::isSaveStateDisallowed,
AndroidPackage::isCoreApp,
AndroidPackage::isCrossProfile,
AndroidPackage::isDebuggable,
@@ -229,17 +229,17 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::isDirectBootAware,
AndroidPackage::isEnabled,
AndroidPackage::isExternalStorage,
- AndroidPackage::isExtractNativeLibs,
+ AndroidPackage::isExtractNativeLibrariesRequested,
AndroidPackage::isFactoryTest,
AndroidPackage::isApex,
AndroidPackage::isForceQueryable,
AndroidPackage::isFullBackupOnly,
AndroidPackage::isGame,
- AndroidPackage::isHasCode,
+ AndroidPackage::isDeclaredHavingCode,
AndroidPackage::isHasDomainUrls,
- AndroidPackage::isHasFragileUserData,
+ AndroidPackage::isUserDataFragile,
AndroidPackage::isIsolatedSplitLoading,
- AndroidPackage::isKillAfterRestore,
+ AndroidPackage::isKillAfterRestoreAllowed,
AndroidPackage::isLargeHeap,
AndroidPackage::isMultiArch,
AndroidPackage::isNativeLibraryRootRequiresIsa,
@@ -257,12 +257,12 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::isSdkLibrary,
AndroidPackage::isStaticSharedLibrary,
AndroidPackage::isStub,
- AndroidPackage::isSupportsRtl,
+ AndroidPackage::isRtlSupported,
AndroidPackage::isTestOnly,
- AndroidPackage::isUse32BitAbi,
+ AndroidPackage::is32BitAbiPreferred,
AndroidPackage::isUseEmbeddedDex,
- AndroidPackage::isUsesCleartextTraffic,
- AndroidPackage::isUsesNonSdkApi,
+ AndroidPackage::isCleartextTrafficAllowed,
+ AndroidPackage::isNonSdkApiRequested,
AndroidPackage::isVisibleToInstantApps,
AndroidPackage::isVmSafeMode,
AndroidPackage::isLeavingSharedUser,
@@ -282,10 +282,10 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
getter(AndroidPackage::getUpgradeKeySets, setOf("testUpgradeKeySet")),
getter(AndroidPackage::isAnyDensity, false, 0),
getter(AndroidPackage::isResizeable, false, 0),
- getter(AndroidPackage::isSupportsSmallScreens, false, 0),
- getter(AndroidPackage::isSupportsNormalScreens, false, 0),
- getter(AndroidPackage::isSupportsLargeScreens, false, 0),
- getter(AndroidPackage::isSupportsExtraLargeScreens, false, 0),
+ getter(AndroidPackage::isSmallScreensSupported, false, 0),
+ getter(AndroidPackage::isNormalScreensSupported, false, 0),
+ getter(AndroidPackage::isLargeScreensSupported, false, 0),
+ getter(AndroidPackage::isExtraLargeScreensSupported, false, 0),
adder(AndroidPackage::getAdoptPermissions, "test.adopt.PERMISSION"),
adder(AndroidPackage::getOriginalPackages, "com.test.original"),
adder(AndroidPackage::getImplicitPermissions, "test.implicit.PERMISSION"),
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
index 8a855e51fc3d..5a733c7ea117 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
@@ -312,4 +312,4 @@ class PackageStateTest {
.that(exception)
.isNotNull()
}
-} \ No newline at end of file
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 419351d489c0..9263bffc48eb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -711,8 +711,6 @@ public class ApplicationExitInfoTest {
null); // description
// Case 8: App1 gets "remove task"
- final String app1Description = "remove task";
-
sleep(1);
final int app1IsolatedUidUser2 = 1099002; // isolated uid
final long app1Pss4 = 34343;
@@ -739,7 +737,7 @@ public class ApplicationExitInfoTest {
mAppExitInfoTracker.mIsolatedUidRecords.addIsolatedUid(app1IsolatedUidUser2, app1UidUser2);
noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_UNKNOWN, app1Description, now8);
+ ApplicationExitInfo.SUBREASON_REMOVE_TASK, null, now8);
updateExitInfo(app, now8);
list.clear();
@@ -749,21 +747,21 @@ public class ApplicationExitInfoTest {
info = list.get(0);
verifyApplicationExitInfo(
- info, // info
- now8, // timestamp
- app1PidUser2, // pid
- app1IsolatedUidUser2, // uid
- app1UidUser2, // packageUid
- null, // definingUid
- app1ProcessName, // processName
- 0, // connectionGroup
- ApplicationExitInfo.REASON_OTHER, // reason
- ApplicationExitInfo.SUBREASON_UNKNOWN, // subReason
- 0, // status
- app1Pss4, // pss
- app1Rss4, // rss
- IMPORTANCE_CACHED, // importance
- app1Description); // description
+ info, // info
+ now8, // timestamp
+ app1PidUser2, // pid
+ app1IsolatedUidUser2, // uid
+ app1UidUser2, // packageUid
+ null, // definingUid
+ app1ProcessName, // processName
+ 0, // connectionGroup
+ ApplicationExitInfo.REASON_OTHER, // reason
+ ApplicationExitInfo.SUBREASON_REMOVE_TASK, // subReason
+ 0, // status
+ app1Pss4, // pss
+ app1Rss4, // rss
+ IMPORTANCE_CACHED, // importance
+ null); // description
// App1 gets "too many empty"
final String app1Description2 = "too many empty";
@@ -1058,7 +1056,18 @@ public class ApplicationExitInfoTest {
if (importance != null) {
assertEquals(importance.intValue(), info.getImportance());
}
- if (description != null) {
+
+ // info.getDescription returns a combination of subReason & description
+ if ((subReason != null) && (subReason != ApplicationExitInfo.SUBREASON_UNKNOWN)
+ && (description != null)) {
+ assertTrue(TextUtils.equals(
+ "[" + info.subreasonToString(subReason) + "] " + description,
+ info.getDescription()));
+ } else if ((subReason != null) && (subReason != ApplicationExitInfo.SUBREASON_UNKNOWN)) {
+ assertTrue(TextUtils.equals(
+ "[" + info.subreasonToString(subReason) + "]",
+ info.getDescription()));
+ } else if (description != null) {
assertTrue(TextUtils.equals(description, info.getDescription()));
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index ad224df5b944..68cfe4591c51 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -223,8 +223,7 @@ public class BroadcastQueueModernImplTest {
private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
BroadcastRecord record, int recordIndex, long enqueueTime) {
- queue.enqueueOrReplaceBroadcast(record, recordIndex,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(record, recordIndex, false);
record.enqueueTime = enqueueTime;
}
@@ -354,8 +353,7 @@ public class BroadcastQueueModernImplTest {
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
List.of(makeMockRegisteredReceiver()));
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);
queue.setProcessCached(false);
final long notCachedRunnableAt = queue.getRunnableAt();
@@ -377,14 +375,12 @@ public class BroadcastQueueModernImplTest {
// enqueue a bg-priority broadcast then a fg-priority one
final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
final BroadcastRecord timezoneRecord = makeBroadcastRecord(timezone);
- queue.enqueueOrReplaceBroadcast(timezoneRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(timezoneRecord, 0, false);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
airplane.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane);
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);
// verify that:
// (a) the queue is immediately runnable by existence of a fg-priority broadcast
@@ -415,8 +411,7 @@ public class BroadcastQueueModernImplTest {
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, null,
List.of(withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10),
withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 0)), true);
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 1,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 1, false);
assertFalse(queue.isRunnable());
assertEquals(BroadcastProcessQueue.REASON_BLOCKED, queue.getRunnableAtReason());
@@ -439,8 +434,7 @@ public class BroadcastQueueModernImplTest {
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
List.of(makeMockRegisteredReceiver()));
- queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);
mConstants.MAX_PENDING_BROADCASTS = 128;
queue.invalidateRunnableAt();
@@ -466,13 +460,11 @@ public class BroadcastQueueModernImplTest {
new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
List.of(makeMockRegisteredReceiver()));
- queue.enqueueOrReplaceBroadcast(lazyRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(lazyRecord, 0, false);
assertThat(queue.getRunnableAt()).isGreaterThan(lazyRecord.enqueueTime);
assertThat(queue.getRunnableAtReason()).isNotEqualTo(testRunnableAtReason);
- queue.enqueueOrReplaceBroadcast(testRecord, 0,
- null /* replacedBroadcastConsumer */, false);
+ queue.enqueueOrReplaceBroadcast(testRecord, 0, false);
assertThat(queue.getRunnableAt()).isAtMost(testRecord.enqueueTime);
assertThat(queue.getRunnableAtReason()).isEqualTo(testRunnableAtReason);
}
@@ -534,26 +526,20 @@ public class BroadcastQueueModernImplTest {
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
- .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0,
- null /* replacedBroadcastConsumer */, false);
+ .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false);
queue.enqueueOrReplaceBroadcast(
- makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0,
- null /* replacedBroadcastConsumer */, false);
+ makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0,
- null /* replacedBroadcastConsumer */, false);
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)
- .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0,
- null /* replacedBroadcastConsumer */, false);
+ .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false);
queue.enqueueOrReplaceBroadcast(
- makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0,
- null /* replacedBroadcastConsumer */, false);
+ makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0, false);
queue.enqueueOrReplaceBroadcast(
makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0,
- null /* replacedBroadcastConsumer */, false);
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false);
queue.makeActiveNextPending();
assertEquals(Intent.ACTION_LOCKED_BOOT_COMPLETED, queue.getActive().intent.getAction());
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 458c9cfc4c2f..6bc2d1f11405 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -20,6 +20,7 @@ import static android.os.UserHandle.USER_SYSTEM;
import static com.android.server.am.BroadcastProcessQueue.reasonToString;
import static com.android.server.am.BroadcastRecord.deliveryStateToString;
+import static com.android.server.am.BroadcastRecord.isReceiverEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -76,8 +77,6 @@ import android.os.PowerExemptionManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
-import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -160,7 +159,7 @@ public class BroadcastQueueTest {
private ActivityManagerService mAms;
private BroadcastQueue mQueue;
BroadcastConstants mConstants;
- private TestBroadcastSkipPolicy mSkipPolicy;
+ private BroadcastSkipPolicy mSkipPolicy;
/**
* Desired behavior of the next
@@ -287,7 +286,10 @@ public class BroadcastQueueTest {
mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS);
mConstants.TIMEOUT = 100;
mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0;
- mSkipPolicy = new TestBroadcastSkipPolicy(mAms);
+
+ mSkipPolicy = spy(new BroadcastSkipPolicy(mAms));
+ doReturn(null).when(mSkipPolicy).shouldSkipMessage(any(), any());
+ doReturn(false).when(mSkipPolicy).disallowBackgroundStart(any());
final BroadcastHistory emptyHistory = new BroadcastHistory(mConstants) {
public void addBroadcastToHistoryLocked(BroadcastRecord original) {
@@ -324,48 +326,6 @@ public class BroadcastQueueTest {
}
}
- private static class TestBroadcastSkipPolicy extends BroadcastSkipPolicy {
- private final ArrayMap<String, ArraySet> mReceiversToSkip = new ArrayMap<>();
-
- TestBroadcastSkipPolicy(ActivityManagerService service) {
- super(service);
- }
-
- public String shouldSkipMessage(BroadcastRecord r, Object o) {
- if (shouldSkipReceiver(r.intent.getAction(), o)) {
- return "test skipped receiver";
- }
- return null;
- }
-
- private boolean shouldSkipReceiver(String action, Object o) {
- final ArraySet<Object> receiversToSkip = mReceiversToSkip.get(action);
- if (receiversToSkip == null) {
- return false;
- }
- for (int i = 0; i < receiversToSkip.size(); ++i) {
- if (BroadcastRecord.isReceiverEquals(o, receiversToSkip.valueAt(i))) {
- return true;
- }
- }
- return false;
- }
-
- public void setSkipReceiver(String action, Object o) {
- ArraySet<Object> receiversToSkip = mReceiversToSkip.get(action);
- if (receiversToSkip == null) {
- receiversToSkip = new ArraySet<>();
- mReceiversToSkip.put(action, receiversToSkip);
- }
- receiversToSkip.add(o);
- }
- public boolean disallowBackgroundStart(BroadcastRecord r) {
- // Ignored
- return false;
- }
-
- }
-
private class TestInjector extends Injector {
TestInjector(Context context) {
super(context);
@@ -2039,8 +1999,16 @@ public class BroadcastQueueTest {
enqueueBroadcast(makeBroadcastRecord(airplane, callerApp,
List.of(greenReceiver, blueReceiver, yellowReceiver, orangeReceiver)));
- mSkipPolicy.setSkipReceiver(airplane.getAction(), greenReceiver);
- mSkipPolicy.setSkipReceiver(airplane.getAction(), orangeReceiver);
+ doAnswer(invocation -> {
+ final BroadcastRecord r = invocation.getArgument(0);
+ final Object o = invocation.getArgument(1);
+ if (airplane.getAction().equals(r.intent.getAction())
+ && (isReceiverEquals(o, greenReceiver)
+ || isReceiverEquals(o, orangeReceiver))) {
+ return "test skipped receiver";
+ }
+ return null;
+ }).when(mSkipPolicy).shouldSkipMessage(any(BroadcastRecord.class), any());
}
waitForIdle();
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index b9893f6ee170..f1acf663eae1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -147,12 +147,12 @@ class PackageManagerServiceHibernationTests {
TEST_PACKAGE_NAME,
1L,
rule.system().dataAppDirectory,
- withPackage = { it.apply { isHasCode = true } })
+ withPackage = { it.apply { isDeclaredHavingCode = true } })
rule.system().stageScanExistingPackage(
TEST_PACKAGE_2_NAME,
1L,
rule.system().dataAppDirectory,
- withPackage = { it.apply { isHasCode = true } })
+ withPackage = { it.apply { isDeclaredHavingCode = true } })
val pm = createPackageManagerService()
rule.system().validateFinalState()
whenever(appHibernationManager.isHibernatingGlobally(TEST_PACKAGE_2_NAME)).thenReturn(true)
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index e605a317f096..99f7905a9f70 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -35,7 +35,6 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
-import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.common.OperationContext;
@@ -365,16 +364,6 @@ public class FingerprintAuthenticationClientTest {
showHideOverlay(c -> c.onLockoutPermanent());
}
- @Test
- public void testPowerPressForwardsErrorMessage() throws RemoteException {
- final FingerprintAuthenticationClient client = createClient();
-
- client.onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR,
- BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED);
-
- verify(mClientMonitorCallbackConverter).onError(anyInt(), anyInt(),
- eq(BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED), eq(0));
- }
private void showHideOverlay(Consumer<FingerprintAuthenticationClient> block)
throws RemoteException {
final FingerprintAuthenticationClient client = createClient();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index a40d3fe3a3d6..26524d7df7c3 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED;
+
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -27,7 +29,6 @@ import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.PointerContext;
@@ -275,12 +276,11 @@ public class FingerprintEnrollClientTest {
@Test
public void testPowerPressForwardsAcquireMessage() throws RemoteException {
final FingerprintEnrollClient client = createClient();
-
- client.onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR,
- BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED);
+ client.start(mCallback);
+ client.onPowerPressed();
verify(mClientMonitorCallbackConverter).onAcquired(anyInt(),
- eq(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED), eq(0));
+ eq(FINGERPRINT_ACQUIRED_POWER_PRESSED), anyInt());
}
private void showHideOverlay(Consumer<FingerprintEnrollClient> block)
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
index ef8a49f95a49..6431e88b1acb 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
@@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
+import android.companion.virtual.sensor.IVirtualSensorCallback;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.hardware.Sensor;
@@ -54,6 +55,8 @@ public class SensorControllerTest {
@Mock
private SensorManagerInternal mSensorManagerInternalMock;
+ @Mock
+ private IVirtualSensorCallback mVirtualSensorCallback;
private SensorController mSensorController;
private VirtualSensorEvent mSensorEvent;
private VirtualSensorConfig mVirtualSensorConfig;
@@ -66,7 +69,8 @@ public class SensorControllerTest {
LocalServices.removeServiceForTest(SensorManagerInternal.class);
LocalServices.addService(SensorManagerInternal.class, mSensorManagerInternalMock);
- mSensorController = new SensorController(new Object(), VIRTUAL_DEVICE_ID);
+ mSensorController =
+ new SensorController(new Object(), VIRTUAL_DEVICE_ID, mVirtualSensorCallback);
mSensorEvent = new VirtualSensorEvent.Builder(new float[] { 1f, 2f, 3f}).build();
mVirtualSensorConfig =
new VirtualSensorConfig.Builder(Sensor.TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME)
@@ -135,6 +139,7 @@ public class SensorControllerTest {
private void doCreateSensorSuccessfully() {
doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
anyInt(), anyInt(), anyString(), anyString(), any());
- mSensorController.createSensor(mSensorToken, mVirtualSensorConfig);
+ assertThat(mSensorController.createSensor(mSensorToken, mVirtualSensorConfig))
+ .isEqualTo(SENSOR_HANDLE);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index ce5ddb060a29..0cd50f03fbfa 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -55,6 +55,9 @@ import android.companion.virtual.IVirtualDeviceSoundEffectListener;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.audio.IAudioConfigChangedCallback;
import android.companion.virtual.audio.IAudioRoutingCallback;
+import android.companion.virtual.sensor.IVirtualSensorCallback;
+import android.companion.virtual.sensor.VirtualSensor;
+import android.companion.virtual.sensor.VirtualSensorCallback;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.content.ComponentName;
import android.content.Context;
@@ -102,6 +105,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
import com.android.internal.app.BlockedAppStreamingActivity;
+import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.input.InputManagerInternal;
import com.android.server.sensors.SensorManagerInternal;
@@ -225,6 +229,10 @@ public class VirtualDeviceManagerServiceTest {
@Mock
private SensorManagerInternal mSensorManagerInternalMock;
@Mock
+ private IVirtualSensorCallback mVirtualSensorCallback;
+ @Mock
+ private VirtualSensorCallback mSensorCallback;
+ @Mock
private IVirtualDeviceActivityListener mActivityListener;
@Mock
private IVirtualDeviceSoundEffectListener mSoundEffectListener;
@@ -333,7 +341,8 @@ public class VirtualDeviceManagerServiceTest {
mInputController = new InputController(new Object(), mNativeWrapperMock,
new Handler(TestableLooper.get(this).getLooper()),
mContext.getSystemService(WindowManager.class), threadVerifier);
- mSensorController = new SensorController(new Object(), VIRTUAL_DEVICE_ID_1);
+ mSensorController =
+ new SensorController(new Object(), VIRTUAL_DEVICE_ID_1, mVirtualSensorCallback);
mCameraAccessController =
new CameraAccessController(mContext, mLocalService, mCameraAccessBlockedCallback);
@@ -451,6 +460,42 @@ public class VirtualDeviceManagerServiceTest {
}
@Test
+ public void getVirtualSensor_defaultDeviceId_returnsNull() {
+ assertThat(mLocalService.getVirtualSensor(DEVICE_ID_DEFAULT, SENSOR_HANDLE)).isNull();
+ }
+
+ @Test
+ public void getVirtualSensor_invalidDeviceId_returnsNull() {
+ assertThat(mLocalService.getVirtualSensor(DEVICE_ID_INVALID, SENSOR_HANDLE)).isNull();
+ }
+
+ @Test
+ public void getVirtualSensor_noSensors_returnsNull() {
+ assertThat(mLocalService.getVirtualSensor(VIRTUAL_DEVICE_ID_1, SENSOR_HANDLE)).isNull();
+ }
+
+ @Test
+ public void getVirtualSensor_returnsCorrectSensor() {
+ VirtualDeviceParams params = new VirtualDeviceParams.Builder()
+ .setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
+ .addVirtualSensorConfig(
+ new VirtualSensorConfig.Builder(Sensor.TYPE_ACCELEROMETER, DEVICE_NAME_1)
+ .build())
+ .setVirtualSensorCallback(BackgroundThread.getExecutor(), mSensorCallback)
+ .build();
+
+ doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
+ anyInt(), anyInt(), anyString(), anyString(), any());
+ mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
+
+ VirtualSensor sensor = mLocalService.getVirtualSensor(VIRTUAL_DEVICE_ID_1, SENSOR_HANDLE);
+ assertThat(sensor).isNotNull();
+ assertThat(sensor.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID_1);
+ assertThat(sensor.getHandle()).isEqualTo(SENSOR_HANDLE);
+ assertThat(sensor.getType()).isEqualTo(Sensor.TYPE_ACCELEROMETER);
+ }
+
+ @Test
public void getDeviceIdsForUid_noRunningApps_returnsNull() {
Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
assertThat(deviceIds).isEmpty();
@@ -888,18 +933,6 @@ public class VirtualDeviceManagerServiceTest {
}
@Test
- public void createVirtualSensor_noPermission_failsSecurityException() {
- try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
- assertThrows(
- SecurityException.class,
- () -> mDeviceImpl.createVirtualSensor(
- BINDER,
- new VirtualSensorConfig.Builder(
- Sensor.TYPE_ACCELEROMETER, DEVICE_NAME_1).build()));
- }
- }
-
- @Test
public void onAudioSessionStarting_noPermission_failsSecurityException() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1);
try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
deleted file mode 100644
index 798650dcc9ce..000000000000
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.companion.virtual;
-
-import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
-import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
-import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
-import static android.hardware.Sensor.TYPE_ACCELEROMETER;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.companion.virtual.VirtualDeviceParams;
-import android.companion.virtual.sensor.VirtualSensorConfig;
-import android.os.Parcel;
-import android.os.UserHandle;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-import java.util.Set;
-
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class VirtualDeviceParamsTest {
-
- private static final String SENSOR_NAME = "VirtualSensorName";
- private static final String SENSOR_VENDOR = "VirtualSensorVendor";
- private static final int PLAYBACK_SESSION_ID = 42;
- private static final int RECORDING_SESSION_ID = 77;
-
- @Test
- public void parcelable_shouldRecreateSuccessfully() {
- VirtualDeviceParams originalParams = new VirtualDeviceParams.Builder()
- .setLockState(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED)
- .setUsersWithMatchingAccounts(Set.of(UserHandle.of(123), UserHandle.of(456)))
- .setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
- .setDevicePolicy(POLICY_TYPE_AUDIO, DEVICE_POLICY_CUSTOM)
- .setAudioPlaybackSessionId(PLAYBACK_SESSION_ID)
- .setAudioRecordingSessionId(RECORDING_SESSION_ID)
- .addVirtualSensorConfig(
- new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
- .setVendor(SENSOR_VENDOR)
- .build())
- .build();
- Parcel parcel = Parcel.obtain();
- originalParams.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
-
- VirtualDeviceParams params = VirtualDeviceParams.CREATOR.createFromParcel(parcel);
- assertThat(params).isEqualTo(originalParams);
- assertThat(params.getLockState()).isEqualTo(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED);
- assertThat(params.getUsersWithMatchingAccounts())
- .containsExactly(UserHandle.of(123), UserHandle.of(456));
- assertThat(params.getDevicePolicy(POLICY_TYPE_SENSORS)).isEqualTo(DEVICE_POLICY_CUSTOM);
- assertThat(params.getDevicePolicy(POLICY_TYPE_AUDIO)).isEqualTo(DEVICE_POLICY_CUSTOM);
- assertThat(params.getAudioPlaybackSessionId()).isEqualTo(PLAYBACK_SESSION_ID);
- assertThat(params.getAudioRecordingSessionId()).isEqualTo(RECORDING_SESSION_ID);
-
- List<VirtualSensorConfig> sensorConfigs = params.getVirtualSensorConfigs();
- assertThat(sensorConfigs).hasSize(1);
- VirtualSensorConfig sensorConfig = sensorConfigs.get(0);
- assertThat(sensorConfig.getType()).isEqualTo(TYPE_ACCELEROMETER);
- assertThat(sensorConfig.getName()).isEqualTo(SENSOR_NAME);
- assertThat(sensorConfig.getVendor()).isEqualTo(SENSOR_VENDOR);
- assertThat(sensorConfig.getStateChangeCallback()).isNull();
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 1904671cd778..a616fbca3679 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -183,6 +183,10 @@ public class DisplayManagerServiceTest {
int[] getSupportedHdrOutputTypes() {
return new int[]{};
}
+
+ boolean getHdrOutputConversionSupport() {
+ return false;
+ }
}
private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 07a5303c9d65..a387d4a8b2bc 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -20,7 +20,6 @@ import static com.android.server.devicepolicy.DpmTestUtils.assertRestrictions;
import static com.android.server.devicepolicy.DpmTestUtils.newRestrictions;
import android.os.Bundle;
-import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import android.test.AndroidTestCase;
@@ -77,30 +76,30 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase {
assertTrue(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_USER_SWITCH));
}
- public void testCanProfileOwnerChange() {
- int user = UserHandle.USER_SYSTEM;
+ public void testCanProfileOwnerChange_mainUser() {
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_RECORD_AUDIO, user));
+ UserManager.DISALLOW_RECORD_AUDIO, true));
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_WALLPAPER, user));
+ UserManager.DISALLOW_WALLPAPER, true));
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_USER_SWITCH, user));
+ UserManager.DISALLOW_USER_SWITCH, true));
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_ADD_USER, user));
+ UserManager.DISALLOW_ADD_USER, true));
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_ADJUST_VOLUME, user));
+ UserManager.DISALLOW_ADJUST_VOLUME, true));
+ }
- user = 10;
+ public void testCanProfileOwnerChange_notMainUser() {
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_RECORD_AUDIO, user));
+ UserManager.DISALLOW_RECORD_AUDIO, false));
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_WALLPAPER, user));
+ UserManager.DISALLOW_WALLPAPER, false));
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_ADD_USER, user));
+ UserManager.DISALLOW_ADD_USER, false));
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_USER_SWITCH, user));
+ UserManager.DISALLOW_USER_SWITCH, false));
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
- UserManager.DISALLOW_ADJUST_VOLUME, user));
+ UserManager.DISALLOW_ADJUST_VOLUME, false));
}
public void testMoveRestriction() {
diff --git a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java
index 6553ea907563..454d3f32c96a 100644
--- a/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/LowPowerStandbyControllerTest.java
@@ -16,6 +16,7 @@
package com.android.server.power;
+import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST;
import static android.os.PowerManager.LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION;
import static android.os.PowerManager.LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN;
@@ -62,6 +63,8 @@ import androidx.test.InstrumentationRegistry;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
+import com.android.server.PowerAllowlistInternal;
+import com.android.server.PowerAllowlistInternal.TempAllowlistChangeListener;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.power.LowPowerStandbyController.DeviceConfigWrapper;
import com.android.server.testutils.OffsettableClock;
@@ -117,6 +120,8 @@ public class LowPowerStandbyControllerTest {
private PowerManagerInternal mPowerManagerInternalMock;
@Mock
private NetworkPolicyManagerInternal mNetworkPolicyManagerInternalMock;
+ @Mock
+ private PowerAllowlistInternal mPowerAllowlistInternalMock;
@Before
public void setUp() throws Exception {
@@ -130,6 +135,7 @@ public class LowPowerStandbyControllerTest {
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
addLocalServiceMock(NetworkPolicyManagerInternal.class, mNetworkPolicyManagerInternalMock);
+ addLocalServiceMock(PowerAllowlistInternal.class, mPowerAllowlistInternalMock);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
@@ -169,6 +175,7 @@ public class LowPowerStandbyControllerTest {
LocalServices.removeServiceForTest(PowerManagerInternal.class);
LocalServices.removeServiceForTest(LowPowerStandbyControllerInternal.class);
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
+ LocalServices.removeServiceForTest(PowerAllowlistInternal.class);
mTestPolicyFile.delete();
}
@@ -614,7 +621,7 @@ public class LowPowerStandbyControllerTest {
InOrder inOrder = inOrder(mPowerManagerInternalMock);
- inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[] {
+ inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{
UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID),
UserHandle.getUid(USER_ID_2, TEST_PKG1_APP_ID),
});
@@ -626,7 +633,7 @@ public class LowPowerStandbyControllerTest {
mContextSpy.sendBroadcast(intent);
mTestLooper.dispatchAll();
- inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[] {
+ inOrder.verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{
UserHandle.getUid(USER_ID_1, TEST_PKG1_APP_ID)
});
inOrder.verifyNoMoreInteractions();
@@ -663,6 +670,39 @@ public class LowPowerStandbyControllerTest {
assertFalse(mController.isPackageExempt(TEST_PKG1_APP_ID));
}
+ @Test
+ public void testAllowReason_tempPowerSaveAllowlist() throws Exception {
+ mController.systemReady();
+ mController.setEnabled(true);
+ mController.setPolicy(policyWithAllowedReasons(
+ LOW_POWER_STANDBY_ALLOWED_REASON_TEMP_POWER_SAVE_ALLOWLIST));
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor<TempAllowlistChangeListener> tempAllowlistChangeListenerArgumentCaptor =
+ ArgumentCaptor.forClass(TempAllowlistChangeListener.class);
+ verify(mPowerAllowlistInternalMock).registerTempAllowlistChangeListener(
+ tempAllowlistChangeListenerArgumentCaptor.capture());
+ TempAllowlistChangeListener tempAllowlistChangeListener =
+ tempAllowlistChangeListenerArgumentCaptor.getValue();
+
+ tempAllowlistChangeListener.onAppAdded(TEST_PKG1_APP_ID);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG1_APP_ID});
+
+ tempAllowlistChangeListener.onAppAdded(TEST_PKG2_APP_ID);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(
+ new int[]{TEST_PKG1_APP_ID, TEST_PKG2_APP_ID});
+
+ tempAllowlistChangeListener.onAppRemoved(TEST_PKG1_APP_ID);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[]{TEST_PKG2_APP_ID});
+
+ mController.setPolicy(EMPTY_POLICY);
+ mTestLooper.dispatchAll();
+ verify(mPowerManagerInternalMock).setLowPowerStandbyAllowlist(new int[0]);
+ }
+
private void setInteractive() throws Exception {
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
mContextSpy.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 9c68ddc9af6a..33ca5c2bbe16 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -302,30 +302,6 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
}
@Test
- public void testXmlMigratingAllowedAdjustments() throws Exception {
- // Old tag, need migration
- String xml = "<q_allowed_adjustments types=\"adj_1\"/>";
-
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(
- new ByteArrayInputStream(xml.toString().getBytes())), null);
- parser.nextTag();
- mAssistants.readExtraTag("q_allowed_adjustments", parser);
- assertTrue(mAssistants.isAdjustmentAllowed("adj_1"));
- assertEquals(mNm.DEFAULT_ALLOWED_ADJUSTMENTS.length + 1,
- mAssistants.getAllowedAssistantAdjustments().size());
-
- // New TAG
- xml = "<s_allowed_adjustments types=\"adj_2\"/>";
- parser.setInput(new BufferedInputStream(
- new ByteArrayInputStream(xml.toString().getBytes())), null);
- parser.nextTag();
- mAssistants.readExtraTag("s_allowed_adjustments", parser);
- assertTrue(mAssistants.isAdjustmentAllowed("adj_2"));
- assertEquals(1, mAssistants.getAllowedAssistantAdjustments().size());
- }
-
- @Test
public void testSetPackageOrComponentEnabled_onlyOnePackage() throws Exception {
ComponentName component1 = ComponentName.unflattenFromString("package/Component1");
ComponentName component2 = ComponentName.unflattenFromString("package/Component2");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 69fccf2671da..009b2591ea9d 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -203,7 +203,6 @@ import androidx.test.InstrumentationRegistry;
import com.android.internal.app.IAppOpsService;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.InstanceIdSequenceFake;
import com.android.internal.messages.nano.SystemMessageProto;
@@ -7619,17 +7618,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testGetAllowedAssistantAdjustments() throws Exception {
- List<String> capabilities = mBinderService.getAllowedAssistantAdjustments(null);
- assertNotNull(capabilities);
-
- for (int i = capabilities.size() - 1; i >= 0; i--) {
- String capability = capabilities.get(i);
- mBinderService.disallowAssistantAdjustment(capability);
- assertEquals(i + 1, mBinderService.getAllowedAssistantAdjustments(null).size());
- List<String> currentCapabilities = mBinderService.getAllowedAssistantAdjustments(null);
- assertNotNull(currentCapabilities);
- assertFalse(currentCapabilities.contains(capability));
- }
+ List<String> adjustments = mBinderService.getAllowedAssistantAdjustments(null);
+ assertNotNull(adjustments);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index cdbcecc4b59b..05ee2f24fbaf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -704,15 +704,15 @@ public class TransitionTests extends WindowTestsBase {
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
- final Task newTask = createTask(mDisplayContent);
- doReturn(false).when(newTask).isTranslucent(any());
final Task oldTask = createTask(mDisplayContent);
- doReturn(false).when(oldTask).isTranslucent(any());
+ final Task newTask = createTask(mDisplayContent);
final ActivityRecord closing = createActivityRecord(oldTask);
closing.setOccludesParent(true);
+ closing.visibleIgnoringKeyguard = true;
final ActivityRecord opening = createActivityRecord(newTask);
- opening.setOccludesParent(false);
+ opening.setOccludesParent(true);
+ opening.visibleIgnoringKeyguard = true;
// Start states.
changes.put(newTask, new Transition.ChangeInfo(newTask, false /* vis */, true /* exChg */));
changes.put(oldTask, new Transition.ChangeInfo(oldTask, true /* vis */, false /* exChg */));
@@ -735,8 +735,8 @@ public class TransitionTests extends WindowTestsBase {
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
- assertTrue((info.getChanges().get(0).getFlags() & FLAG_TRANSLUCENT) == 0);
- assertTrue((info.getChanges().get(1).getFlags() & FLAG_TRANSLUCENT) == 0);
+ assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
}
@Test
@@ -745,15 +745,15 @@ public class TransitionTests extends WindowTestsBase {
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
ArraySet<WindowContainer> participants = transition.mParticipants;
- final Task newTask = createTask(mDisplayContent);
- doReturn(true).when(newTask).isTranslucent(any());
final Task oldTask = createTask(mDisplayContent);
- doReturn(false).when(oldTask).isTranslucent(any());
+ final Task newTask = createTask(mDisplayContent);
final ActivityRecord closing = createActivityRecord(oldTask);
closing.setOccludesParent(true);
+ closing.visibleIgnoringKeyguard = true;
final ActivityRecord opening = createActivityRecord(newTask);
opening.setOccludesParent(false);
+ opening.visibleIgnoringKeyguard = true;
// Start states.
changes.put(newTask, new Transition.ChangeInfo(newTask, false /* vis */, true /* exChg */));
changes.put(oldTask, new Transition.ChangeInfo(oldTask, true /* vis */, false /* exChg */));
@@ -776,8 +776,186 @@ public class TransitionTests extends WindowTestsBase {
assertEquals(2, info.getChanges().size());
assertEquals(transit, info.getType());
- assertTrue((info.getChanges().get(0).getFlags() & FLAG_TRANSLUCENT) != 0);
- assertTrue((info.getChanges().get(1).getFlags() & FLAG_TRANSLUCENT) == 0);
+ assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+ }
+
+ @Test
+ public void testOpenOpaqueTaskFragment() {
+ final Transition transition = createTestTransition(TRANSIT_OPEN);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+ final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+
+ final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+ closing.setOccludesParent(true);
+ closing.visibleIgnoringKeyguard = true;
+ final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+ opening.setOccludesParent(true);
+ opening.visibleIgnoringKeyguard = true;
+ // Start states.
+ changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+ false /* vis */, true /* exChg */));
+ changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+ true /* vis */, false /* exChg */));
+ changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+ changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+ fillChangeMap(changes, openingTaskFragment);
+ // End states.
+ closing.setVisibleRequested(false);
+ opening.setVisibleRequested(true);
+
+ final int transit = transition.mType;
+ int flags = 0;
+
+ // Check basic both tasks participating
+ participants.add(closingTaskFragment);
+ participants.add(openingTaskFragment);
+ ArrayList<Transition.ChangeInfo> targets =
+ Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transit, info.getType());
+
+ assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+ }
+
+ @Test
+ public void testOpenTranslucentTaskFragment() {
+ final Transition transition = createTestTransition(TRANSIT_OPEN);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+ final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+
+ final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+ closing.setOccludesParent(true);
+ closing.visibleIgnoringKeyguard = true;
+ final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+ opening.setOccludesParent(false);
+ opening.visibleIgnoringKeyguard = true;
+ // Start states.
+ changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+ false /* vis */, true /* exChg */));
+ changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+ true /* vis */, false /* exChg */));
+ changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+ changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+ fillChangeMap(changes, openingTaskFragment);
+ // End states.
+ closing.setVisibleRequested(false);
+ opening.setVisibleRequested(true);
+
+ final int transit = transition.mType;
+ int flags = 0;
+
+ // Check basic both tasks participating
+ participants.add(closingTaskFragment);
+ participants.add(openingTaskFragment);
+ ArrayList<Transition.ChangeInfo> targets =
+ Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transit, info.getType());
+
+ assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+ }
+
+ @Test
+ public void testCloseOpaqueTaskFragment_withFinishingActivity() {
+ final Transition transition = createTestTransition(TRANSIT_CLOSE);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+ final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+
+ final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+ opening.setOccludesParent(true);
+ opening.visibleIgnoringKeyguard = true;
+ final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+ closing.setOccludesParent(true);
+ closing.visibleIgnoringKeyguard = true;
+ closing.finishing = true;
+ // Start states.
+ changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+ false /* vis */, true /* exChg */));
+ changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+ true /* vis */, false /* exChg */));
+ changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+ changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+ fillChangeMap(changes, openingTaskFragment);
+ // End states.
+ closing.setVisibleRequested(false);
+ opening.setVisibleRequested(true);
+
+ final int transit = transition.mType;
+ int flags = 0;
+
+ // Check basic both tasks participating
+ participants.add(closingTaskFragment);
+ participants.add(openingTaskFragment);
+ ArrayList<Transition.ChangeInfo> targets =
+ Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transit, info.getType());
+
+ assertFalse(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
+ }
+
+ @Test
+ public void testCloseTranslucentTaskFragment_withFinishingActivity() {
+ final Transition transition = createTestTransition(TRANSIT_CLOSE);
+ ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+ ArraySet<WindowContainer> participants = transition.mParticipants;
+
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment openingTaskFragment = createTaskFragmentWithActivity(task);
+ final TaskFragment closingTaskFragment = createTaskFragmentWithActivity(task);
+
+ final ActivityRecord opening = openingTaskFragment.getTopMostActivity();
+ opening.setOccludesParent(true);
+ opening.visibleIgnoringKeyguard = true;
+ final ActivityRecord closing = closingTaskFragment.getTopMostActivity();
+ closing.setOccludesParent(false);
+ closing.visibleIgnoringKeyguard = true;
+ closing.finishing = true;
+ // Start states.
+ changes.put(openingTaskFragment, new Transition.ChangeInfo(openingTaskFragment,
+ false /* vis */, true /* exChg */));
+ changes.put(closingTaskFragment, new Transition.ChangeInfo(closingTaskFragment,
+ true /* vis */, false /* exChg */));
+ changes.put(opening, new Transition.ChangeInfo(opening, false /* vis */, true /* exChg */));
+ changes.put(closing, new Transition.ChangeInfo(closing, true /* vis */, false /* exChg */));
+ fillChangeMap(changes, openingTaskFragment);
+ // End states.
+ closing.setVisibleRequested(false);
+ opening.setVisibleRequested(true);
+
+ final int transit = transition.mType;
+ int flags = 0;
+
+ // Check basic both tasks participating
+ participants.add(closingTaskFragment);
+ participants.add(openingTaskFragment);
+ ArrayList<Transition.ChangeInfo> targets =
+ Transition.calculateTargets(participants, changes);
+ TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
+ assertEquals(2, info.getChanges().size());
+ assertEquals(transit, info.getType());
+
+ assertTrue(info.getChanges().get(0).hasFlags(FLAG_TRANSLUCENT));
+ assertFalse(info.getChanges().get(1).hasFlags(FLAG_TRANSLUCENT));
}
@Test
diff --git a/telecomm/java/android/telecom/CallControl.java b/telecomm/java/android/telecom/CallControl.java
index f3c91f664dee..2135e276e591 100644
--- a/telecomm/java/android/telecom/CallControl.java
+++ b/telecomm/java/android/telecom/CallControl.java
@@ -197,10 +197,10 @@ public final class CallControl {
* of the requested operation.
*
* {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
- * rejected the incoming call.
+ * started the call streaming.
*
* {@link OutcomeReceiver#onError} will be called if Telecom has failed to
- * reject the incoming call. A {@link CallException} will be passed that
+ * start the call streaming. A {@link CallException} will be passed that
* details why the operation failed.
*/
public void startCallStreaming(@CallbackExecutor @NonNull Executor executor,
diff --git a/telecomm/java/android/telecom/CallStreamingService.java b/telecomm/java/android/telecom/CallStreamingService.java
index 7f1112830222..3f538a7f262d 100644
--- a/telecomm/java/android/telecom/CallStreamingService.java
+++ b/telecomm/java/android/telecom/CallStreamingService.java
@@ -19,6 +19,7 @@ package android.telecom;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
@@ -38,10 +39,22 @@ import java.lang.annotation.RetentionPolicy;
/**
* This service is implemented by an app that wishes to provide functionality for a general call
* streaming sender for voip calls.
- *
- * TODO: add doc of how to be the general streaming sender
- *
+ * <p>
+ * Below is an example manifest registration for a {@code CallStreamingService}.
+ * <pre>
+ * {@code
+ * <service android:name=".EgCallStreamingService"
+ * android:permission="android.permission.BIND_CALL_STREAMING_SERVICE" >
+ * ...
+ * <intent-filter>
+ * <action android:name="android.telecom.CallStreamingService" />
+ * </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ * @hide
*/
+@SystemApi
public abstract class CallStreamingService extends Service {
/**
* The {@link android.content.Intent} that must be declared as handled by the service.
@@ -122,6 +135,13 @@ public abstract class CallStreamingService extends Service {
/**
* Call streaming request reject reason used with
* {@link CallEventCallback#onCallStreamingFailed(int)} to indicate that telecom is rejecting a
+ * call streaming request due to unknown reason.
+ */
+ public static final int STREAMING_FAILED_UNKNOWN = 0;
+
+ /**
+ * Call streaming request reject reason used with
+ * {@link CallEventCallback#onCallStreamingFailed(int)} to indicate that telecom is rejecting a
* call streaming request because there's an ongoing streaming call on this device.
*/
public static final int STREAMING_FAILED_ALREADY_STREAMING = 1;
@@ -149,6 +169,7 @@ public abstract class CallStreamingService extends Service {
*/
@IntDef(prefix = {"STREAMING_FAILED"},
value = {
+ STREAMING_FAILED_UNKNOWN,
STREAMING_FAILED_ALREADY_STREAMING,
STREAMING_FAILED_NO_SENDER,
STREAMING_FAILED_SENDER_BINDING_ERROR
diff --git a/telecomm/java/android/telecom/StreamingCall.java b/telecomm/java/android/telecom/StreamingCall.java
index 4b27dd6f1e59..d4f43225139b 100644
--- a/telecomm/java/android/telecom/StreamingCall.java
+++ b/telecomm/java/android/telecom/StreamingCall.java
@@ -18,6 +18,7 @@ package android.telecom;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.content.ComponentName;
import android.net.Uri;
import android.os.Bundle;
@@ -30,7 +31,10 @@ import java.lang.annotation.RetentionPolicy;
/**
* Represents a voip call requested to stream to another device that the general streaming sender
* app should present to the receiver.
+ *
+ * @hide
*/
+@SystemApi
public final class StreamingCall implements Parcelable {
/**
* The state of a {@code StreamingCall} when newly created. General streaming sender should
@@ -50,9 +54,12 @@ public final class StreamingCall implements Parcelable {
*/
public static final int STATE_DISCONNECTED = 3;
+ /**
+ * @hide
+ */
private StreamingCall(@NonNull Parcel in) {
mComponentName = in.readParcelable(ComponentName.class.getClassLoader());
- mDisplayName = in.readString16NoHelper();
+ mDisplayName = in.readCharSequence();
mAddress = in.readParcelable(Uri.class.getClassLoader());
mExtras = in.readBundle();
mState = in.readInt();
@@ -79,7 +86,7 @@ public final class StreamingCall implements Parcelable {
@Override
public void writeToParcel(@androidx.annotation.NonNull Parcel dest, int flags) {
dest.writeParcelable(mComponentName, flags);
- dest.writeString16NoHelper(mDisplayName);
+ dest.writeCharSequence(mDisplayName);
dest.writeParcelable(mAddress, flags);
dest.writeBundle(mExtras);
dest.writeInt(mState);
@@ -98,14 +105,14 @@ public final class StreamingCall implements Parcelable {
public @interface StreamingCallState {}
private final ComponentName mComponentName;
- private final String mDisplayName;
+ private final CharSequence mDisplayName;
private final Uri mAddress;
private final Bundle mExtras;
@StreamingCallState
private int mState;
private StreamingCallAdapter mAdapter = null;
- public StreamingCall(@NonNull ComponentName componentName, @NonNull String displayName,
+ public StreamingCall(@NonNull ComponentName componentName, @NonNull CharSequence displayName,
@NonNull Uri address, @NonNull Bundle extras) {
mComponentName = componentName;
mDisplayName = displayName;
@@ -137,7 +144,7 @@ public final class StreamingCall implements Parcelable {
* {@code StreamingCall} to the receiver side.
*/
@NonNull
- public String getDisplayName() {
+ public CharSequence getDisplayName() {
return mDisplayName;
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 7404adb96e6c..d75e573a2e89 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -174,7 +174,7 @@ public class SubscriptionManager {
/**
* Key to the backup & restore data byte array in the Bundle that is returned by {@link
* #getAllSimSpecificSettingsForBackup()} or to be pass in to {@link
- * #restoreAllSimSpecificSettings()}.
+ * #restoreAllSimSpecificSettingsFromBackup(byte[])}.
*
* @hide
*/
@@ -4051,39 +4051,16 @@ public class SubscriptionManager {
}
/**
- * Called to attempt to restore the backed up sim-specific configs to device for specific sim.
- * This will try to restore the data that was stored internally when {@link
- * #restoreAllSimSpecificSettingsFromBackup(byte[] data)} was called during setup wizard.
- * End result is SimInfoDB is modified to match any backed up configs for the requested
- * inserted sim.
- *
- * <p>
- * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any SimInfoDB
- * entry is updated as the result of this method call.
- *
- * @param iccId of the sim that a restore is requested for.
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
- public void restoreSimSpecificSettingsForIccIdFromBackup(@NonNull String iccId) {
- mContext.getContentResolver().call(
- SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI,
- RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME,
- iccId, null);
- }
-
- /**
* Called during setup wizard restore flow to attempt to restore the backed up sim-specific
- * configs to device for all existing SIMs in SimInfoDB. Internally, it will store the backup
- * data in an internal file. This file will persist on device for device's lifetime and will be
- * used later on when a SIM is inserted to restore that specific SIM's settings by calling
- * {@link #restoreSimSpecificSettingsForIccIdFromBackup(String iccId)}. End result is
- * SimInfoDB is modified to match any backed up configs for the appropriate inserted SIMs.
+ * configs to device for all existing SIMs in the subscription database {@link SimInfo}.
+ * Internally, it will store the backup data in an internal file. This file will persist on
+ * device for device's lifetime and will be used later on when a SIM is inserted to restore that
+ * specific SIM's settings. End result is subscription database is modified to match any backed
+ * up configs for the appropriate inserted SIMs.
*
* <p>
- * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any SimInfoDB
- * entry is updated as the result of this method call.
+ * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any
+ * {@link SimInfo} entry is updated as the result of this method call.
*
* @param data with the sim specific configs to be backed up.
*
@@ -4092,12 +4069,18 @@ public class SubscriptionManager {
@SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void restoreAllSimSpecificSettingsFromBackup(@NonNull byte[] data) {
- Bundle bundle = new Bundle();
- bundle.putByteArray(KEY_SIM_SPECIFIC_SETTINGS_DATA, data);
- mContext.getContentResolver().call(
- SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI,
- RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME,
- null, bundle);
+ try {
+ ISub iSub = TelephonyManager.getSubscriptionService();
+ if (iSub != null) {
+ iSub.restoreAllSimSpecificSettingsFromBackup(data);
+ } else {
+ throw new IllegalStateException("subscription service unavailable.");
+ }
+ } catch (RemoteException ex) {
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
+ }
}
/**
diff --git a/telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl b/telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl
index 6fb09799dacf..0ce9c98bd346 100644
--- a/telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl
+++ b/telephony/java/android/telephony/satellite/ISatelliteStateListener.aidl
@@ -17,13 +17,17 @@
package android.telephony.satellite;
import android.telephony.satellite.PointingInfo;
+import android.telephony.satellite.SatelliteDatagram;
/**
* Interface for satellite state listener.
* @hide
*/
oneway interface ISatelliteStateListener {
- void onSatelliteProvisionStateChanged(in int[] features, in boolean provisioned);
+ void onSatelliteProvisionStateChanged(in boolean provisioned);
void onSatellitePositionUpdate(in PointingInfo pointingInfo);
void onMessageTransferStateUpdate(in int state);
+ void onSatelliteModemStateChange(in int state);
+ void onPendingMessageCount(in int count);
+ void onSatelliteDatagrams(in SatelliteDatagram[] datagrams);
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteCallback.java b/telephony/java/android/telephony/satellite/SatelliteCallback.java
index 1b82d062047a..5250562a82cd 100644
--- a/telephony/java/android/telephony/satellite/SatelliteCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteCallback.java
@@ -18,9 +18,9 @@ package android.telephony.satellite;
import android.annotation.NonNull;
import android.os.Binder;
-import android.telephony.satellite.stub.SatelliteImplBase;
import java.lang.ref.WeakReference;
+import java.util.List;
import java.util.concurrent.Executor;
/**
@@ -63,12 +63,10 @@ public class SatelliteCallback {
/**
* Called when satellite provision state changes.
*
- * @param features The list of provisioned features.
* @param provisioned The new provision state. {@code true} means satellite is provisioned
* {@code false} means satellite is not provisioned.
*/
- void onSatelliteProvisionStateChanged(
- @SatelliteImplBase.Feature int[] features, boolean provisioned);
+ void onSatelliteProvisionStateChanged(boolean provisioned);
}
/**
@@ -91,6 +89,34 @@ public class SatelliteCallback {
@SatelliteManager.SatelliteMessageTransferState int state);
}
+ /**
+ * Interface for satellite state change listener.
+ */
+ public interface SatelliteStateListener {
+ /**
+ * Called when satellite state changes.
+ * @param state - The new satellite state.
+ */
+ void onSatelliteModemStateChange(@SatelliteManager.SatelliteModemState int state);
+
+ /**
+ * Called when there are pending messages to be received from satellite.
+ * @param count - pending message count.
+ */
+ void onPendingMessageCount(int count);
+ }
+
+ /**
+ * Interface for satellite datagram listener.
+ */
+ public interface SatelliteDatagramListener {
+ /**
+ * Called when there are incoming datagrams to be received.
+ * @param datagrams - datagrams to be received over satellite.
+ */
+ void onSatelliteDatagrams(SatelliteDatagram[] datagrams);
+ }
+
private static class ISatelliteStateListenerStub extends ISatelliteStateListener.Stub {
private WeakReference<SatelliteCallback> mSatelliteCallbackWeakRef;
private Executor mExecutor;
@@ -100,14 +126,13 @@ public class SatelliteCallback {
mExecutor = executor;
}
- public void onSatelliteProvisionStateChanged(
- @SatelliteImplBase.Feature int[] features, boolean provisioned) {
+ public void onSatelliteProvisionStateChanged(boolean provisioned) {
SatelliteProvisionStateListener listener =
(SatelliteProvisionStateListener) mSatelliteCallbackWeakRef.get();
if (listener == null) return;
Binder.withCleanCallingIdentity(() -> mExecutor.execute(
- () -> listener.onSatelliteProvisionStateChanged(features, provisioned)));
+ () -> listener.onSatelliteProvisionStateChanged(provisioned)));
}
public void onSatellitePositionUpdate(@NonNull PointingInfo pointingInfo) {
@@ -128,5 +153,36 @@ public class SatelliteCallback {
Binder.withCleanCallingIdentity(() -> mExecutor.execute(
() -> listener.onMessageTransferStateUpdate(state)));
}
+
+
+ @Override
+ public void onSatelliteModemStateChange(@SatelliteManager.SatelliteModemState int state) {
+ SatelliteStateListener listener =
+ (SatelliteStateListener) mSatelliteCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+ () -> listener.onSatelliteModemStateChange(state)));
+ }
+
+ @Override
+ public void onPendingMessageCount(int count) {
+ SatelliteStateListener listener =
+ (SatelliteStateListener) mSatelliteCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+ () -> listener.onPendingMessageCount(count)));
+ }
+
+ @Override
+ public void onSatelliteDatagrams(SatelliteDatagram[] datagrams) {
+ SatelliteDatagramListener listener =
+ (SatelliteDatagramListener) mSatelliteCallbackWeakRef.get();
+ if (listener == null) return;
+
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+ () -> listener.onSatelliteDatagrams(datagrams)));
+ }
}
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagram.aidl b/telephony/java/android/telephony/satellite/SatelliteDatagram.aidl
new file mode 100644
index 000000000000..993aacf80bd1
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/SatelliteDatagram.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.satellite;
+
+parcelable SatelliteDatagram;
diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagram.java b/telephony/java/android/telephony/satellite/SatelliteDatagram.java
new file mode 100644
index 000000000000..cc5a9f45de83
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/SatelliteDatagram.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.satellite;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public final class SatelliteDatagram implements Parcelable {
+ /**
+ * Datagram to be sent or received over satellite.
+ */
+ private byte[] mData;
+
+ /**
+ * @hide
+ */
+ public SatelliteDatagram(@NonNull byte[] data) {
+ mData = data;
+ }
+
+ private SatelliteDatagram(Parcel in) {
+ readFromParcel(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeByteArray(mData);
+ }
+
+ public static final @android.annotation.NonNull Creator<SatelliteDatagram> CREATOR =
+ new Creator<SatelliteDatagram>() {
+ @Override
+ public SatelliteDatagram createFromParcel(Parcel in) {
+ return new SatelliteDatagram(in);
+ }
+
+ @Override
+ public SatelliteDatagram[] newArray(int size) {
+ return new SatelliteDatagram[size];
+ }
+ };
+
+ @Nullable
+ public byte[] getSatelliteDatagram() {
+ return mData;
+ }
+
+ private void readFromParcel(Parcel in) {
+ mData = in.createByteArray();
+ }
+}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index a818b63c372a..100799e67c36 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -26,15 +26,15 @@ import android.annotation.RequiresPermission;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ICancellationSignal;
+import android.os.OutcomeReceiver;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyFrameworkInitializer;
-import android.telephony.satellite.stub.SatelliteImplBase;
-import com.android.internal.telephony.IBooleanConsumer;
-import com.android.internal.telephony.IIntArrayConsumer;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.ITelephony;
import com.android.telephony.Rlog;
@@ -72,16 +72,6 @@ public class SatelliteManager {
}
/**
- * Create a new SatelliteManager associated with the given subscription ID.
- *
- * @param subId The subscription ID to create the SatelliteManager with.
- * @return A SatelliteManager that uses the given subscription ID for all calls.
- */
- @NonNull public SatelliteManager createForSubscriptionId(int subId) {
- return new SatelliteManager(mContext, subId);
- }
-
- /**
* Create an instance of the SatelliteManager associated with a particular subscription.
*
* @param context The context the SatelliteManager belongs to.
@@ -93,6 +83,67 @@ public class SatelliteManager {
}
/**
+ * Exception from the satellite service containing the {@link SatelliteError} error code.
+ */
+ public static class SatelliteException extends Exception {
+ @SatelliteError private final int mErrorCode;
+
+ /**
+ * Create a SatelliteException with a given error code.
+ *
+ * @param errorCode The {@link SatelliteError}.
+ */
+ public SatelliteException(@SatelliteError int errorCode) {
+ mErrorCode = errorCode;
+ }
+
+ /**
+ * Get the error code returned from the satellite service.
+ *
+ * @return The {@link SatelliteError}.
+ */
+ @SatelliteError public int getErrorCode() {
+ return mErrorCode;
+ }
+ }
+
+ /**
+ * Bundle key to get the response from
+ * {@link #requestIsSatelliteEnabled(Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_SATELLITE_ENABLED = "satellite_enabled";
+
+ /**
+ * Bundle key to get the response from
+ * {@link #requestIsSatelliteSupported(Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_SATELLITE_SUPPORTED = "satellite_supported";
+
+ /**
+ * Bundle key to get the response from
+ * {@link #requestSatelliteCapabilities(Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_SATELLITE_CAPABILITIES = "satellite_capabilities";
+
+ /**
+ * Bundle key to get the response from
+ * {@link #requestMaxCharactersPerSatelliteTextMessage(Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_MAX_CHARACTERS_PER_SATELLITE_TEXT =
+ "max_characters_per_satellite_text";
+
+ /**
+ * Bundle key to get the response from
+ * {@link #requestIsSatelliteProvisioned(Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_SATELLITE_PROVISIONED = "satellite_provisioned";
+
+ /**
* The request was successfully processed.
*/
public static final int SATELLITE_ERROR_NONE = 0;
@@ -133,8 +184,8 @@ public class SatelliteManager {
*/
public static final int SATELLITE_INVALID_ARGUMENTS = 8;
/**
- * Telephony framework failed to send a request to the vendor service or the satellite
- * modem due to internal error.
+ * Telephony framework failed to send a request or receive a response from the vendor service
+ * or satellite modem due to internal error.
*/
public static final int SATELLITE_REQUEST_FAILED = 9;
/**
@@ -211,158 +262,201 @@ public class SatelliteManager {
public @interface SatelliteError {}
/**
- * Power on or off the satellite modem.
+ * Enable or disable the satellite modem. If the satellite modem is enabled, this will also
+ * disable the cellular modem, and if the satellite modem is disabled, this will also re-enable
+ * the cellular modem.
*
- * @param powerOn {@code true} to power on the satellite modem and {@code false} to power off.
+ * @param enable {@code true} to enable the satellite modem and {@code false} to disable.
+ * @param executor The executor on which the error code listener will be called.
+ * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
*
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
- *
- * @return The result of the operation.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
- @SatelliteError public int setSatellitePower(boolean powerOn) {
+ public void setSatelliteEnabled(boolean enable, @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<Integer> errorCodeListener) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(errorCodeListener);
+
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.setSatellitePower(mSubId, powerOn);
+ IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> errorCodeListener.accept(result)));
+ }
+ };
+ telephony.setSatelliteEnabled(mSubId, enable, errorCallback);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- Rlog.e(TAG, "setSatellitePower RemoteException", ex);
+ Rlog.e(TAG, "setSatelliteEnabled RemoteException: ", ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_REQUEST_FAILED;
}
/**
- * Check whether the satellite modem is powered on.
+ * Request to get whether the satellite modem is enabled.
*
- * @param executor The executor on which the result listener will be called.
- * @param resultListener Listener with the result if the operation is successful.
- * If this method returns {@link #SATELLITE_ERROR_NONE}, the result
- * listener will return {@code true} if the satellite modem is powered on
- * and {@code false} otherwise.
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback object to which the result will be delivered.
+ * If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+ * will return a {@code boolean} with value {@code true} if the satellite modem
+ * is powered on and {@code false} otherwise.
+ * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+ * will return a {@link SatelliteException} with the {@link SatelliteError}.
*
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
- *
- * @return The result of the operation.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
- @SatelliteError public int isSatellitePowerOn(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<Boolean> resultListener) {
+ public void requestIsSatelliteEnabled(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
Objects.requireNonNull(executor);
- Objects.requireNonNull(resultListener);
+ Objects.requireNonNull(callback);
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- IBooleanConsumer internalCallback = new IBooleanConsumer.Stub() {
+ ResultReceiver receiver = new ResultReceiver(null) {
@Override
- public void accept(boolean result) {
- executor.execute(() -> Binder.withCleanCallingIdentity(
- () -> resultListener.accept(result)));
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_ERROR_NONE) {
+ if (resultData.containsKey(KEY_SATELLITE_ENABLED)) {
+ boolean isSatelliteEnabled =
+ resultData.getBoolean(KEY_SATELLITE_ENABLED);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(isSatelliteEnabled)));
+ } else {
+ loge("KEY_SATELLITE_ENABLED does not exist.");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(
+ new SatelliteException(SATELLITE_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
}
};
-
- return telephony.isSatellitePowerOn(mSubId, internalCallback);
+ telephony.requestIsSatelliteEnabled(mSubId, receiver);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("isSatellitePowerOn() RemoteException:" + ex);
+ loge("requestIsSatelliteEnabled() RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_REQUEST_FAILED;
}
/**
- * Check whether the satellite service is supported on the device.
+ * Request to get whether the satellite service is supported on the device.
*
- * @param executor The executor on which the result listener will be called.
- * @param resultListener Listener with the result if the operation is successful.
- * If this method returns {@link #SATELLITE_ERROR_NONE}, the result
- * listener will return {@code true} if the satellite service is supported
- * and {@code false} otherwise.
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback object to which the result will be delivered.
+ * If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+ * will return a {@code boolean} with value {@code true} if the satellite
+ * service is supported on the device and {@code false} otherwise.
+ * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+ * will return a {@link SatelliteException} with the {@link SatelliteError}.
*
- * @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
- *
- * @return The result of the operation.
*/
- @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
- @SatelliteError public int isSatelliteSupported(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<Boolean> resultListener) {
+ public void requestIsSatelliteSupported(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
Objects.requireNonNull(executor);
- Objects.requireNonNull(resultListener);
+ Objects.requireNonNull(callback);
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- IBooleanConsumer internalCallback = new IBooleanConsumer.Stub() {
+ ResultReceiver receiver = new ResultReceiver(null) {
@Override
- public void accept(boolean result) {
- executor.execute(() -> Binder.withCleanCallingIdentity(
- () -> resultListener.accept(result)));
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_ERROR_NONE) {
+ if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) {
+ boolean isSatelliteSupported =
+ resultData.getBoolean(KEY_SATELLITE_SUPPORTED);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(isSatelliteSupported)));
+ } else {
+ loge("KEY_SATELLITE_SUPPORTED does not exist.");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(
+ new SatelliteException(SATELLITE_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
}
};
-
- return telephony.isSatelliteSupported(mSubId, internalCallback);
+ telephony.requestIsSatelliteSupported(mSubId, receiver);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("isSatelliteSupported() RemoteException:" + ex);
+ loge("requestIsSatelliteSupported() RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_REQUEST_FAILED;
}
/**
- * Get the {@link SatelliteCapabilities} with all capabilities of the satellite service.
+ * Request to get the {@link SatelliteCapabilities} of the satellite service.
*
- * @param executor The executor on which the result listener will be called.
- * @param resultListener Listener with the result if the operation is successful.
- * If this method returns {@link #SATELLITE_ERROR_NONE}, the result
- * listener will return the current {@link SatelliteCapabilities}.
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback object to which the result will be delivered.
+ * If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+ * will return the {@link SatelliteCapabilities} of the satellite service.
+ * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+ * will return a {@link SatelliteException} with the {@link SatelliteError}.
*
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
- *
- * @return The result of the operation.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
- @SatelliteError public int getSatelliteCapabilities(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<SatelliteCapabilities> resultListener) {
+ public void requestSatelliteCapabilities(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback) {
Objects.requireNonNull(executor);
- Objects.requireNonNull(resultListener);
+ Objects.requireNonNull(callback);
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- ISatelliteCapabilitiesConsumer internalCallback =
- new ISatelliteCapabilitiesConsumer.Stub() {
+ ResultReceiver receiver = new ResultReceiver(null) {
@Override
- public void accept(SatelliteCapabilities result) {
- executor.execute(() -> Binder.withCleanCallingIdentity(
- () -> resultListener.accept(result)));
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_ERROR_NONE) {
+ if (resultData.containsKey(KEY_SATELLITE_CAPABILITIES)) {
+ SatelliteCapabilities capabilities =
+ resultData.getParcelable(KEY_SATELLITE_CAPABILITIES,
+ SatelliteCapabilities.class);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(capabilities)));
+ } else {
+ loge("KEY_SATELLITE_CAPABILITIES does not exist.");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(
+ new SatelliteException(SATELLITE_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
}
};
-
- return telephony.getSatelliteCapabilities(mSubId, internalCallback);
+ telephony.requestSatelliteCapabilities(mSubId, receiver);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("getSatelliteCapabilities() RemoteException:" + ex);
+ loge("requestSatelliteCapabilities() RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_REQUEST_FAILED;
}
/**
@@ -396,6 +490,44 @@ public class SatelliteManager {
})
public @interface SatelliteMessageTransferState {}
+ /* Satellite modem is in idle state. */
+ public static final int SATELLITE_MODEM_STATE_IDLE = 0;
+
+ /* Satellite modem is listening for incoming messages. */
+ public static final int SATELLITE_MODEM_STATE_LISTENING = 1;
+
+ /* Satellite modem is sending and/or receiving messages. */
+ public static final int SATELLITE_MODEM_STATE_MESSAGE_TRANSFERRING = 2;
+
+ /* Satellite modem is powered off */
+ public static final int SATELLITE_MODEM_STATE_OFF = 3;
+
+ /** @hide */
+ @IntDef(prefix = {"SATELLITE_STATE_"},
+ value = {
+ SATELLITE_MODEM_STATE_IDLE,
+ SATELLITE_MODEM_STATE_LISTENING,
+ SATELLITE_MODEM_STATE_MESSAGE_TRANSFERRING,
+ SATELLITE_MODEM_STATE_OFF
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SatelliteModemState {}
+
+ /** SOS SMS */
+ public static final int DATAGRAM_TYPE_SOS_SMS = 0;
+
+ /** Location sharing message */
+ public static final int DATAGRAM_TYPE_LOCATION_SHARING = 3;
+
+ @IntDef(
+ prefix = "DATAGRAM_TYPE_",
+ value = {
+ DATAGRAM_TYPE_SOS_SMS,
+ DATAGRAM_TYPE_LOCATION_SHARING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DatagramType {}
+
/**
* Start receiving satellite position updates.
* This can be called by the pointing UI when the user starts pointing to the satellite.
@@ -403,28 +535,35 @@ public class SatelliteManager {
* Satellite position updates are started only on {@link #SATELLITE_ERROR_NONE}.
* All other results indicate that this operation failed.
*
- * @param executor The executor on which the callback will be called.
+ * @param executor The executor on which the callback and error code listener will be called.
+ * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
* @param callback The callback to notify of changes in satellite position. This
* SatelliteCallback should implement the interface
* {@link SatelliteCallback.SatellitePositionUpdateListener}.
*
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
- *
- * @return The result of the operation.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
- @SatelliteError
- public int startSatellitePositionUpdates(
- @NonNull Executor executor, @NonNull SatelliteCallback callback) {
+ public void startSatellitePositionUpdates(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<Integer> errorCodeListener, @NonNull SatelliteCallback callback) {
Objects.requireNonNull(executor);
+ Objects.requireNonNull(errorCodeListener);
Objects.requireNonNull(callback);
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
callback.init(executor);
- return telephony.startSatellitePositionUpdates(mSubId, callback.getCallbackStub());
+ IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> errorCodeListener.accept(result)));
+ }
+ };
+ telephony.startSatellitePositionUpdates(mSubId, errorCallback,
+ callback.getCallbackStub());
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -432,7 +571,6 @@ public class SatelliteManager {
loge("startSatellitePositionUpdates RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_REQUEST_FAILED;
}
/**
@@ -441,25 +579,35 @@ public class SatelliteManager {
* Satellite position updates are stopped only on {@link #SATELLITE_ERROR_NONE}.
* All other results indicate that this operation failed.
*
- * @param callback The callback that was passed in {@link
- * #startSatellitePositionUpdates(Executor, SatelliteCallback)}.
+ * @param callback The callback that was passed to
+ * {@link #startSatellitePositionUpdates(Executor, Consumer, SatelliteCallback)}.
+ * @param executor The executor on which the error code listener will be called.
+ * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
*
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalArgumentException if the callback is invalid.
* @throws IllegalStateException if the Telephony process is not currently available.
- *
- * @return The result of the operation.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
- @SatelliteError
- public int stopSatellitePositionUpdates(
- @NonNull SatelliteCallback callback) {
+ public void stopSatellitePositionUpdates(@NonNull SatelliteCallback callback,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<Integer> errorCodeListener) {
Objects.requireNonNull(callback);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(errorCodeListener);
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.stopSatellitePositionUpdates(mSubId, callback.getCallbackStub());
+ IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> errorCodeListener.accept(result)));
+ }
+ };
+ telephony.stopSatellitePositionUpdates(mSubId, errorCallback,
+ callback.getCallbackStub());
// TODO: Notify SmsHandler that pointing UI stopped
} else {
throw new IllegalStateException("telephony service is null.");
@@ -468,89 +616,98 @@ public class SatelliteManager {
loge("stopSatellitePositionUpdates RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_REQUEST_FAILED;
}
/**
- * Get maximum number of characters per text message on satellite.
- * @param executor - The executor on which the result listener will be called.
- * @param resultListener - Listener that will be called when the operation is successful.
- * If this method returns {@link #SATELLITE_ERROR_NONE}, listener
- * will be called with maximum characters limit.
+ * Request to get the maximum number of characters per text message on satellite.
+ *
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback object to which the result will be delivered.
+ * If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+ * will return the maximum number of characters per text message on satellite.
+ * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
*
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
- *
- * @return The result of the operation.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
- @SatelliteError
- public int getMaxCharactersPerSatelliteTextMessage(@NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<Integer> resultListener) {
+ public void requestMaxCharactersPerSatelliteTextMessage(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<Integer, SatelliteException> callback) {
Objects.requireNonNull(executor);
- Objects.requireNonNull(resultListener);
+ Objects.requireNonNull(callback);
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
+ ResultReceiver receiver = new ResultReceiver(null) {
@Override
- public void accept(int result) {
- executor.execute(() -> Binder.withCleanCallingIdentity(
- () -> resultListener.accept(result)));
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_ERROR_NONE) {
+ if (resultData.containsKey(KEY_MAX_CHARACTERS_PER_SATELLITE_TEXT)) {
+ int maxCharacters =
+ resultData.getInt(KEY_MAX_CHARACTERS_PER_SATELLITE_TEXT);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(maxCharacters)));
+ } else {
+ loge("KEY_MAX_CHARACTERS_PER_SATELLITE_TEXT does not exist.");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(
+ new SatelliteException(SATELLITE_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
}
};
-
- return telephony.getMaxCharactersPerSatelliteTextMessage(mSubId, internalCallback);
+ telephony.requestMaxCharactersPerSatelliteTextMessage(mSubId, receiver);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("getMaxCharactersPerSatelliteTextMessage() RemoteException:" + ex);
+ loge("requestMaxCharactersPerSatelliteTextMessage() RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_REQUEST_FAILED;
}
/**
- * Register the subscription with a satellite provider. This is needed if the provider allows
- * dynamic registration.
+ * Provision the device with a satellite provider.
+ * This is needed if the provider allows dynamic registration.
*
- * @param features List of features to be provisioned.
- * @param executor The optional executor to run callbacks on.
- * @param callback The optional callback to get the error code of the request.
+ * @param token The token to be used as a unique identifier for provisioning with satellite
+ * gateway.
* @param cancellationSignal The optional signal used by the caller to cancel the provision
* request. Even when the cancellation is signaled, Telephony will
* still trigger the callback to return the result of this request.
+ * @param executor The executor on which the error code listener will be called.
+ * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
+ *
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
- public void provisionSatelliteService(
- @NonNull @SatelliteImplBase.Feature int[] features,
- @Nullable @CallbackExecutor Executor executor,
- @SatelliteError @Nullable Consumer<Integer> callback,
- @Nullable CancellationSignal cancellationSignal) {
- Objects.requireNonNull(features);
+ public void provisionSatelliteService(@NonNull String token,
+ @Nullable CancellationSignal cancellationSignal,
+ @NonNull @CallbackExecutor Executor executor,
+ @SatelliteError @NonNull Consumer<Integer> errorCodeListener) {
+ Objects.requireNonNull(token);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(errorCodeListener);
ICancellationSignal cancelRemote = null;
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- IIntegerConsumer callbackStub = new IIntegerConsumer.Stub() {
+ IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
@Override
public void accept(int result) {
- if (executor == null || callback == null) {
- logd("provisionSatelliteService: executor and/or callback is null");
- return;
- }
- Binder.withCleanCallingIdentity(() -> {
- executor.execute(() -> callback.accept(result));
- });
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> errorCodeListener.accept(result)));
}
};
- cancelRemote = telephony.provisionSatelliteService(mSubId, features, callbackStub);
+ cancelRemote = telephony.provisionSatelliteService(mSubId, token, errorCallback);
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -564,29 +721,80 @@ public class SatelliteManager {
}
/**
+ * Deprovision the device with the satellite provider.
+ * This is needed if the provider allows dynamic registration. Once deprovisioned,
+ * {@link SatelliteCallback.SatelliteProvisionStateListener#onSatelliteProvisionStateChanged}
+ * should report as deprovisioned.
+ * For provisioning satellite service, refer to
+ * {@link #provisionSatelliteService(String, CancellationSignal, Executor, Consumer)}.
+ *
+ * @param token The token of the device/subscription to be deprovisioned.
+ * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
+ *
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ public void deprovisionSatelliteService(@NonNull String token,
+ @NonNull @CallbackExecutor Executor executor,
+ @SatelliteError @NonNull Consumer<Integer> errorCodeListener) {
+ Objects.requireNonNull(token);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(errorCodeListener);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> errorCodeListener.accept(result)));
+ }
+ };
+ telephony.deprovisionSatelliteService(mSubId, token, errorCallback);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("deprovisionSatelliteService RemoteException=" + ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Register for the satellite provision state change.
*
- * @param executor - The executor on which the callback will be called.
+ * @param executor The executor on which the callback and error code listener will be called.
+ * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
* @param callback The callback to handle the satellite provision state changed event. This
* SatelliteCallback should implement the interface
* {@link SatelliteCallback.SatelliteProvisionStateListener}.
- * @return The error code of the request.
+ *
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
- @SatelliteError
- public int registerForSatelliteProvisionStateChanged(
- @NonNull Executor executor, @NonNull SatelliteCallback callback) {
+ public void registerForSatelliteProvisionStateChanged(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<Integer> errorCodeListener, @NonNull SatelliteCallback callback) {
Objects.requireNonNull(executor);
+ Objects.requireNonNull(errorCodeListener);
Objects.requireNonNull(callback);
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
callback.init(executor);
- return telephony.registerForSatelliteProvisionStateChanged(
- mSubId, callback.getCallbackStub());
+ IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> errorCodeListener.accept(result)));
+ }
+ };
+ telephony.registerForSatelliteProvisionStateChanged(
+ mSubId, errorCallback, callback.getCallbackStub());
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -594,80 +802,311 @@ public class SatelliteManager {
loge("registerForSatelliteProvisionStateChanged RemoteException: " + ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_REQUEST_FAILED;
}
/**
* Unregister for the satellite provision state change.
*
* @param callback The callback that was passed to
- * {@link #registerForSatelliteProvisionStateChanged(Executor, SatelliteCallback)}
+ * {@link #registerForSatelliteProvisionStateChanged(Executor, Consumer, SatelliteCallback)}.
+ * @param executor The executor on which the error code listener will be called.
+ * @param errorCodeListener Listener for the {@link SatelliteError} result of the operation.
+ *
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ public void unregisterForSatelliteProvisionStateChanged(@NonNull SatelliteCallback callback,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<Integer> errorCodeListener) {
+ Objects.requireNonNull(callback);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(errorCodeListener);
+
+ if (callback.getCallbackStub() == null) {
+ loge("unregisterForSatelliteProvisionStateChanged: callbackStub is null");
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> errorCodeListener.accept(SATELLITE_INVALID_ARGUMENTS)));
+ return;
+ }
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
+ @Override
+ public void accept(int result) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> errorCodeListener.accept(result)));
+ }
+ };
+ telephony.unregisterForSatelliteProvisionStateChanged(mSubId, errorCallback,
+ callback.getCallbackStub());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("unregisterForSatelliteProvisionStateChanged RemoteException: " + ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Request to get whether this device is provisioned with a satellite provider.
+ *
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback object to which the result will be delivered.
+ * If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+ * will return a {@code boolean} with value {@code true} if the device is
+ * provisioned with a satellite provider and {@code false} otherwise.
+ * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+ * will return a {@link SatelliteException} with the {@link SatelliteError}.
+ *
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ public void requestIsSatelliteProvisioned(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ ResultReceiver receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_ERROR_NONE) {
+ if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) {
+ boolean isSatelliteProvisioned =
+ resultData.getBoolean(KEY_SATELLITE_PROVISIONED);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(isSatelliteProvisioned)));
+ } else {
+ loge("KEY_SATELLITE_PROVISIONED does not exist.");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(
+ new SatelliteException(SATELLITE_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
+ }
+ };
+ telephony.requestIsSatelliteProvisioned(mSubId, receiver);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("requestIsSatelliteProvisioned() RemoteException: " + ex);
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Register for listening to satellite modem state changes.
+ *
+ * @param executor - The executor on which the callback will be called.
+ * @param callback - The callback to handle the satellite state change event. This
+ * SatelliteCallback should implement the interface
+ * {@link SatelliteCallback.SatelliteStateListener}.
+ *
* @return The error code of the request.
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@SatelliteError
- public int unregisterForSatelliteProvisionStateChanged(@NonNull SatelliteCallback callback) {
+ public int registerForSatelliteModemStateChange(@NonNull @CallbackExecutor Executor executor,
+ @NonNull SatelliteCallback callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ callback.init(executor);
+ return telephony.registerForSatelliteModemStateChange(mSubId,
+ callback.getCallbackStub());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("registerForSatelliteModemStateChange() RemoteException:" + ex);
+ ex.rethrowFromSystemServer();
+ }
+ return SATELLITE_REQUEST_FAILED;
+ }
+
+ /**
+ * Unregister to stop listening to satellite modem state changes.
+ *
+ * @param callback - The callback that was passed to
+ * {@link #registerForSatelliteModemStateChange(Executor, SatelliteCallback)}
+ *
+ * @return The error code of the request.
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ @SatelliteError
+ public int unregisterForSatelliteModemStateChange(@NonNull SatelliteCallback callback) {
Objects.requireNonNull(callback);
if (callback.getCallbackStub() == null) {
- loge("unregisterForSatelliteProvisionStateChanged: callbackStub is null");
+ loge("unregisterForSatelliteModemStateChange: callbackStub is null");
return SATELLITE_INVALID_ARGUMENTS;
}
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.unregisterForSatelliteProvisionStateChanged(
- mSubId, callback.getCallbackStub());
+ return telephony.unregisterForSatelliteModemStateChange(mSubId,
+ callback.getCallbackStub());
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("unregisterForSatelliteProvisionStateChanged RemoteException: " + ex);
+ loge("unregisterForSatelliteModemStateChange() RemoteException:" + ex);
ex.rethrowFromSystemServer();
}
return SATELLITE_REQUEST_FAILED;
}
/**
- * Get the list of provisioned satellite features.
+ * Register to receive incoming datagrams over satellite.
+ *
+ * @param datagramType - type of datagram
+ * @param executor - The executor on which the callback will be called.
+ * @param callback - The callback to handle incoming datagrams over satellite. This
+ * SatelliteCallback should implement the interface
+ * {@link SatelliteCallback.SatelliteDatagramListener}.
*
- * @param executor The executor to run callbacks on.
- * @param resultListener The callback to get the list of provisioned features when the request
- * returns success result.
* @return The error code of the request.
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@SatelliteError
- public int getProvisionedSatelliteFeatures(
- @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<int[]> resultListener) {
- Objects.requireNonNull(resultListener);
+ public int registerForSatelliteDatagram(@DatagramType int datagramType,
+ @NonNull @CallbackExecutor Executor executor, @NonNull SatelliteCallback callback) {
Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ callback.init(executor);
+ return telephony.registerForSatelliteDatagram(mSubId, datagramType,
+ callback.getCallbackStub());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("registerForSatelliteDatagram() RemoteException:" + ex);
+ ex.rethrowFromSystemServer();
+ }
+ return SATELLITE_REQUEST_FAILED;
+ }
+
+ /**
+ * Unregister to stop receiving incoming datagrams over satellite.
+ *
+ * @param callback - The callback that was passed to
+ * {@link #registerForSatelliteDatagram(int, Executor, SatelliteCallback)}
+ *
+ * @return The error code of the request.
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ @SatelliteError
+ public int unregisterForSatelliteDatagram(@NonNull SatelliteCallback callback) {
+ Objects.requireNonNull(callback);
+
+ if (callback.getCallbackStub() == null) {
+ loge("unregisterForSatelliteDatagram: callbackStub is null");
+ return SATELLITE_INVALID_ARGUMENTS;
+ }
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- IIntArrayConsumer callbackStub = new IIntArrayConsumer.Stub() {
+ return telephony.unregisterForSatelliteDatagram(mSubId,
+ callback.getCallbackStub());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("unregisterForSatelliteDatagram() RemoteException:" + ex);
+ ex.rethrowFromSystemServer();
+ }
+ return SATELLITE_REQUEST_FAILED;
+ }
+
+ /**
+ * Poll pending satellite datagrams over satellite.
+ *
+ * @return The result of the operation.
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ @SatelliteError
+ public int pollPendingSatelliteDatagrams() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.pollPendingSatelliteDatagrams(mSubId);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ loge("pollPendingSatelliteDatagrams() RemoteException:" + ex);
+ ex.rethrowFromSystemServer();
+ }
+ return SATELLITE_REQUEST_FAILED;
+ }
+
+ /**
+ * Send datagram over satellite.
+ * @param datagramType - type of datagram
+ * @param datagram - datagram to send over satellite
+ * @param executor - The executor on which the result listener will be called.
+ * @param resultListener - Listener that will be called with the result of the operation.
+ *
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ public void sendSatelliteDatagram(@DatagramType int datagramType,
+ @NonNull SatelliteDatagram datagram, @NonNull @CallbackExecutor Executor executor,
+ @SatelliteError @NonNull Consumer<Integer> resultListener) {
+ Objects.requireNonNull(datagram);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(resultListener);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
@Override
- public void accept(int[] result) {
- Binder.withCleanCallingIdentity(() -> {
- executor.execute(() -> resultListener.accept(result));
- });
+ public void accept(int result) {
+ executor.execute(() -> Binder.withCleanCallingIdentity(
+ () -> resultListener.accept(result)));
}
};
- return telephony.getProvisionedSatelliteFeatures(mSubId, callbackStub);
+ telephony.sendSatelliteDatagram(mSubId, datagramType, datagram,
+ internalCallback);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("getProvisionedSatelliteFeatures() RemoteException:" + ex);
+ loge("sendSatelliteDatagram() RemoteException:" + ex);
ex.rethrowFromSystemServer();
}
- return SATELLITE_REQUEST_FAILED;
}
private static ITelephony getITelephony() {
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index defa046da503..af4edc443151 100644
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -363,4 +363,20 @@ interface ISub {
*/
//TODO: Removed before U AOSP public release.
boolean isSubscriptionManagerServiceEnabled();
+
+ /**
+ * Called during setup wizard restore flow to attempt to restore the backed up sim-specific
+ * configs to device for all existing SIMs in the subscription database
+ * {@link Telephony.SimInfo}. Internally, it will store the backup data in an internal file.
+ * This file will persist on device for device's lifetime and will be used later on when a SIM
+ * is inserted to restore that specific SIM's settings. End result is subscription database is
+ * modified to match any backed up configs for the appropriate inserted SIMs.
+ *
+ * <p>
+ * The {@link Uri} {@link #SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is notified if any
+ * {@link Telephony.SimInfo} entry is updated as the result of this method call.
+ *
+ * @param data with the sim specific configs to be backed up.
+ */
+ void restoreAllSimSpecificSettingsFromBackup(in byte[] data);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index baf45cd8ca91..9090edb09870 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -68,15 +68,14 @@ import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.telephony.ims.aidl.IRcsConfigCallback;
import android.telephony.satellite.ISatelliteStateListener;
-import android.telephony.satellite.ISatelliteCapabilitiesConsumer;
import android.telephony.satellite.SatelliteCapabilities;
+import android.telephony.satellite.SatelliteDatagram;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.IBooleanConsumer;
import com.android.internal.telephony.ICallForwardingInfoCallback;
import com.android.internal.telephony.IccLogicalChannelRequest;
import com.android.internal.telephony.IImsStateCallback;
-import com.android.internal.telephony.IIntArrayConsumer;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.INumberVerificationCallback;
import com.android.internal.telephony.OperatorInfo;
@@ -2704,74 +2703,209 @@ interface ITelephony {
void getCarrierRestrictionStatus(IIntegerConsumer internalCallback, String packageName);
/**
- * Power on or off the satellite modem.
+ * Enable or disable the satellite modem.
+ *
+ * @param subId The subId of the subscription to enable or disable the satellite modem for.
+ * @param enable True to enable the satellite modem and false to disable.
+ * @param callback The callback to get the error code of the request.
*/
- int setSatellitePower(int subId, boolean powerOn);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void setSatelliteEnabled(int subId, boolean enable, in IIntegerConsumer callback);
/**
- * Check whether the satellite modem is powered on.
+ * Request to get whether the satellite modem is enabled.
+ *
+ * @param subId The subId of the subscription to request whether satellite is enabled for.
+ * @param receiver Result receiver to get the error code of the request and whether the
+ * satellite modem is enabled.
*/
- int isSatellitePowerOn(int subId, IBooleanConsumer internalCallback);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void requestIsSatelliteEnabled(int subId, in ResultReceiver receiver);
/**
- * Check whether the satellite service is supported on the device.
+ * Request to get whether the satellite service is supported on the device.
+ *
+ * @param subId The subId of the subscription to check whether satellite is supported for.
+ * @param receiver Result receiver to get the error code of the request and whether the
+ * satellite service is supported on the device.
*/
- int isSatelliteSupported(int subId, IBooleanConsumer internalCallback);
+ void requestIsSatelliteSupported(int subId, in ResultReceiver receiver);
/**
- * Get the capabilities of the satellite service.
+ * Request to get the capabilities of the satellite service.
+ *
+ * @param subId The subId of the subscription to get the capabilities for.
+ * @param receiver Result receiver to get the error code of the request and the requested
+ * capabilities of the satellite service.
*/
- int getSatelliteCapabilities(int subId, ISatelliteCapabilitiesConsumer internalCallback);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void requestSatelliteCapabilities(int subId, in ResultReceiver receiver);
/**
* Start receiving satellite pointing updates.
+ *
+ * @param subId The subId of the subscription to stop satellite position updates for.
+ * @param errorCallback The callback to get the error code of the request.
+ * @param callback The callback to handle position updates.
*/
- int startSatellitePositionUpdates(int subId, in ISatelliteStateListener callback);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void startSatellitePositionUpdates(int subId, in IIntegerConsumer errorCallback,
+ in ISatelliteStateListener callback);
/**
* Stop receiving satellite pointing updates.
+ *
+ * @param subId The subId of the subscritpion to stop satellite position updates for.
+ * @param errorCallback The callback to get the error code of the request.
+ * @param callback The callback that was passed to startSatellitePositionUpdates.
*/
- int stopSatellitePositionUpdates(int subId, ISatelliteStateListener callback);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void stopSatellitePositionUpdates(int subId, in IIntegerConsumer errorCallback,
+ in ISatelliteStateListener callback);
/**
- * Get maximum number of characters per text message on satellite.
+ * Request to get the maximum number of characters per text message on satellite.
+ *
+ * @param subId The subId to get the maximum number of characters for.
+ * @param receiver Result receiver to get the error code of the request and the requested
+ * maximum number of characters per text message on satellite.
*/
- int getMaxCharactersPerSatelliteTextMessage(int subId, IIntegerConsumer internalCallback);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void requestMaxCharactersPerSatelliteTextMessage(int subId, in ResultReceiver receiver);
/**
* Register the subscription with a satellite provider.
* This is needed to register the subscription if the provider allows dynamic registration.
*
* @param subId The subId of the subscription to be provisioned.
- * @param features List of features to be provisioned.
+ * @param token The token to be used as a unique identifier for provisioning with satellite
+ * gateway.
* @param callback The callback to get the error code of the request.
+ *
* @return The signal transport used by callers to cancel the provision request.
*/
- ICancellationSignal provisionSatelliteService(int subId, in int[] features,
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ ICancellationSignal provisionSatelliteService(int subId, in String token,
in IIntegerConsumer callback);
/**
+ * Unregister the subscription with the satellite provider.
+ * This is needed to unregister the subscription if the provider allows dynamic registration.
+ * Once deprovisioned,
+ * {@link SatelliteCallback.SatelliteProvisionStateListener#onSatelliteProvisionStateChanged}
+ * should report as deprovisioned.
+ *
+ * @param subId The subId of the subscription to be deprovisioned.
+ * @param token The token of the device/subscription to be deprovisioned.
+ * @param callback The callback to get the error code of the request.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void deprovisionSatelliteService(int subId, in String token, in IIntegerConsumer callback);
+
+
+ /**
* Register for the satellite provision state change.
*
- * @param subId The subId of the subscription to be provisioned.
+ * @param subId The subId of the subscription to register for provision state changes for.
+ * @param errorCallback The callback to get the error code of the request.
* @param callback The callback to handle the satellite provision state changed event.
*/
- int registerForSatelliteProvisionStateChanged(int subId, ISatelliteStateListener callback);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void registerForSatelliteProvisionStateChanged(int subId,
+ in IIntegerConsumer errorCallback, in ISatelliteStateListener callback);
/**
* Unregister for the satellite provision state change.
*
* @param subId The subId of the subscription associated with the satellite service.
- * @param callback The callback that was passed to
- * registerForSatelliteProvisionStateChanged.
+ * @param errorCallback The callback to get the error code of the request.
+ * @param callback The callback that was passed to registerForSatelliteProvisionStateChanged.
*/
- int unregisterForSatelliteProvisionStateChanged(int subId, ISatelliteStateListener callback);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void unregisterForSatelliteProvisionStateChanged(int subId,
+ in IIntegerConsumer errorCallback, in ISatelliteStateListener callback);
/**
- * Get the list of provisioned satellite features.
+ * Request to get whether the device is provisioned with a satellite provider.
*
- * @param subId The subId of the subscription to be provisioned.
- * @param callback The callback to get the list of provisioned satellite features.
+ * @param subId The subId of the subscription to get whether the device is provisioned for.
+ * @param receiver Result receiver to get the error code of the request and whether the
+ * device is provisioned with a satellite provider.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void requestIsSatelliteProvisioned(int subId, in ResultReceiver receiver);
+
+ /**
+ * Register for listening to satellite modem state changes.
+ *
+ * @param subId - The subId of the subscription used for listening to satellite state changes.
+ * @param callback - The callback to handle the satellite state changed event.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ int registerForSatelliteModemStateChange(int subId, ISatelliteStateListener callback);
+
+ /**
+ * Unregister to stop listening to satellite modem state changes.
+ *
+ * @param subId - The subId of the subscription associated with the satellite service.
+ * @param callback - The callback that was passed to registerForSatelliteStateChange.
*/
- int getProvisionedSatelliteFeatures(int subId, IIntArrayConsumer callback);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ int unregisterForSatelliteModemStateChange(int subId, ISatelliteStateListener callback);
+
+ /**
+ * Register to receive incoming datagrams over satellite.
+ *
+ * @param subId - The subId of the subscription used for receiving datagrams.
+ * @param datagramType - type of datagram
+ * @param callback - The callback to receive incoming datagrams.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ int registerForSatelliteDatagram(int subId, int datagramType, ISatelliteStateListener callback);
+
+ /**
+ * Unregister to stop receiving incoming datagrams over satellite.
+ *
+ * @param subId - The subId of the subscription associated with the satellite service.
+ * @param callback - The callback that was passed to registerForSatelliteDatagram.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ int unregisterForSatelliteDatagram(int subId, ISatelliteStateListener callback);
+
+ /**
+ * Poll pending satellite datagrams over satellite.
+ *
+ * @param subId - The subId of the subscription used for receiving datagrams.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ int pollPendingSatelliteDatagrams(int subId);
+
+ /**
+ * Send datagram over satellite.
+ *
+ * @param subId - The subId of the subscription used for receiving datagrams.
+ * @param datagramType - type of datagram
+ * @param datagram - datagram to send over satellite
+ * @param callback - The callback to get the error code of the request.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void sendSatelliteDatagram(int subId, int datagramType, in SatelliteDatagram datagram,
+ IIntegerConsumer callback);
}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
index daff76f4f522..5d4a4efecf83 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BasePerfTest.java
@@ -61,10 +61,11 @@ public class BasePerfTest {
return intent;
}
- protected Intent createBroadcastIntent(String action) {
+ protected Intent createFgBroadcastIntent(String action) {
final Intent intent = new Intent(action);
- intent.addFlags(
- Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+ | Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
putTimeReceiverBinderExtra(intent);
return intent;
}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
index bc528d4d4fb7..6a535759c699 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/BroadcastPerfTest.java
@@ -30,11 +30,11 @@ import org.junit.runner.RunWith;
@LargeTest
public class BroadcastPerfTest extends BasePerfTest {
@Test
- public void manifestBroadcastRunning() {
+ public void manifestFgBroadcastRunning() {
runPerfFunction(() -> {
startTargetPackage();
- final Intent intent = createBroadcastIntent(
+ final Intent intent = createFgBroadcastIntent(
Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
final long startTime = System.nanoTime();
@@ -48,9 +48,9 @@ public class BroadcastPerfTest extends BasePerfTest {
}
@Test
- public void manifestBroadcastNotRunning() {
+ public void manifestFgBroadcastNotRunning() {
runPerfFunction(() -> {
- final Intent intent = createBroadcastIntent(
+ final Intent intent = createFgBroadcastIntent(
Constants.ACTION_BROADCAST_MANIFEST_RECEIVE);
final long startTime = System.nanoTime();
@@ -64,11 +64,11 @@ public class BroadcastPerfTest extends BasePerfTest {
}
@Test
- public void registeredBroadcast() {
+ public void registeredFgBroadcast() {
runPerfFunction(() -> {
startTargetPackage();
- final Intent intent = createBroadcastIntent(
+ final Intent intent = createFgBroadcastIntent(
Constants.ACTION_BROADCAST_REGISTERED_RECEIVE);
final long startTime = System.nanoTime();
diff --git a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
index 3ea9651045fa..48d050ce4391 100644
--- a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
+++ b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
@@ -16,7 +16,9 @@
package android.view.choreographertests;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -63,6 +65,7 @@ public class AttachedChoreographerTest {
private DisplayManager mDisplayManager;
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
+ private Choreographer mChoreographer;
private boolean mIsFirstCallback = true;
private int mCallbackMissedCounter = 0;
@@ -127,37 +130,60 @@ public class AttachedChoreographerTest {
@Test
public void testCreateChoreographer() {
+ Looper testLooper = Looper.myLooper();
mScenario.onActivity(activity -> {
if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
fail("Unable to create surface within 1 Second");
}
SurfaceControl sc = mSurfaceView.getSurfaceControl();
+ mChoreographer = sc.getChoreographer();
mTestCompleteSignal.countDown();
SurfaceControl sc1 = new SurfaceControl(sc, "AttachedChoreographerTests");
// Create attached choreographer with getChoreographer
- sc1.getChoreographer();
+ Choreographer choreographer1 = sc1.getChoreographer();
assertTrue(sc1.hasChoreographer());
assertTrue(sc1.isValid());
- sc1.release();
+ assertEquals(choreographer1, sc1.getChoreographer());
+ assertEquals(choreographer1, sc1.getChoreographer(Looper.myLooper()));
+ assertEquals(choreographer1, sc1.getChoreographer(Looper.getMainLooper()));
+ assertThrows(IllegalStateException.class, () -> sc1.getChoreographer(testLooper));
SurfaceControl sc2 = new SurfaceControl(sc, "AttachedChoreographerTests");
// Create attached choreographer with Looper.myLooper
- sc2.getChoreographer(Looper.myLooper());
+ Choreographer choreographer2 = sc2.getChoreographer(Looper.myLooper());
assertTrue(sc2.hasChoreographer());
assertTrue(sc2.isValid());
- sc2.release();
+ assertEquals(choreographer2, sc2.getChoreographer(Looper.myLooper()));
+ assertEquals(choreographer2, sc2.getChoreographer(Looper.getMainLooper()));
+ assertEquals(choreographer2, sc2.getChoreographer());
+ assertThrows(IllegalStateException.class, () -> sc2.getChoreographer(testLooper));
SurfaceControl sc3 = new SurfaceControl(sc, "AttachedChoreographerTests");
// Create attached choreographer with Looper.myLooper
- sc3.getChoreographer(Looper.getMainLooper());
+ Choreographer choreographer3 = sc3.getChoreographer(Looper.getMainLooper());
assertTrue(sc3.hasChoreographer());
assertTrue(sc3.isValid());
+ assertEquals(choreographer3, sc3.getChoreographer(Looper.getMainLooper()));
+ assertEquals(choreographer3, sc3.getChoreographer(Looper.myLooper()));
+ assertEquals(choreographer3, sc3.getChoreographer());
+ assertThrows(IllegalStateException.class, () -> sc3.getChoreographer(testLooper));
+
+ assertNotEquals(choreographer1, choreographer2);
+ assertNotEquals(choreographer1, choreographer3);
+ assertNotEquals(choreographer2, choreographer3);
+ sc1.release();
+ sc2.release();
sc3.release();
mTestCompleteSignal.countDown();
});
if (waitForCountDown(mTestCompleteSignal, /* timeoutInSeconds */ 2L)) {
fail("Test not finished in 2 Seconds");
}
+ SurfaceControl surfaceControl = mSurfaceView.getSurfaceControl();
+ assertTrue(surfaceControl.hasChoreographer());
+ assertEquals(mChoreographer, surfaceControl.getChoreographer());
+ assertThrows(IllegalStateException.class,
+ () -> surfaceControl.getChoreographer(testLooper));
}
@Test
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index aa337e5f9691..0d6dc3522d24 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -50,6 +50,7 @@ cc_defaults {
],
target: {
windows: {
+ compile_multilib: "64",
enabled: true,
cflags: ["-Wno-maybe-uninitialized"],
ldflags: ["-static"],
diff --git a/tools/lint/fix/Android.bp b/tools/lint/fix/Android.bp
index 5f6c6f779f85..7375c160a59f 100644
--- a/tools/lint/fix/Android.bp
+++ b/tools/lint/fix/Android.bp
@@ -25,4 +25,10 @@ python_binary_host {
name: "lint_fix",
main: "lint_fix.py",
srcs: ["lint_fix.py"],
+ libs: ["soong_lint_fix"],
+}
+
+python_library_host {
+ name: "soong_lint_fix",
+ srcs: ["soong_lint_fix.py"],
}
diff --git a/tools/lint/fix/lint_fix.py b/tools/lint/fix/lint_fix.py
index 0f94bd2b9b2c..1c83f7b38400 100644
--- a/tools/lint/fix/lint_fix.py
+++ b/tools/lint/fix/lint_fix.py
@@ -1,77 +1,29 @@
-import argparse
-import os
-import sys
-
-ANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP")
-PATH_PREFIX = "out/soong/.intermediates"
-PATH_SUFFIX = "android_common/lint"
-FIX_DIR = "suggested-fixes"
-
-parser = argparse.ArgumentParser(description="""
-This is a python script that applies lint fixes to the platform:
-1. Set up the environment, etc.
-2. Build the lint and run it.
-3. Unpack soong's intermediate zip containing source files modified by lint.
-4. Copy the modified files back into the tree.
-
-**Gotcha**: You must have run `source build/envsetup.sh` and `lunch` \
-so that the `ANDROID_BUILD_TOP` environment variable has been set.
-Alternatively, set it manually in your shell.
-""", formatter_class=argparse.RawTextHelpFormatter)
-
-parser.add_argument('build_path', metavar='build_path', type=str,
- help='The build module to run '
- '(e.g. frameworks/base/framework-minus-apex or '
- 'frameworks/base/services/core/services.core.unboosted)')
-
-parser.add_argument('--check', metavar='check', type=str,
- help='Which lint to run. Passed to the ANDROID_LINT_CHECK environment variable.')
-
-parser.add_argument('--dry-run', dest='dry_run', action='store_true',
- help='Just print the resulting shell script instead of running it.')
-
-parser.add_argument('--no-fix', dest='no_fix', action='store_true',
- help='Just build and run the lint, do NOT apply the fixes.')
-
-args = parser.parse_args()
-
-path = f"{PATH_PREFIX}/{args.build_path}/{PATH_SUFFIX}"
-target = f"{path}/lint-report.html"
-
-commands = []
-
-if not args.dry_run:
- commands += [f"export ANDROID_BUILD_TOP={ANDROID_BUILD_TOP}"]
-
-if args.check:
- commands += [f"export ANDROID_LINT_CHECK={args.check}"]
-
-commands += [
- "cd $ANDROID_BUILD_TOP",
- "source build/envsetup.sh",
- f"rm {target}", # remove the file first so soong doesn't think there is no work to do
- f"rm {path}/{FIX_DIR}.zip", # remove in case there are fixes from a prior run that we don't want applied if this run fails
- f"m {target}",
-]
-
-if not args.no_fix:
- commands += [
- f"cd {path}",
- f"unzip {FIX_DIR}.zip -d {FIX_DIR}",
- f"cd {FIX_DIR}",
- # Find all the java files in the fix directory, excluding the ./out subdirectory,
- # and copy them back into the same path within the tree.
- f"find . -path ./out -prune -o -name '*.java' -print | xargs -n 1 sh -c 'cp $1 $ANDROID_BUILD_TOP/$1' --",
- f"rm -rf {FIX_DIR}"
- ]
-
-if args.dry_run:
- print("(\n" + ";\n".join(commands) + "\n)")
- sys.exit(0)
-
-with_echo = []
-for c in commands:
- with_echo.append(f'echo "{c}"')
- with_echo.append(c)
-
-os.system("(\n" + ";\n".join(with_echo) + "\n)")
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# 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.
+
+from soong_lint_fix import SoongLintFix
+
+SoongLintFix().run()
diff --git a/tools/lint/fix/soong_lint_fix.py b/tools/lint/fix/soong_lint_fix.py
new file mode 100644
index 000000000000..3308df6fc5af
--- /dev/null
+++ b/tools/lint/fix/soong_lint_fix.py
@@ -0,0 +1,169 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import os
+import subprocess
+import sys
+
+ANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP")
+PATH_PREFIX = "out/soong/.intermediates"
+PATH_SUFFIX = "android_common/lint"
+FIX_DIR = "suggested-fixes"
+
+class SoongLintFix:
+ """
+ This class creates a command line tool that will
+ apply lint fixes to the platform via the necessary
+ combination of soong and shell commands.
+
+ It provides some basic hooks for experimental code
+ to tweak the generation of the resulting shell script.
+
+ By default, it will apply lint fixes using the intermediate `suggested-fixes`
+ directory that soong creates during its invocation of lint.
+
+ The default argument parser configures a number of command line arguments to
+ facilitate running lint via soong.
+
+ Basic usage:
+ ```
+ from soong_lint_fix import SoongLintFix
+
+ SoongLintFix().run()
+ ```
+ """
+ def __init__(self):
+ self._commands = None
+ self._args = None
+ self._path = None
+ self._target = None
+ self._parser = _setup_parser()
+
+
+ def add_argument(self, *args, **kwargs):
+ """
+ If necessary, add arguments to the underlying argparse.ArgumentParser before running
+ """
+ self._parser.add_argument(*args, **kwargs)
+
+
+ def run(self, add_setup_commands=None, override_fix_commands=None):
+ """
+ Run the script
+ :param add_setup_commands: OPTIONAL function to add additional setup commands
+ passed the command line arguments, path, and build target
+ must return a list of strings (the additional commands)
+ :param override_fix_commands: OPTIONAL function to override the fix commands
+ passed the command line arguments, path, and build target
+ must return a list of strings (the fix commands)
+ """
+ self._setup()
+ if add_setup_commands:
+ self._commands += add_setup_commands(self._args, self._path, self._target)
+
+ self._add_lint_report_commands()
+
+ if not self._args.no_fix:
+ if override_fix_commands:
+ self._commands += override_fix_commands(self._args, self._path, self._target)
+ else:
+ self._commands += [
+ f"cd {self._path}",
+ f"unzip {FIX_DIR}.zip -d {FIX_DIR}",
+ f"cd {FIX_DIR}",
+ # Find all the java files in the fix directory, excluding the ./out subdirectory,
+ # and copy them back into the same path within the tree.
+ f"find . -path ./out -prune -o -name '*.java' -print | xargs -n 1 sh -c 'cp $1 $ANDROID_BUILD_TOP/$1 || exit 255' --",
+ f"rm -rf {FIX_DIR}"
+ ]
+
+
+ if self._args.dry_run:
+ print(self._get_commands_str())
+ else:
+ self._execute()
+
+
+ def _setup(self):
+ self._args = self._parser.parse_args()
+ self._commands = []
+ self._path = f"{PATH_PREFIX}/{self._args.build_path}/{PATH_SUFFIX}"
+ self._target = f"{self._path}/lint-report.html"
+
+ if not self._args.dry_run:
+ self._commands += [f"export ANDROID_BUILD_TOP={ANDROID_BUILD_TOP}"]
+
+ if self._args.check:
+ self._commands += [f"export ANDROID_LINT_CHECK={self._args.check}"]
+
+
+ def _add_lint_report_commands(self):
+ self._commands += [
+ "cd $ANDROID_BUILD_TOP",
+ "source build/envsetup.sh",
+ # remove the file first so soong doesn't think there is no work to do
+ f"rm {self._target}",
+ # remove in case there are fixes from a prior run,
+ # that we don't want applied if this run fails
+ f"rm {self._path}/{FIX_DIR}.zip",
+ f"m {self._target}",
+ ]
+
+
+ def _get_commands_str(self):
+ prefix = "(\n"
+ delimiter = ";\n"
+ suffix = "\n)"
+ return f"{prefix}{delimiter.join(self._commands)}{suffix}"
+
+
+ def _execute(self, with_echo=True):
+ if with_echo:
+ exec_commands = []
+ for c in self._commands:
+ exec_commands.append(f'echo "{c}"')
+ exec_commands.append(c)
+ self._commands = exec_commands
+
+ subprocess.call(self._get_commands_str(), executable='/bin/bash', shell=True)
+
+
+def _setup_parser():
+ parser = argparse.ArgumentParser(description="""
+ This is a python script that applies lint fixes to the platform:
+ 1. Set up the environment, etc.
+ 2. Run lint on the specified target.
+ 3. Copy the modified files, from soong's intermediate directory, back into the tree.
+
+ **Gotcha**: You must have run `source build/envsetup.sh` and `lunch`
+ so that the `ANDROID_BUILD_TOP` environment variable has been set.
+ Alternatively, set it manually in your shell.
+ """, formatter_class=argparse.RawTextHelpFormatter)
+
+ parser.add_argument('build_path', metavar='build_path', type=str,
+ help='The build module to run '
+ '(e.g. frameworks/base/framework-minus-apex or '
+ 'frameworks/base/services/core/services.core.unboosted)')
+
+ parser.add_argument('--check', metavar='check', type=str,
+ help='Which lint to run. Passed to the ANDROID_LINT_CHECK environment variable.')
+
+ parser.add_argument('--dry-run', dest='dry_run', action='store_true',
+ help='Just print the resulting shell script instead of running it.')
+
+ parser.add_argument('--no-fix', dest='no_fix', action='store_true',
+ help='Just build and run the lint, do NOT apply the fixes.')
+
+ return parser
diff --git a/wifi/java/src/android/net/wifi/nl80211/PnoSettings.java b/wifi/java/src/android/net/wifi/nl80211/PnoSettings.java
index 00ebe624ba0d..2f15066f97cf 100644
--- a/wifi/java/src/android/net/wifi/nl80211/PnoSettings.java
+++ b/wifi/java/src/android/net/wifi/nl80211/PnoSettings.java
@@ -19,9 +19,12 @@ package android.net.wifi.nl80211;
import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import androidx.annotation.RequiresApi;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -38,6 +41,8 @@ public final class PnoSettings implements Parcelable {
private int mMin2gRssi;
private int mMin5gRssi;
private int mMin6gRssi;
+ private int mScanIterations;
+ private int mScanIntervalMultiplier;
private List<PnoNetwork> mPnoNetworks;
/** Construct an uninitialized PnoSettings object */
@@ -122,6 +127,46 @@ public final class PnoSettings implements Parcelable {
}
/**
+ * Get the requested PNO scan iterations.
+ *
+ * @return PNO scan iterations.
+ */
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public int getScanIterations() {
+ return mScanIterations;
+ }
+
+ /**
+ * Set the requested PNO scan iterations.
+ *
+ * @param scanIterations the PNO scan iterations.
+ */
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public void setScanIterations(int scanIterations) {
+ this.mScanIterations = scanIterations;
+ }
+
+ /**
+ * Get the requested PNO scan interval multiplier.
+ *
+ * @return PNO scan interval multiplier.
+ */
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public int getScanIntervalMultiplier() {
+ return mScanIntervalMultiplier;
+ }
+
+ /**
+ * Set the requested PNO scan interval multiplier.
+ *
+ * @param scanIntervalMultiplier the PNO scan interval multiplier.
+ */
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public void setScanIntervalMultiplier(int scanIntervalMultiplier) {
+ this.mScanIntervalMultiplier = scanIntervalMultiplier;
+ }
+
+ /**
* Return the configured list of specific networks to search for in a PNO scan.
*
* @return A list of {@link PnoNetwork} objects, possibly empty if non configured.
@@ -156,13 +201,16 @@ public final class PnoSettings implements Parcelable {
&& mMin2gRssi == settings.mMin2gRssi
&& mMin5gRssi == settings.mMin5gRssi
&& mMin6gRssi == settings.mMin6gRssi
+ && mScanIterations == settings.mScanIterations
+ && mScanIntervalMultiplier == settings.mScanIntervalMultiplier
&& mPnoNetworks.equals(settings.mPnoNetworks);
}
/** override hash code */
@Override
public int hashCode() {
- return Objects.hash(mIntervalMs, mMin2gRssi, mMin5gRssi, mMin6gRssi, mPnoNetworks);
+ return Objects.hash(mIntervalMs, mMin2gRssi, mMin5gRssi, mMin6gRssi,
+ mScanIterations, mScanIntervalMultiplier, mPnoNetworks);
}
/** implement Parcelable interface */
@@ -181,6 +229,8 @@ public final class PnoSettings implements Parcelable {
out.writeInt(mMin2gRssi);
out.writeInt(mMin5gRssi);
out.writeInt(mMin6gRssi);
+ out.writeInt(mScanIterations);
+ out.writeInt(mScanIntervalMultiplier);
out.writeTypedList(mPnoNetworks);
}
@@ -194,6 +244,8 @@ public final class PnoSettings implements Parcelable {
result.mMin2gRssi = in.readInt();
result.mMin5gRssi = in.readInt();
result.mMin6gRssi = in.readInt();
+ result.mScanIterations = in.readInt();
+ result.mScanIntervalMultiplier = in.readInt();
result.mPnoNetworks = new ArrayList<>();
in.readTypedList(result.mPnoNetworks, PnoNetwork.CREATOR);
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index c2981899d2ab..8aa369e31ce8 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -35,6 +35,8 @@ import android.os.IInterface;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.R;
+
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -51,8 +53,6 @@ import java.util.concurrent.Executor;
public class SharedConnectivityManager {
private static final String TAG = SharedConnectivityManager.class.getSimpleName();
private static final boolean DEBUG = true;
- private static final String SERVICE_PACKAGE_NAME = "sharedconnectivity_service_package";
- private static final String SERVICE_CLASS_NAME = "sharedconnectivity_service_class";
private static final class SharedConnectivityCallbackProxy extends
ISharedConnectivityCallback.Stub {
@@ -101,7 +101,7 @@ public class SharedConnectivityManager {
Binder.restoreCallingIdentity(token);
}
}
- };
+ }
@Override
public void onTetherNetworkConnectionStatusChanged(
@@ -115,7 +115,7 @@ public class SharedConnectivityManager {
Binder.restoreCallingIdentity(token);
}
}
- };
+ }
@Override
public void onKnownNetworkConnectionStatusChanged(
@@ -129,7 +129,7 @@ public class SharedConnectivityManager {
Binder.restoreCallingIdentity(token);
}
}
- };
+ }
}
private ISharedConnectivityService mService;
@@ -137,14 +137,33 @@ public class SharedConnectivityManager {
mProxyMap = new HashMap<>();
/**
- * Constructor for new instance of {@link SharedConnectivityManager}.
+ * Creates a new instance of {@link SharedConnectivityManager}.
*
* Automatically binds to implementation of {@link SharedConnectivityService} specified in
* device overlay.
*
+ * @return An instance of {@link SharedConnectivityManager} or null if the shared connectivity
+ * service is not found.
* @hide
*/
- public SharedConnectivityManager(@NonNull Context context) {
+ @Nullable
+ public static SharedConnectivityManager create(@NonNull Context context) {
+ Resources resources = context.getResources();
+ try {
+ String servicePackageName = resources.getString(
+ R.string.shared_connectivity_service_package);
+ String serviceIntentAction = resources.getString(
+ R.string.shared_connectivity_service_intent_action);
+ return new SharedConnectivityManager(context, servicePackageName, serviceIntentAction);
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "To support shared connectivity service on this device, the service's"
+ + " package name and intent action string must be defined");
+ }
+ return null;
+ }
+
+ private SharedConnectivityManager(@NonNull Context context, String servicePackageName,
+ String serviceIntentAction) {
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -158,7 +177,10 @@ public class SharedConnectivityManager {
mProxyMap.clear();
}
};
- bind(context, serviceConnection);
+
+ context.bindService(
+ new Intent().setPackage(servicePackageName).setAction(serviceIntentAction),
+ serviceConnection, Context.BIND_AUTO_CREATE);
}
/**
@@ -169,25 +191,6 @@ public class SharedConnectivityManager {
mService = (ISharedConnectivityService) service;
}
- private void bind(Context context, ServiceConnection serviceConnection) {
- Resources resources = context.getResources();
- int packageNameId = resources.getIdentifier(SERVICE_PACKAGE_NAME, "string",
- context.getPackageName());
- int classNameId = resources.getIdentifier(SERVICE_CLASS_NAME, "string",
- context.getPackageName());
- if (packageNameId == 0 || classNameId == 0) {
- throw new Resources.NotFoundException("Package and class names for"
- + " shared connectivity service must be defined");
- }
-
- Intent intent = new Intent();
- intent.setComponent(new ComponentName(resources.getString(packageNameId),
- resources.getString(classNameId)));
- context.bindService(
- intent,
- serviceConnection, Context.BIND_AUTO_CREATE);
- }
-
/**
* Registers a callback for receiving updates to the list of Tether Networks and Known Networks.
*
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
index a40049b2515a..10ef0669aeab 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/service/SharedConnectivityService.java
@@ -101,13 +101,13 @@ public abstract class SharedConnectivityService extends Service {
@Override
public void registerCallback(ISharedConnectivityCallback callback) {
checkPermissions();
- mHandler.post(() -> registerCallback(callback));
+ mHandler.post(() -> onRegisterCallback(callback));
}
@Override
public void unregisterCallback(ISharedConnectivityCallback callback) {
checkPermissions();
- mHandler.post(() -> unregisterCallback(callback));
+ mHandler.post(() -> onUnregisterCallback(callback));
}
@Override
@@ -147,7 +147,7 @@ public abstract class SharedConnectivityService extends Service {
};
}
- private void registerCallback(ISharedConnectivityCallback callback) {
+ private void onRegisterCallback(ISharedConnectivityCallback callback) {
// Listener gets triggered on first register using cashed data
if (!notifyTetherNetworkUpdate(callback) || !notifyKnownNetworkUpdate(callback)
|| !notifySettingsStateUpdate(callback)
@@ -167,7 +167,7 @@ public abstract class SharedConnectivityService extends Service {
}
}
- private void unregisterCallback(ISharedConnectivityCallback callback) {
+ private void onUnregisterCallback(ISharedConnectivityCallback callback) {
DeathRecipient deathRecipient = mDeathRecipientMap.get(callback);
if (deathRecipient != null) {
callback.asBinder().unlinkToDeath(deathRecipient, 0);
diff --git a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
index 9aeccac1968e..784e9c4731ee 100644
--- a/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManagerTest.java
@@ -89,7 +89,7 @@ public class SharedConnectivityManagerTest {
*/
@Test
public void testBindingToService() {
- new SharedConnectivityManager(mContext);
+ SharedConnectivityManager.create(mContext);
verify(mContext).bindService(any(), any(), anyInt());
}
@@ -98,22 +98,22 @@ public class SharedConnectivityManagerTest {
*/
@Test
public void testRegisterCallback() throws Exception {
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.registerCallback(mExecutor, mClientCallback));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
assertTrue(manager.registerCallback(mExecutor, mClientCallback));
verify(mService).registerCallback(any());
// Registering the same callback twice should fail.
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
assertFalse(manager.registerCallback(mExecutor, mClientCallback));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).registerCallback(any());
assertFalse(manager.registerCallback(mExecutor, mClientCallback));
@@ -125,24 +125,24 @@ public class SharedConnectivityManagerTest {
*/
@Test
public void testUnregisterCallback() throws Exception {
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.unregisterCallback(mClientCallback));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
assertTrue(manager.unregisterCallback(mClientCallback));
verify(mService).unregisterCallback(any());
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.registerCallback(mExecutor, mClientCallback);
manager.unregisterCallback(mClientCallback);
assertFalse(manager.unregisterCallback(mClientCallback));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
doThrow(new RemoteException()).when(mService).unregisterCallback(any());
assertFalse(manager.unregisterCallback(mClientCallback));
@@ -156,11 +156,11 @@ public class SharedConnectivityManagerTest {
public void testConnectTetherNetwork() throws RemoteException {
TetherNetwork network = buildTetherNetwork();
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.connectTetherNetwork(network));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.connectTetherNetwork(network);
verify(mService).connectTetherNetwork(network);
@@ -175,11 +175,11 @@ public class SharedConnectivityManagerTest {
*/
@Test
public void testDisconnectTetherNetwork() throws RemoteException {
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.disconnectTetherNetwork());
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.disconnectTetherNetwork();
verify(mService).disconnectTetherNetwork();
@@ -196,11 +196,11 @@ public class SharedConnectivityManagerTest {
public void testConnectKnownNetwork() throws RemoteException {
KnownNetwork network = buildKnownNetwork();
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.connectKnownNetwork(network));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.connectKnownNetwork(network);
verify(mService).connectKnownNetwork(network);
@@ -217,11 +217,11 @@ public class SharedConnectivityManagerTest {
public void testForgetKnownNetwork() throws RemoteException {
KnownNetwork network = buildKnownNetwork();
- SharedConnectivityManager manager = new SharedConnectivityManager(mContext);
+ SharedConnectivityManager manager = SharedConnectivityManager.create(mContext);
manager.setService(null);
assertFalse(manager.forgetKnownNetwork(network));
- manager = new SharedConnectivityManager(mContext);
+ manager = SharedConnectivityManager.create(mContext);
manager.setService(mService);
manager.forgetKnownNetwork(network);
verify(mService).forgetKnownNetwork(network);