summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobInfo.java32
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobParameters.java2
-rw-r--r--apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java259
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java42
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java22
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java9
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java277
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java7
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java22
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java20
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java305
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/README.md49
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java16
-rw-r--r--api/api.go6
-rw-r--r--core/api/module-lib-lint-baseline.txt20
-rw-r--r--core/api/system-lint-baseline.txt267
-rw-r--r--core/api/test-lint-baseline.txt2916
-rw-r--r--core/java/android/app/KeyguardManager.java6
-rw-r--r--core/java/android/content/pm/PackageParser.java6
-rw-r--r--core/java/android/content/pm/TEST_MAPPING66
-rw-r--r--core/java/android/content/pm/verify/domain/TEST_MAPPING3
-rw-r--r--core/java/android/inputmethodservice/NavigationBarController.java18
-rw-r--r--core/java/android/net/Uri.java22
-rw-r--r--core/java/android/permission/ILegacyPermissionManager.aidl2
-rw-r--r--core/java/android/permission/LegacyPermissionManager.java17
-rw-r--r--core/java/android/provider/DeviceConfig.java7
-rw-r--r--core/java/android/provider/Settings.java49
-rw-r--r--core/java/android/service/dreams/DreamService.java8
-rw-r--r--core/java/android/service/games/GameSession.java14
-rw-r--r--core/java/android/service/games/GameSessionActivityResult.java12
-rw-r--r--core/java/android/service/games/GameSessionService.java11
-rw-r--r--core/java/android/service/games/GameSessionTrampolineActivity.java53
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java20
-rw-r--r--core/java/android/view/Choreographer.java25
-rw-r--r--core/java/android/view/ImeInsetsSourceConsumer.java15
-rw-r--r--core/java/android/view/InsetsSource.java17
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java6
-rw-r--r--core/java/android/view/InsetsState.java13
-rw-r--r--core/java/android/view/SurfaceControl.java22
-rw-r--r--core/java/android/view/View.java91
-rw-r--r--core/java/android/view/ViewRootImpl.java3
-rw-r--r--core/java/android/view/WindowManager.java12
-rw-r--r--core/java/android/view/WindowManagerPolicyConstants.java1
-rw-r--r--core/java/android/window/WindowContainerTransaction.java23
-rw-r--r--core/java/com/android/internal/app/AppLocaleStore.java15
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl5
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl5
-rw-r--r--core/java/com/android/internal/app/LocalePickerWithRegion.java1
-rw-r--r--core/java/com/android/internal/app/ResolverListAdapter.java10
-rw-r--r--core/java/com/android/internal/app/SuggestedLocaleAdapter.java8
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java8
-rw-r--r--core/java/com/android/internal/policy/ForceShowNavBarSettingsObserver.java75
-rw-r--r--core/java/com/android/internal/view/ScrollCaptureViewSupport.java8
-rw-r--r--core/jni/android_view_SurfaceControl.cpp5
-rw-r--r--core/proto/android/os/appbackgroundrestrictioninfo.proto14
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/res/res/layout/app_language_picker_current_locale_item.xml2
-rw-r--r--core/res/res/layout/app_language_picker_system_current.xml2
-rw-r--r--core/res/res/values/config.xml6
-rw-r--r--core/res/res/values/config_telephony.xml8
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/values/themes.xml16
-rw-r--r--core/tests/coretests/src/android/net/UriTest.java54
-rw-r--r--graphics/java/android/graphics/drawable/Icon.java23
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java9
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java24
-rw-r--r--libs/WindowManager/Shell/res/layout/split_decor.xml4
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java (renamed from core/java/com/android/internal/policy/KidsModeSettingsObserver.java)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java9
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt13
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt13
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt17
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt17
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt21
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java1
-rw-r--r--packages/SettingsLib/ActionButtonsPreference/res/layout-v31/settingslib_action_buttons.xml12
-rw-r--r--packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java10
-rw-r--r--packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiPermissionChecker.java98
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiPermissionCheckerTest.java111
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java3
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java3
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt326
-rw-r--r--packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt49
-rw-r--r--packages/SystemUI/res-keyguard/layout/fgs_footer.xml11
-rw-r--r--packages/SystemUI/res/drawable/keyguard_framed_avatar_background.xml22
-rw-r--r--packages/SystemUI/res/layout/keyguard_qs_user_switch.xml31
-rw-r--r--packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml10
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml4
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/res/values/strings.xml10
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ILauncherUnlockAnimationController.aidl9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java45
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java22
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java42
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/FontSizeUtils.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt667
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java84
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt89
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaColorSchemes.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt84
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java127
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroup.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/WifiStateWorker.java124
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderController.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/NoOpOverScroller.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/ShadeOverScroller.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/ShadeTransitionController.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/SplitShadeOverScroller.kt142
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/Utils.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt342
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt66
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt62
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt34
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt167
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/WifiStateWorkerTest.java205
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderControllerTest.kt55
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt168
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java66
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/shade/transition/ShadeTransitionControllerTest.kt118
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/shade/transition/SplitShadeOverScrollerTest.kt107
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java12
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java19
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java5
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java14
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java13
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java13
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java23
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java15
-rw-r--r--services/core/java/com/android/server/am/AppBatteryTracker.java16
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java11
-rw-r--r--services/core/java/com/android/server/am/AppRestrictionController.java29
-rw-r--r--services/core/java/com/android/server/am/DropboxRateLimiter.java3
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java1
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java11
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java87
-rw-r--r--services/core/java/com/android/server/app/GameTaskInfo.java66
-rw-r--r--services/core/java/com/android/server/app/GameTaskInfoProvider.java121
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java6
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java26
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java42
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java39
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java2
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java38
-rw-r--r--services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java48
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java16
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java18
-rw-r--r--services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java4
-rw-r--r--services/core/java/com/android/server/media/MediaShellCommand.java1
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java99
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageHandler.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java3
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java18
-rw-r--r--services/core/java/com/android/server/pm/Settings.java46
-rw-r--r--services/core/java/com/android/server/pm/ShortcutLauncher.java10
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java38
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackageItem.java49
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java32
-rw-r--r--services/core/java/com/android/server/pm/ShortcutUser.java27
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java17
-rw-r--r--services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java10
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java4
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java6
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyInternal.java5
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java166
-rw-r--r--services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityInterceptorCallback.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java81
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java50
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java27
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/AppTaskImpl.java16
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java11
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java9
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java34
-rw-r--r--services/core/java/com/android/server/wm/DisplayFrames.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java41
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java42
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java17
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java1
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java6
-rw-r--r--services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java72
-rw-r--r--services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java49
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/StartingSurfaceController.java10
-rw-r--r--services/core/java/com/android/server/wm/Task.java16
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java25
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java29
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java3
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java12
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java158
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java27
-rw-r--r--services/tests/mockingservicestests/Android.bp2
-rw-r--r--services/tests/mockingservicestests/AndroidManifest.xml4
-rw-r--r--services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java212
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java14
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java44
-rw-r--r--services/tests/servicestests/Android.bp7
-rw-r--r--services/tests/servicestests/AndroidManifest.xml1
-rw-r--r--services/tests/servicestests/AndroidTest.xml1
-rw-r--r--services/tests/servicestests/aidl/Android.bp31
-rw-r--r--services/tests/servicestests/aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl21
-rw-r--r--services/tests/servicestests/aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl27
-rw-r--r--services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/display/TEST_MAPPING21
-rw-r--r--services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java420
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java20
-rw-r--r--services/tests/servicestests/test-apps/ConnTestApp/Android.bp40
-rw-r--r--services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml30
-rw-r--r--services/tests/servicestests/test-apps/ConnTestApp/OWNERS1
-rw-r--r--services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/CmdReceiverService.java36
-rw-r--r--services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java146
-rw-r--r--services/tests/uiservicestests/AndroidManifest.xml1
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java69
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java47
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java149
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java45
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java75
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java42
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java31
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java49
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java25
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java13
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java26
-rw-r--r--telephony/java/Android.bp9
-rw-r--r--telephony/java/android/telephony/AnomalyReporter.java9
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java11
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt30
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt10
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/DialogThemedActivity.java20
-rw-r--r--tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java2
318 files changed, 8176 insertions, 5829 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 18665e7f4d22..f49cdbf403f0 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -241,7 +241,7 @@ public class JobInfo implements Parcelable {
/**
* Default value for all regular jobs. As noted in {@link JobScheduler},
- * these jobs have a general maximum execution time of 10 minutes.
+ * these jobs have a general execution time of 10 minutes.
* Receives the standard job management policy.
*/
public static final int PRIORITY_DEFAULT = 300;
@@ -250,7 +250,7 @@ public class JobInfo implements Parcelable {
* This task should be ordered ahead of most other tasks. It may be
* deferred a little, but if it doesn't run at some point, the user may think
* something is wrong. Assuming all constraints remain satisfied
- * (including ideal system load conditions), these jobs will have a maximum
+ * (including ideal system load conditions), these jobs can have an
* execution time of at least 4 minutes. Setting all of your jobs to high
* priority will not be beneficial to your app and in fact may hurt its
* performance in the long run.
@@ -260,7 +260,7 @@ public class JobInfo implements Parcelable {
/**
* This task should be run ahead of all other tasks. Only Expedited Jobs
* {@link Builder#setExpedited(boolean)} can have this priority and as such,
- * are subject to the same maximum execution time details noted in
+ * are subject to the same execution time details noted in
* {@link Builder#setExpedited(boolean)}.
* A sample task of max priority: receiving a text message and processing it to
* show a notification
@@ -1414,6 +1414,15 @@ public class JobInfo implements Parcelable {
* you also need to define the network traffic used by each work item
* when constructing them.
*
+ * <p class="note">
+ * Prior to Android version {@link Build.VERSION_CODES#TIRAMISU}, JobScheduler used the
+ * estimated transfer numbers in a similar fashion to
+ * {@link #setMinimumNetworkChunkBytes(long)} (to estimate if the work would complete
+ * within the time available to job). In other words, JobScheduler treated the transfer as
+ * all-or-nothing. Starting from Android version {@link Build.VERSION_CODES#TIRAMISU},
+ * JobScheduler will only use the estimated transfer numbers in this manner if minimum
+ * chunk sizes have not been provided via {@link #setMinimumNetworkChunkBytes(long)}.
+ *
* @param downloadBytes The estimated size of network traffic that will
* be downloaded by this job, in bytes.
* @param uploadBytes The estimated size of network traffic that will be
@@ -1756,14 +1765,19 @@ public class JobInfo implements Parcelable {
*
* <p>
* Assuming all constraints remain satisfied (including ideal system load conditions),
- * expedited jobs will have a maximum execution time of at least 1 minute. If your
+ * expedited jobs can have an execution time of at least 1 minute. If your
* app has remaining expedited job quota, then the expedited job <i>may</i> potentially run
* longer until remaining quota is used up. Just like with regular jobs, quota is not
* consumed while the app is on top and visible to the user.
*
- * <p>
+ * <p class="note">
* Note: Even though expedited jobs are meant to run as soon as possible, they may be
* deferred if the system is under heavy load or requested constraints are not satisfied.
+ * This delay may be true for expedited jobs of the foreground app on Android version
+ * {@link Build.VERSION_CODES#S}, but starting from Android version
+ * {@link Build.VERSION_CODES#TIRAMISU}, expedited jobs for the foreground app are
+ * guaranteed to be started before {@link JobScheduler#schedule(JobInfo)} returns (assuming
+ * all requested constraints are satisfied), similar to foreground services.
*
* @see JobInfo#isExpedited()
*/
@@ -1799,6 +1813,9 @@ public class JobInfo implements Parcelable {
* and in the background, or the job failed due to unsatisfied constraints,
* this job should be expected to behave like other jobs without this flag.
*
+ * <p>
+ * Jobs marked as important-while-foreground are given {@link #PRIORITY_HIGH} by default.
+ *
* @param importantWhileForeground whether to relax doze restrictions for this job when the
* app is in the foreground. False by default.
* @see JobInfo#isImportantWhileForeground()
@@ -1831,8 +1848,9 @@ public class JobInfo implements Parcelable {
* the specific user of this device. For example, fetching top headlines
* of interest to the current user.
* <p>
- * Starting with Android version {@link Build.VERSION_CODES#TIRAMISU}, prefetch jobs are
- * not allowed to have deadlines (set via {@link #setOverrideDeadline(long)}.
+ * Apps targeting Android version {@link Build.VERSION_CODES#TIRAMISU} or later are
+ * not allowed to have deadlines (set via {@link #setOverrideDeadline(long)} on their
+ * prefetch jobs.
* <p>
* The system may use this signal to relax the network constraints you
* originally requested, such as allowing a
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index 1429c45ef2d2..ed72530d8608 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -167,7 +167,7 @@ public class JobParameters implements Parcelable {
/**
* The job used up its maximum execution time and timed out. Each individual job has a maximum
* execution time limit, regardless of how much total quota the app has. See the note on
- * {@link JobScheduler} for the execution time limits.
+ * {@link JobScheduler} and {@link JobInfo} for the execution time limits.
*/
public static final int STOP_REASON_TIMEOUT = 3;
/**
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
index dd0d07f68547..c3fc7b16ebdf 100644
--- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
+++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
@@ -16,8 +16,10 @@
package android.app.tare;
+import android.annotation.Nullable;
import android.annotation.SystemService;
import android.content.Context;
+import android.util.Log;
/**
* Provides access to the resource economy service.
@@ -26,6 +28,69 @@ import android.content.Context;
*/
@SystemService(Context.RESOURCE_ECONOMY_SERVICE)
public class EconomyManager {
+ private static final String TAG = "TARE-" + EconomyManager.class.getSimpleName();
+
+ /**
+ * 1 ARC = 1 GIGA-CAKE!
+ *
+ * @hide
+ */
+ public static final long CAKE_IN_ARC = 1_000_000_000L;
+
+ /** @hide */
+ public static long arcToCake(int arcs) {
+ return arcs * CAKE_IN_ARC;
+ }
+
+ /**
+ * Parses a configuration string to get the value in cakes.
+ *
+ * @hide
+ */
+ public static long parseCreditValue(@Nullable final String val, final long defaultValCakes) {
+ String trunc;
+ if (val == null || (trunc = val.trim()).isEmpty()) {
+ return defaultValCakes;
+ }
+ long multiplier;
+ if (trunc.endsWith("c")) {
+ trunc = trunc.substring(0, trunc.length() - 1);
+ multiplier = 1;
+ } else if (trunc.endsWith("ck")) {
+ trunc = trunc.substring(0, trunc.length() - 2);
+ multiplier = 1;
+ } else if (trunc.endsWith("A")) {
+ trunc = trunc.substring(0, trunc.length() - 1);
+ multiplier = CAKE_IN_ARC;
+ } else if (trunc.endsWith("ARC")) {
+ trunc = trunc.substring(0, trunc.length() - 3);
+ multiplier = CAKE_IN_ARC;
+ } else {
+ // Don't risk using the wrong units
+ Log.e(TAG, "Couldn't determine units of credit value: " + val);
+ return defaultValCakes;
+ }
+
+ // Allow people to shorten notation (eg. Mc for Megacake).
+ if (trunc.endsWith("k")) {
+ trunc = trunc.substring(0, trunc.length() - 1);
+ multiplier *= 1_000;
+ } else if (trunc.endsWith("M")) {
+ trunc = trunc.substring(0, trunc.length() - 1);
+ multiplier *= 1_000_000;
+ } else if (trunc.endsWith("G")) {
+ trunc = trunc.substring(0, trunc.length() - 1);
+ multiplier *= 1_000_000_000;
+ }
+
+ try {
+ return Long.parseLong(trunc) * multiplier;
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Malformed config string: " + val + " to " + trunc, e);
+ return defaultValCakes;
+ }
+ }
+
// Keys for AlarmManager TARE factors
/** @hide */
public static final String KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED =
@@ -276,179 +341,201 @@ public class EconomyManager {
// Default values AlarmManager factors
/** @hide */
- public static final int DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED = 500;
+ public static final long DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES = arcToCake(500);
/** @hide */
- public static final int DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP = 200;
+ public static final long DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES =
+ arcToCake(256);
/** @hide */
- public static final int DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP = 160;
+ public static final long DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES = arcToCake(160);
/** @hide */
- public static final int DEFAULT_AM_MAX_SATIATED_BALANCE = 1440;
+ public static final long DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES = arcToCake(960);
/** @hide */
- public static final int DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT = 4000;
+ public static final long DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES = arcToCake(2880);
/** @hide */
- public static final int DEFAULT_AM_HARD_CONSUMPTION_LIMIT = 28_800;
+ public static final long DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES = arcToCake(15_000);
// TODO: add AlarmManager modifier default values
/** @hide */
- public static final int DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT = 0;
+ public static final long DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT_CAKES = arcToCake(0);
/** @hide */
- public static final float DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING = 0.01f;
+ // 10 megacakes = .01 ARC
+ public static final long DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING_CAKES = 10_000_000;
/** @hide */
- public static final int DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX = 500;
+ public static final long DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX_CAKES = arcToCake(500);
/** @hide */
- public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT = 3;
+ public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES = arcToCake(3);
/** @hide */
- public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING = 0;
+ public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES = arcToCake(0);
/** @hide */
- public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX = 60;
+ public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX_CAKES = arcToCake(60);
/** @hide */
- public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_INSTANT = 5;
+ public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_INSTANT_CAKES =
+ arcToCake(5);
/** @hide */
- public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_ONGOING = 0;
+ public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_ONGOING_CAKES =
+ arcToCake(0);
/** @hide */
- public static final int DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_MAX = 500;
+ public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_MAX_CAKES =
+ arcToCake(500);
/** @hide */
- public static final int DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT = 5;
+ public static final long DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES =
+ arcToCake(5);
/** @hide */
- public static final int DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING = 0;
+ public static final long DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES =
+ arcToCake(0);
/** @hide */
- public static final int DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX = 500;
+ public static final long DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES = arcToCake(500);
/** @hide */
- public static final int DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT = 10;
+ public static final long DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT_CAKES = arcToCake(10);
/** @hide */
- public static final int DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING = 0;
+ public static final long DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING_CAKES = arcToCake(0);
/** @hide */
- public static final int DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX = 500;
+ public static final long DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX_CAKES = arcToCake(500);
/** @hide */
- public static final int DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT = 10;
+ public static final long DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES = arcToCake(10);
/** @hide */
- public static final int DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING = 0;
+ public static final long DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES = arcToCake(0);
/** @hide */
- public static final int DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX = 500;
+ public static final long DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX_CAKES = arcToCake(500);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP = 3;
+ public static final long DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP_CAKES =
+ arcToCake(3);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP = 3;
+ public static final long DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP_CAKES =
+ arcToCake(3);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP = 3;
+ public static final long DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP_CAKES = arcToCake(3);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP = 3;
+ public static final long DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP_CAKES = arcToCake(3);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP = 1;
+ public static final long DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP_CAKES =
+ arcToCake(1);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP = 1;
+ public static final long DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP_CAKES = arcToCake(1);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP = 1;
+ public static final long DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP_CAKES =
+ arcToCake(1);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP = 1;
+ public static final long DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP_CAKES = arcToCake(1);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP = 5;
+ public static final long DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP_CAKES = arcToCake(5);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE = 5;
+ public static final long
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE_CAKES = arcToCake(5);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE = 4;
+ public static final long
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE_CAKES = arcToCake(4);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE = 4;
+ public static final long DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE_CAKES = arcToCake(4);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE = 3;
+ public static final long DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES = arcToCake(3);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE = 3;
+ public static final long
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE_CAKES =
+ arcToCake(3);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE = 2;
+ public static final long DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE_CAKES =
+ arcToCake(2);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE =
- 2;
+ public static final long
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES =
+ arcToCake(2);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE = 1;
+ public static final long DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE_CAKES =
+ arcToCake(1);
/** @hide */
- public static final int DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE = 10;
+ public static final long DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE_CAKES = arcToCake(10);
// Default values JobScheduler factors
// TODO: add time_since_usage variable to min satiated balance factors
/** @hide */
- public static final int DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED = 20000;
+ public static final long DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES = arcToCake(15000);
/** @hide */
- public static final int DEFAULT_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP = 10000;
+ public static final long DEFAULT_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES =
+ arcToCake(7500);
/** @hide */
- public static final int DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP = 2000;
+ public static final long DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES = arcToCake(2000);
/** @hide */
- public static final int DEFAULT_JS_MAX_SATIATED_BALANCE = 60000;
+ public static final long DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES = arcToCake(60000);
/** @hide */
- public static final int DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT = 100_000;
+ public static final long DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES = arcToCake(29_000);
/** @hide */
- public static final int DEFAULT_JS_HARD_CONSUMPTION_LIMIT = 460_000;
+ // TODO: set hard limit based on device type (phone vs tablet vs etc) + battery size
+ public static final long DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES = arcToCake(250_000);
// TODO: add JobScheduler modifier default values
/** @hide */
- public static final int DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT = 0;
+ public static final long DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT_CAKES = arcToCake(0);
/** @hide */
- public static final float DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING = 0.5f;
+ public static final long DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING_CAKES = CAKE_IN_ARC / 2;
/** @hide */
- public static final int DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX = 15000;
+ public static final long DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX_CAKES = arcToCake(15000);
/** @hide */
- public static final int DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT = 1;
+ public static final long DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES = arcToCake(1);
/** @hide */
- public static final int DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING = 0;
+ public static final long DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES = arcToCake(0);
/** @hide */
- public static final int DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX = 10;
+ public static final long DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX_CAKES = arcToCake(10);
/** @hide */
- public static final int DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT = 5;
+ public static final long DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES =
+ arcToCake(5);
/** @hide */
- public static final int DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING = 0;
+ public static final long DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES =
+ arcToCake(0);
/** @hide */
- public static final int DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX = 5000;
+ public static final long DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES = arcToCake(5000);
/** @hide */
- public static final int DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT = 10;
+ public static final long DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT_CAKES = arcToCake(10);
/** @hide */
- public static final int DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING = 0;
+ public static final long DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING_CAKES = arcToCake(0);
/** @hide */
- public static final int DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX = 5000;
+ public static final long DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX_CAKES = arcToCake(5000);
/** @hide */
- public static final int DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT = 10;
+ public static final long DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES = arcToCake(10);
/** @hide */
- public static final int DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING = 0;
+ public static final long DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES = arcToCake(0);
/** @hide */
- public static final int DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX = 5000;
+ public static final long DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX_CAKES = arcToCake(5000);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_MAX_START_CTP = 3;
+ public static final long DEFAULT_JS_ACTION_JOB_MAX_START_CTP_CAKES = arcToCake(3);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP = 2;
+ public static final long DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP_CAKES = arcToCake(2);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_HIGH_START_CTP = 3;
+ public static final long DEFAULT_JS_ACTION_JOB_HIGH_START_CTP_CAKES = arcToCake(3);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP = 2;
+ public static final long DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP_CAKES = arcToCake(2);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP = 3;
+ public static final long DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP_CAKES = arcToCake(3);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP = 2;
+ public static final long DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP_CAKES = arcToCake(2);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_LOW_START_CTP = 3;
+ public static final long DEFAULT_JS_ACTION_JOB_LOW_START_CTP_CAKES = arcToCake(3);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP = 2;
+ public static final long DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP_CAKES = arcToCake(2);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_MIN_START_CTP = 3;
+ public static final long DEFAULT_JS_ACTION_JOB_MIN_START_CTP_CAKES = arcToCake(3);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP = 2;
+ public static final long DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP_CAKES = arcToCake(2);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP = 30;
+ public static final long DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP_CAKES = arcToCake(30);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE = 10;
+ public static final long DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE_CAKES = arcToCake(10);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE = 5;
+ public static final long DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE_CAKES = arcToCake(5);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE = 8;
+ public static final long DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE_CAKES = arcToCake(8);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE = 4;
+ public static final long DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE_CAKES = arcToCake(4);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE = 6;
+ public static final long DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE_CAKES = arcToCake(6);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE = 3;
+ public static final long DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE_CAKES = arcToCake(3);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE = 4;
+ public static final long DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE_CAKES = arcToCake(4);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE = 2;
+ public static final long DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE_CAKES = arcToCake(2);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE = 2;
+ public static final long DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE_CAKES = arcToCake(2);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE = 1;
+ public static final long DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE_CAKES = arcToCake(1);
/** @hide */
- public static final int DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE = 60;
+ public static final long DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE_CAKES = arcToCake(60);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 0e4887d27b53..2ea8592e883e 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -2637,15 +2637,18 @@ public class AlarmManagerService extends SystemService {
* Returns true if the given uid can set window to be as small as it wants.
*/
boolean isExemptFromMinWindowRestrictions(int uid) {
- return isExemptFromExactAlarmPermission(uid);
+ return isExemptFromExactAlarmPermissionNoLock(uid);
}
/**
* Returns true if the given uid does not require SCHEDULE_EXACT_ALARM to set exact,
* allow-while-idle alarms.
- * Note: It is ok to call this method without the lock {@link #mLock} held.
+ * <b> Note: This should not be called with {@link #mLock} held.</b>
*/
- boolean isExemptFromExactAlarmPermission(int uid) {
+ boolean isExemptFromExactAlarmPermissionNoLock(int uid) {
+ if (Build.IS_DEBUGGABLE && Thread.holdsLock(mLock)) {
+ Slog.wtfStack(TAG, "Alarm lock held while calling into DeviceIdleController");
+ }
return (UserHandle.isSameApp(mSystemUiUid, uid)
|| UserHandle.isCore(uid)
|| mLocalDeviceIdleController == null
@@ -2747,7 +2750,7 @@ public class AlarmManagerService extends SystemService {
}
if (needsPermission && !hasScheduleExactAlarmInternal(callingPackage, callingUid)
&& !hasUseExactAlarmInternal(callingPackage, callingUid)) {
- if (!isExemptFromExactAlarmPermission(callingUid)) {
+ if (!isExemptFromExactAlarmPermissionNoLock(callingUid)) {
final String errorMessage = "Caller " + callingPackage + " needs to hold "
+ Manifest.permission.SCHEDULE_EXACT_ALARM + " to set "
+ "exact alarms.";
@@ -2810,7 +2813,7 @@ public class AlarmManagerService extends SystemService {
if (!isExactAlarmChangeEnabled(packageName, userId)) {
return true;
}
- return isExemptFromExactAlarmPermission(packageUid)
+ return isExemptFromExactAlarmPermissionNoLock(packageUid)
|| hasScheduleExactAlarmInternal(packageName, packageUid)
|| hasUseExactAlarmInternal(packageName, packageUid);
}
@@ -3862,10 +3865,7 @@ public class AlarmManagerService extends SystemService {
// added: true => package was added to the deny list
// added: false => package was removed from the deny list
if (added) {
- synchronized (mLock) {
- removeExactAlarmsOnPermissionRevokedLocked(uid,
- changedPackage, /*killUid = */ true);
- }
+ removeExactAlarmsOnPermissionRevoked(uid, changedPackage, /*killUid = */ true);
} else {
sendScheduleExactAlarmPermissionStateChangedBroadcast(changedPackage, userId);
}
@@ -3880,9 +3880,8 @@ public class AlarmManagerService extends SystemService {
*
* This is not expected to get called frequently.
*/
- @GuardedBy("mLock")
- void removeExactAlarmsOnPermissionRevokedLocked(int uid, String packageName, boolean killUid) {
- if (isExemptFromExactAlarmPermission(uid)
+ void removeExactAlarmsOnPermissionRevoked(int uid, String packageName, boolean killUid) {
+ if (isExemptFromExactAlarmPermissionNoLock(uid)
|| !isExactAlarmChangeEnabled(packageName, UserHandle.getUserId(uid))) {
return;
}
@@ -3891,7 +3890,9 @@ public class AlarmManagerService extends SystemService {
final Predicate<Alarm> whichAlarms = a -> (a.uid == uid && a.packageName.equals(packageName)
&& a.windowLength == 0);
- removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);
+ synchronized (mLock) {
+ removeAlarmsInternalLocked(whichAlarms, REMOVE_REASON_EXACT_PERMISSION_REVOKED);
+ }
if (killUid && mConstants.KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED) {
PermissionManagerService.killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
@@ -4807,10 +4808,7 @@ public class AlarmManagerService extends SystemService {
case REMOVE_EXACT_ALARMS:
int uid = msg.arg1;
String packageName = (String) msg.obj;
- synchronized (mLock) {
- removeExactAlarmsOnPermissionRevokedLocked(uid, packageName, /*killUid = */
- true);
- }
+ removeExactAlarmsOnPermissionRevoked(uid, packageName, /*killUid = */true);
break;
case EXACT_ALARM_DENY_LIST_PACKAGES_ADDED:
handleChangesToExactAlarmDenyList((ArraySet<String>) msg.obj, true);
@@ -4826,10 +4824,7 @@ public class AlarmManagerService extends SystemService {
uid = msg.arg1;
if (!hasScheduleExactAlarmInternal(packageName, uid)
&& !hasUseExactAlarmInternal(packageName, uid)) {
- synchronized (mLock) {
- removeExactAlarmsOnPermissionRevokedLocked(uid,
- packageName, /*killUid = */false);
- }
+ removeExactAlarmsOnPermissionRevoked(uid, packageName, /*killUid = */false);
}
break;
case CHECK_EXACT_ALARM_PERMISSION_ON_FEATURE_TOGGLE:
@@ -4849,10 +4844,7 @@ public class AlarmManagerService extends SystemService {
if (defaultDenied) {
if (!hasScheduleExactAlarmInternal(pkg, uid)
&& !hasUseExactAlarmInternal(pkg, uid)) {
- synchronized (mLock) {
- removeExactAlarmsOnPermissionRevokedLocked(uid, pkg,
- true);
- }
+ removeExactAlarmsOnPermissionRevoked(uid, pkg, true);
}
} else if (hasScheduleExactAlarmInternal(pkg, uid)) {
sendScheduleExactAlarmPermissionStateChangedBroadcast(pkg,
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index c8ec89475050..c86353c84467 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -690,6 +690,12 @@ class JobConcurrencyManager {
int projectedRunningCount = numRunningJobs;
while ((nextPending = pendingJobQueue.next()) != null) {
if (mRunningJobs.contains(nextPending)) {
+ // Should never happen.
+ Slog.wtf(TAG, "Pending queue contained a running job");
+ if (DEBUG) {
+ Slog.e(TAG, "Pending+running job: " + nextPending);
+ }
+ pendingJobQueue.remove(nextPending);
continue;
}
@@ -1137,7 +1143,8 @@ class JobConcurrencyManager {
}
}
- if (mActiveServices.size() >= STANDARD_CONCURRENCY_LIMIT) {
+ final PendingJobQueue pendingJobQueue = mService.getPendingJobQueue();
+ if (mActiveServices.size() >= STANDARD_CONCURRENCY_LIMIT || pendingJobQueue.size() == 0) {
worker.clearPreferredUid();
// We're over the limit (because the TOP app scheduled a lot of EJs). Don't start
// running anything new until we get back below the limit.
@@ -1145,7 +1152,6 @@ class JobConcurrencyManager {
return;
}
- final PendingJobQueue pendingJobQueue = mService.getPendingJobQueue();
if (worker.getPreferredUid() != JobServiceContext.NO_PREFERRED_UID) {
updateCounterConfigLocked();
// Preemption case needs special care.
@@ -1162,6 +1168,12 @@ class JobConcurrencyManager {
pendingJobQueue.resetIterator();
while ((nextPending = pendingJobQueue.next()) != null) {
if (mRunningJobs.contains(nextPending)) {
+ // Should never happen.
+ Slog.wtf(TAG, "Pending queue contained a running job");
+ if (DEBUG) {
+ Slog.e(TAG, "Pending+running job: " + nextPending);
+ }
+ pendingJobQueue.remove(nextPending);
continue;
}
@@ -1239,6 +1251,12 @@ class JobConcurrencyManager {
while ((nextPending = pendingJobQueue.next()) != null) {
if (mRunningJobs.contains(nextPending)) {
+ // Should never happen.
+ Slog.wtf(TAG, "Pending queue contained a running job");
+ if (DEBUG) {
+ Slog.e(TAG, "Pending+running job: " + nextPending);
+ }
+ pendingJobQueue.remove(nextPending);
continue;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 9e131339595f..358c32722b8b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1749,8 +1749,13 @@ public class JobSchedulerService extends com.android.server.SystemService
if (!removed) {
// We never create JobStatus objects for the express purpose of removing them, and this
// method is only ever called for jobs that were saved in the JobStore at some point,
- // so if we can't find it, something went seriously wrong.
- Slog.wtfStack(TAG, "Job didn't exist in JobStore");
+ // so if we can't find it, something may be wrong. As of Android T, there is a
+ // legitimate code path where removed is false --- when an actively running job is
+ // cancelled (eg. via JobScheduler.cancel() or the app scheduling a new job with the
+ // same job ID), we remove it from the JobStore and tell the JobServiceContext to stop
+ // running the job. Once the job stops running, we then call this method again.
+ // TODO: rework code so we don't intentionally call this method twice for the same job
+ Slog.w(TAG, "Job didn't exist in JobStore");
}
if (mReadyToRock) {
for (int i = 0; i < mControllers.size(); i++) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
index c2e81882eed2..d0f719b13b89 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -16,43 +16,43 @@
package com.android.server.tare;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_AM_HARD_CONSUMPTION_LIMIT;
-import static android.app.tare.EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT;
-import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE;
-import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED;
-import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING_CAKES;
import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE;
import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP;
import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE;
@@ -97,12 +97,12 @@ import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
-import static com.android.server.tare.TareUtils.arcToCake;
import static com.android.server.tare.TareUtils.cakeToString;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
@@ -157,14 +157,15 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
AlarmManagerEconomicPolicy(InternalResourceService irs) {
super(irs);
mInternalResourceService = irs;
- loadConstants("");
+ loadConstants("", null);
}
@Override
- void setup() {
- super.setup();
+ void setup(@NonNull DeviceConfig.Properties properties) {
+ super.setup(properties);
ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
- loadConstants(Settings.Global.getString(resolver, TARE_ALARM_MANAGER_CONSTANTS));
+ loadConstants(Settings.Global.getString(resolver, TARE_ALARM_MANAGER_CONSTANTS),
+ properties);
}
@Override
@@ -178,6 +179,11 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
@Override
long getMaxSatiatedBalance() {
+ // TODO(230501287): adjust balance based on whether the app has the SCHEDULE_EXACT_ALARM
+ // permission granted. Apps without the permission granted shouldn't need a high balance
+ // since they won't be able to use exact alarms. Apps with the permission granted could
+ // have a higher balance, or perhaps just those with the USE_EXACT_ALARM permission since
+ // that is limited to specific use cases.
return mMaxSatiatedBalance;
}
@@ -209,7 +215,8 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
return mRewards.get(rewardId);
}
- private void loadConstants(String policyValuesString) {
+ private void loadConstants(String policyValuesString,
+ @Nullable DeviceConfig.Properties properties) {
mActions.clear();
mRewards.clear();
@@ -219,145 +226,159 @@ public class AlarmManagerEconomicPolicy extends EconomicPolicy {
Slog.e(TAG, "Global setting key incorrect: ", e);
}
- mMinSatiatedBalanceExempted = arcToCake(mParser.getInt(KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED,
- DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED));
- mMinSatiatedBalanceOther = arcToCake(mParser.getInt(KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP,
- DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP));
- mMaxSatiatedBalance = arcToCake(mParser.getInt(KEY_AM_MAX_SATIATED_BALANCE,
- DEFAULT_AM_MAX_SATIATED_BALANCE));
- mInitialSatiatedConsumptionLimit = arcToCake(mParser.getInt(
- KEY_AM_INITIAL_CONSUMPTION_LIMIT, DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT));
+ mMinSatiatedBalanceExempted = getConstantAsCake(mParser, properties,
+ KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED,
+ DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES);
+ mMinSatiatedBalanceOther = getConstantAsCake(mParser, properties,
+ KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP,
+ DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES);
+ mMaxSatiatedBalance = getConstantAsCake(mParser, properties,
+ KEY_AM_MAX_SATIATED_BALANCE,
+ DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES);
+ mInitialSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
+ KEY_AM_INITIAL_CONSUMPTION_LIMIT, DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES);
mHardSatiatedConsumptionLimit = Math.max(mInitialSatiatedConsumptionLimit,
- arcToCake(mParser.getInt(
- KEY_AM_HARD_CONSUMPTION_LIMIT, DEFAULT_AM_HARD_CONSUMPTION_LIMIT)));
+ getConstantAsCake(mParser, properties,
+ KEY_AM_HARD_CONSUMPTION_LIMIT, DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES));
- final long exactAllowWhileIdleWakeupBasePrice = arcToCake(
- mParser.getInt(KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE));
+ final long exactAllowWhileIdleWakeupBasePrice = getConstantAsCake(mParser, properties,
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE_CAKES);
mActions.put(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP)),
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP_CAKES),
exactAllowWhileIdleWakeupBasePrice));
mActions.put(ACTION_ALARM_WAKEUP_EXACT,
new Action(ACTION_ALARM_WAKEUP_EXACT,
- arcToCake(mParser.getInt(KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP)),
- arcToCake(mParser.getInt(KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE_CAKES)));
final long inexactAllowWhileIdleWakeupBasePrice =
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE));
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE_CAKES);
mActions.put(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
new Action(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP)),
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP_CAKES),
inexactAllowWhileIdleWakeupBasePrice));
mActions.put(ACTION_ALARM_WAKEUP_INEXACT,
new Action(ACTION_ALARM_WAKEUP_INEXACT,
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP)),
- arcToCake(mParser.getInt(
+ DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE))));
-
- final long exactAllowWhileIdleNonWakeupBasePrice =
- arcToCake(mParser.getInt(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE));
+ DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES)));
+ final long exactAllowWhileIdleNonWakeupBasePrice = getConstantAsCake(mParser, properties,
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES);
mActions.put(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
new Action(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP)),
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP_CAKES),
exactAllowWhileIdleNonWakeupBasePrice));
+
mActions.put(ACTION_ALARM_NONWAKEUP_EXACT,
new Action(ACTION_ALARM_NONWAKEUP_EXACT,
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP)),
- arcToCake(mParser.getInt(
+ DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE))));
-
- final long inexactAllowWhileIdleNonWakeupBasePrice =
- arcToCake(mParser.getInt(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE));
-
+ DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE_CAKES)));
+
+ final long inexactAllowWhileIdleNonWakeupBasePrice = getConstantAsCake(mParser, properties,
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES);
+ final long inexactAllowWhileIdleNonWakeupCtp = getConstantAsCake(mParser, properties,
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP_CAKES);
mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
new Action(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- arcToCake(mParser.getInt(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP)),
+ inexactAllowWhileIdleNonWakeupCtp,
inexactAllowWhileIdleNonWakeupBasePrice));
+
mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT,
new Action(ACTION_ALARM_NONWAKEUP_INEXACT,
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP)),
- arcToCake(mParser.getInt(
+ DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE))));
+ DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE_CAKES)));
mActions.put(ACTION_ALARM_CLOCK,
new Action(ACTION_ALARM_CLOCK,
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP,
- DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP)),
- arcToCake(mParser.getInt(
+ DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE))));
+ DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE_CAKES)));
mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
- arcToCake(mParser.getInt(KEY_AM_REWARD_TOP_ACTIVITY_INSTANT,
- DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT)),
- (long) (arcToCake(1) * mParser.getFloat(KEY_AM_REWARD_TOP_ACTIVITY_ONGOING,
- DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING)),
- arcToCake(mParser.getInt(KEY_AM_REWARD_TOP_ACTIVITY_MAX,
- DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX))));
+ getConstantAsCake(mParser, properties,
+ KEY_AM_REWARD_TOP_ACTIVITY_INSTANT,
+ DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_AM_REWARD_TOP_ACTIVITY_ONGOING,
+ DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_AM_REWARD_TOP_ACTIVITY_MAX,
+ DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX_CAKES)));
mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
- arcToCake(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT,
- DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT)),
- arcToCake(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING,
- DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING)),
- arcToCake(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_MAX,
- DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX))));
+ getConstantAsCake(mParser, properties,
+ KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT,
+ DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING,
+ DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_AM_REWARD_NOTIFICATION_SEEN_MAX,
+ DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX_CAKES)));
mRewards.put(REWARD_NOTIFICATION_INTERACTION,
new Reward(REWARD_NOTIFICATION_INTERACTION,
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT,
- DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT)),
- arcToCake(mParser.getInt(
+ DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING,
- DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING)),
- arcToCake(mParser.getInt(
+ DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX,
- DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX))));
+ DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES)));
mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
- arcToCake(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT,
- DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT)),
- arcToCake(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING,
- DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING)),
- arcToCake(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_MAX,
- DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX))));
+ getConstantAsCake(mParser, properties,
+ KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT,
+ DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING,
+ DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_AM_REWARD_WIDGET_INTERACTION_MAX,
+ DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX_CAKES)));
mRewards.put(REWARD_OTHER_USER_INTERACTION,
new Reward(REWARD_OTHER_USER_INTERACTION,
- arcToCake(mParser.getInt(KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT,
- DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT)),
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
+ KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT,
+ DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING,
- DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING)),
- arcToCake(mParser.getInt(
+ DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX,
- DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX))));
+ DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX_CAKES)));
}
@Override
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
index 2109a8575777..c3eb5bf51161 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
@@ -18,6 +18,7 @@ package com.android.server.tare;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.SparseArray;
@@ -57,10 +58,10 @@ public class CompleteEconomicPolicy extends EconomicPolicy {
}
@Override
- void setup() {
- super.setup();
+ void setup(@NonNull DeviceConfig.Properties properties) {
+ super.setup(properties);
for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
- mEnabledEconomicPolicies.valueAt(i).setup();
+ mEnabledEconomicPolicies.valueAt(i).setup(properties);
}
updateMaxBalances();
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
index 3a26aae217c2..d401373c0066 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -16,6 +16,8 @@
package com.android.server.tare;
+import static android.app.tare.EconomyManager.parseCreditValue;
+
import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
@@ -27,7 +29,9 @@ import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.provider.DeviceConfig;
import android.util.IndentingPrintWriter;
+import android.util.KeyValueListParser;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -170,7 +174,7 @@ public abstract class EconomicPolicy {
}
@CallSuper
- void setup() {
+ void setup(@NonNull DeviceConfig.Properties properties) {
for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
final Modifier modifier = COST_MODIFIER_BY_INDEX[i];
if (modifier != null) {
@@ -409,6 +413,22 @@ public abstract class EconomicPolicy {
return "UNKNOWN_REWARD:" + Integer.toHexString(eventId);
}
+ protected long getConstantAsCake(@NonNull KeyValueListParser parser,
+ @Nullable DeviceConfig.Properties properties, String key, long defaultValCake) {
+ // Don't cross the streams! Mixing Settings/local user config changes with DeviceConfig
+ // config can cause issues since the scales may be different, so use one or the other.
+ if (parser.size() > 0) {
+ // User settings take precedence. Just stick with the Settings constants, even if there
+ // are invalid values. It's not worth the time to evaluate all the key/value pairs to
+ // make sure there are valid ones before deciding.
+ return parseCreditValue(parser.getString(key, null), defaultValCake);
+ }
+ if (properties != null) {
+ return parseCreditValue(properties.getString(key, null), defaultValCake);
+ }
+ return defaultValCake;
+ }
+
protected static void dumpActiveModifiers(IndentingPrintWriter pw) {
for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
pw.print("Modifier ");
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index ce4604f80f50..2118eeb45d70 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -731,7 +731,7 @@ public class InternalResourceService extends SystemService {
registerListeners();
mCurrentBatteryLevel = getCurrentBatteryLevel();
mHandler.post(this::setupHeavyWork);
- mCompleteEconomicPolicy.setup();
+ mCompleteEconomicPolicy.setup(mConfigObserver.getAllDeviceConfigProperties());
}
}
@@ -1014,10 +1014,17 @@ public class InternalResourceService extends SystemService {
Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS), false, this);
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS), false, this);
- onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_TARE));
+ onPropertiesChanged(getAllDeviceConfigProperties());
updateEnabledStatus();
}
+ @NonNull
+ DeviceConfig.Properties getAllDeviceConfigProperties() {
+ // Don't want to cache the Properties object locally in case it ends up being large,
+ // especially since it'll only be used once/infrequently (during setup or on a change).
+ return DeviceConfig.getProperties(DeviceConfig.NAMESPACE_TARE);
+ }
+
@Override
public void onChange(boolean selfChange, Uri uri) {
if (uri.equals(Settings.Global.getUriFor(Settings.Global.ENABLE_TARE))) {
@@ -1030,6 +1037,7 @@ public class InternalResourceService extends SystemService {
@Override
public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ boolean economicPolicyUpdated = false;
synchronized (mLock) {
for (String name : properties.getKeyset()) {
if (name == null) {
@@ -1039,6 +1047,12 @@ public class InternalResourceService extends SystemService {
case KEY_DC_ENABLE_TARE:
updateEnabledStatus();
break;
+ default:
+ if (!economicPolicyUpdated
+ && (name.startsWith("am") || name.startsWith("js"))) {
+ updateEconomicPolicy();
+ economicPolicyUpdated = true;
+ }
}
}
}
@@ -1072,7 +1086,7 @@ public class InternalResourceService extends SystemService {
mCompleteEconomicPolicy.tearDown();
mCompleteEconomicPolicy = new CompleteEconomicPolicy(InternalResourceService.this);
if (mIsEnabled && mBootPhase >= PHASE_SYSTEM_SERVICES_READY) {
- mCompleteEconomicPolicy.setup();
+ mCompleteEconomicPolicy.setup(getAllDeviceConfigProperties());
if (initialLimit != mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit()
|| hardLimit
!= mCompleteEconomicPolicy.getHardSatiatedConsumptionLimit()) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index 99b93ce5c22c..948f0a71510c 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -16,48 +16,48 @@
package com.android.server.tare;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT;
-import static android.app.tare.EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT;
-import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE;
-import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED;
-import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING_CAKES;
import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE;
import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP;
import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE;
@@ -106,12 +106,12 @@ import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
-import static com.android.server.tare.TareUtils.arcToCake;
import static com.android.server.tare.TareUtils.cakeToString;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
@@ -159,14 +159,15 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
JobSchedulerEconomicPolicy(InternalResourceService irs) {
super(irs);
mInternalResourceService = irs;
- loadConstants("");
+ loadConstants("", null);
}
@Override
- void setup() {
- super.setup();
+ void setup(@NonNull DeviceConfig.Properties properties) {
+ super.setup(properties);
ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
- loadConstants(Settings.Global.getString(resolver, TARE_JOB_SCHEDULER_CONSTANTS));
+ loadConstants(Settings.Global.getString(resolver, TARE_JOB_SCHEDULER_CONSTANTS),
+ properties);
}
@Override
@@ -211,7 +212,8 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
return mRewards.get(rewardId);
}
- private void loadConstants(String policyValuesString) {
+ private void loadConstants(String policyValuesString,
+ @Nullable DeviceConfig.Properties properties) {
mActions.clear();
mRewards.clear();
@@ -221,118 +223,153 @@ public class JobSchedulerEconomicPolicy extends EconomicPolicy {
Slog.e(TAG, "Global setting key incorrect: ", e);
}
- mMinSatiatedBalanceExempted = arcToCake(
- mParser.getInt(KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED,
- DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED));
- mMinSatiatedBalanceOther = arcToCake(
- mParser.getInt(KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP,
- DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP));
- mMaxSatiatedBalance = arcToCake(mParser.getInt(KEY_JS_MAX_SATIATED_BALANCE,
- DEFAULT_JS_MAX_SATIATED_BALANCE));
- mInitialSatiatedConsumptionLimit = arcToCake(mParser.getInt(
- KEY_JS_INITIAL_CONSUMPTION_LIMIT, DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT));
+ mMinSatiatedBalanceExempted = getConstantAsCake(mParser, properties,
+ KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED,
+ DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES);
+ mMinSatiatedBalanceOther = getConstantAsCake(mParser, properties,
+ KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP,
+ DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES);
+ mMaxSatiatedBalance = getConstantAsCake(mParser, properties,
+ KEY_JS_MAX_SATIATED_BALANCE,
+ DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES);
+ mInitialSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
+ KEY_JS_INITIAL_CONSUMPTION_LIMIT,
+ DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES);
mHardSatiatedConsumptionLimit = Math.max(mInitialSatiatedConsumptionLimit,
- arcToCake(mParser.getInt(
- KEY_JS_HARD_CONSUMPTION_LIMIT, DEFAULT_JS_HARD_CONSUMPTION_LIMIT)));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_HARD_CONSUMPTION_LIMIT,
+ DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES));
mActions.put(ACTION_JOB_MAX_START, new Action(ACTION_JOB_MAX_START,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_MAX_START_CTP,
- DEFAULT_JS_ACTION_JOB_MAX_START_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_MAX_START_CTP,
+ DEFAULT_JS_ACTION_JOB_MAX_START_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE_CAKES)));
mActions.put(ACTION_JOB_MAX_RUNNING, new Action(ACTION_JOB_MAX_RUNNING,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_MAX_RUNNING_CTP,
- DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_MAX_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE_CAKES)));
mActions.put(ACTION_JOB_HIGH_START, new Action(ACTION_JOB_HIGH_START,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_START_CTP,
- DEFAULT_JS_ACTION_JOB_HIGH_START_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_HIGH_START_CTP,
+ DEFAULT_JS_ACTION_JOB_HIGH_START_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE_CAKES)));
mActions.put(ACTION_JOB_HIGH_RUNNING, new Action(ACTION_JOB_HIGH_RUNNING,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP,
- DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE_CAKES)));
mActions.put(ACTION_JOB_DEFAULT_START, new Action(ACTION_JOB_DEFAULT_START,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_START_CTP,
- DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_DEFAULT_START_CTP,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE_CAKES)));
mActions.put(ACTION_JOB_DEFAULT_RUNNING, new Action(ACTION_JOB_DEFAULT_RUNNING,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP,
- DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE_CAKES)));
mActions.put(ACTION_JOB_LOW_START, new Action(ACTION_JOB_LOW_START,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_LOW_START_CTP,
- DEFAULT_JS_ACTION_JOB_LOW_START_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_LOW_START_CTP,
+ DEFAULT_JS_ACTION_JOB_LOW_START_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE_CAKES)));
mActions.put(ACTION_JOB_LOW_RUNNING, new Action(ACTION_JOB_LOW_RUNNING,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_LOW_RUNNING_CTP,
- DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_LOW_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE_CAKES)));
mActions.put(ACTION_JOB_MIN_START, new Action(ACTION_JOB_MIN_START,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_MIN_START_CTP,
- DEFAULT_JS_ACTION_JOB_MIN_START_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_MIN_START_CTP,
+ DEFAULT_JS_ACTION_JOB_MIN_START_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE_CAKES)));
mActions.put(ACTION_JOB_MIN_RUNNING, new Action(ACTION_JOB_MIN_RUNNING,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_MIN_RUNNING_CTP,
- DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_MIN_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE_CAKES)));
mActions.put(ACTION_JOB_TIMEOUT, new Action(ACTION_JOB_TIMEOUT,
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP,
- DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP)),
- arcToCake(mParser.getInt(KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP,
+ DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE_CAKES)));
mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
- arcToCake(mParser.getInt(KEY_JS_REWARD_TOP_ACTIVITY_INSTANT,
- DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT)),
- (long) (arcToCake(1) * mParser.getFloat(KEY_JS_REWARD_TOP_ACTIVITY_ONGOING,
- DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING)),
- arcToCake(mParser.getInt(KEY_JS_REWARD_TOP_ACTIVITY_MAX,
- DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_TOP_ACTIVITY_INSTANT,
+ DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_TOP_ACTIVITY_ONGOING,
+ DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_TOP_ACTIVITY_MAX,
+ DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX_CAKES)));
mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
- arcToCake(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT,
- DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT)),
- arcToCake(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING,
- DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING)),
- arcToCake(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_MAX,
- DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT,
+ DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING,
+ DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_NOTIFICATION_SEEN_MAX,
+ DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX_CAKES)));
mRewards.put(REWARD_NOTIFICATION_INTERACTION,
new Reward(REWARD_NOTIFICATION_INTERACTION,
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT,
- DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT)),
- arcToCake(mParser.getInt(
+ DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING,
- DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING)),
- arcToCake(mParser.getInt(
+ DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX,
- DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX))));
+ DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES)));
mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
- arcToCake(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT,
- DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT)),
- arcToCake(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING,
- DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING)),
- arcToCake(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_MAX,
- DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX))));
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT,
+ DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING,
+ DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_WIDGET_INTERACTION_MAX,
+ DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX_CAKES)));
mRewards.put(REWARD_OTHER_USER_INTERACTION,
new Reward(REWARD_OTHER_USER_INTERACTION,
- arcToCake(mParser.getInt(KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT,
- DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT)),
- arcToCake(mParser.getInt(
+ getConstantAsCake(mParser, properties,
+ KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT,
+ DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING,
- DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING)),
- arcToCake(mParser.getInt(
+ DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES),
+ getConstantAsCake(mParser, properties,
KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX,
- DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX))));
+ DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX_CAKES)));
}
@Override
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/README.md b/apex/jobscheduler/service/java/com/android/server/tare/README.md
index 72d506972dd1..e338ed1c6987 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/README.md
+++ b/apex/jobscheduler/service/java/com/android/server/tare/README.md
@@ -18,16 +18,17 @@ The key tenets of TARE are:
In an ideal world, the system could be said to most efficiently allocate resources by maximizing its
profits &mdash; by maximizing the aggregate sum of the difference between an action's price (that
the app ends up paying) and the cost to produce by the system. This assumes that more important
-actions have a higher price than less important actions. With this assumption, maximizing profits
-implies that the system runs the most important work first and proceeds in decreasing order of
-importance. Of course, that also means the system will not run anything where an app would pay less
-for the action than the system's cost to produce that action. Some of this breaks down when we throw
-TOP apps into the mix &mdash; TOP apps pay 0 for all actions, even though the CTP may be greater
-than 0. This is to ensure ideal user experience for the app the user is actively interacting with.
-Similar caveats exist for system-critical processes (such as the OS itself) and apps running
-foreground services (since those could be critical to user experience, as is the case for media and
-navigation apps). Excluding those caveats/special situations, maximizing profits of actions
-performed by apps in the background should be the target.
+actions have a higher price than less important actions and all actors have perfect information and
+convey that information accurately. With these assumptions, maximizing profits implies that the
+system runs the most important work first and proceeds in decreasing order of importance. Of course,
+that also means the system will not run anything where an app would pay less for the action than the
+system's cost to produce that action. Some of this breaks down when we throw TOP apps into the mix
+&mdash; TOP apps pay 0 for all actions, even though the CTP may be greater than 0. This is to ensure
+ideal user experience for the app the user is actively interacting with. Similar caveats exist for
+system-critical processes (such as the OS itself) and apps running foreground services (since those
+could be critical to user experience, as is the case for media and navigation apps). Excluding those
+caveats/special situations, maximizing profits of actions performed by apps in the background should
+be the target.
To achieve the goal laid out by TARE, we use Android Resource Credits (ARCs for short) as the
internal/representative currency of the system.
@@ -101,11 +102,37 @@ Tare Improvement Proposal #1 (TIP1) separated allocation (to apps) from supply (
allowed apps to accrue credits as appropriate while still limiting the total number of credits
consumed.
+# Potential Future Changes
+
+These are some ideas for further changes. There's no guarantee that they'll be implemented.
+
+* Include additional components and policies for them. TARE may benefit from adding policies for
+ components such as broadcast dispatching, network traffic, location requests, and sensor usage.
+* Have a separate "account" for critical/special actions. In other words, have two accounts for each
+ app, where one acts like a special savings account and is only allowed to be used for special
+ actions such as expedited job execution. The second account would have a lower maximum than the
+ main account, but would help to make sure that normal actions don't interfere too much with more
+ critical actions.
+* Transferring credits from one app to another. For apps that rely on others for some pieces of
+ work, it may be beneficial to allow the requesting app to transfer, donate, or somehow make
+ available some of its own credits to the app doing the work in order to make sure the working app
+ has enough credits available to do the work.
+* Formulate values based on device hardware. For example, adjust the consumption limit based on the
+ battery size, or the price and/or CTP of actions based on hardware efficiency.
+* Price discovery via an auction system. Instead of just setting a fixed price that may be modified
+ by device and app states, let an app say how much it's willing to pay for a specific action and
+ then have a small auction when the system needs to decide which app to perform the action for
+ first or how much to charge the app.
+
# Definitions
* ARC: Android Resource Credits are the "currency" units used as an abstraction layer over the real
battery drain. They allow the system to standardize costs and prices across various devices.
* Cake: A lie; also the smallest unit of an ARC (1 cake = one-billionth of an ARC = 1 nano-ARC).
When the apps request to do something, we shall let them eat cake.
-* NARC: The smallest unit of an ARC. A narc is 1 nano-ARC.
+* Cost to produce (CTP): An economic term that refers to the total cost incurred by a business to
+ produce a specific quantity of a product or offer a service. In TARE's context, CTP is meant to be
+ the estimated cost t ohe system to accomplish a certain action. These "actions" are basically APIs
+ that apps use to get something done. So the idea is to define the base cost for an app to use a
+ specific API.
* Satiated: used to refer to when the device is fully charged (at 100% battery level) \ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
index 87db8637ddac..6b6984f6ac17 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
@@ -16,6 +16,8 @@
package com.android.server.tare;
+import static android.app.tare.EconomyManager.CAKE_IN_ARC;
+
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.util.IndentingPrintWriter;
@@ -26,8 +28,6 @@ import java.text.SimpleDateFormat;
import java.time.Clock;
class TareUtils {
- private static final long CAKE_IN_ARC = 1_000_000_000L;
-
@SuppressLint("SimpleDateFormat")
private static final SimpleDateFormat sDumpDateFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
@@ -35,10 +35,6 @@ class TareUtils {
@VisibleForTesting
static Clock sSystemClock = Clock.systemUTC();
- static long arcToCake(int arcs) {
- return arcs * CAKE_IN_ARC;
- }
-
static void dumpTime(IndentingPrintWriter pw, long time) {
pw.print(sDumpDateFormat.format(time));
}
@@ -56,7 +52,7 @@ class TareUtils {
if (cakes == 0) {
return "0 ARCs";
}
- final long sub = Math.abs(cakes) % CAKE_IN_ARC;
+ final long sub = cakes % CAKE_IN_ARC;
final long arcs = cakeToArc(cakes);
if (arcs == 0) {
return sub == 1
@@ -65,11 +61,11 @@ class TareUtils {
}
StringBuilder sb = new StringBuilder();
sb.append(arcs);
- if (sub > 0) {
- sb.append(".").append(sub / (CAKE_IN_ARC / 1000));
+ if (sub != 0) {
+ sb.append(".").append(String.format("%03d", Math.abs(sub) / (CAKE_IN_ARC / 1000)));
}
sb.append(" ARC");
- if (arcs != 1 || sub > 0) {
+ if (arcs != 1 || sub != 0) {
sb.append("s");
}
return sb.toString();
diff --git a/api/api.go b/api/api.go
index 9aac879b4eae..ce8cd1426661 100644
--- a/api/api.go
+++ b/api/api.go
@@ -208,12 +208,6 @@ func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) {
props := libraryProps{}
props.Name = proptools.StringPtr("all-framework-module-impl")
props.Static_libs = transformArray(modules, "", ".impl")
- // Media module's impl jar is called "updatable-media"
- for i, v := range props.Static_libs {
- if v == "framework-media.impl" {
- props.Static_libs[i] = "updatable-media"
- }
- }
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
ctx.CreateModule(java.LibraryFactory, &props)
diff --git a/core/api/module-lib-lint-baseline.txt b/core/api/module-lib-lint-baseline.txt
index 0c1ebb3b2208..27436ce35867 100644
--- a/core/api/module-lib-lint-baseline.txt
+++ b/core/api/module-lib-lint-baseline.txt
@@ -1,4 +1,6 @@
// Baseline format: 1.0
+SamShouldBeLast: android.app.Activity#convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions):
+ SAM-compatible parameters (such as parameter 1, "callback", in android.app.Activity.convertToTranslucent) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int):
SAM-compatible parameters (such as parameter 1, "listener", in android.app.ActivityManager.addOnUidImportanceListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler):
@@ -9,6 +11,24 @@ SamShouldBeLast: android.app.PendingIntent#send(android.content.Context, int, an
SAM-compatible parameters (such as parameter 4, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.app.PendingIntent#send(int, android.app.PendingIntent.OnFinished, android.os.Handler):
SAM-compatible parameters (such as parameter 2, "onFinished", in android.app.PendingIntent.send) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.content.pm.ApplicationInfo#dump(android.util.Printer, String):
+ SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ApplicationInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.content.pm.PackageItemInfo#dumpBack(android.util.Printer, String):
+ SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpBack) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.content.pm.PackageItemInfo#dumpFront(android.util.Printer, String):
+ SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpFront) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
+ SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper):
+ SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
+ SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
+ SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
+ SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.AudioManager#abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes):
SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.abandonAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int):
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index 1b45e88584fe..025e8629fc20 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -1,36 +1,20 @@
// Baseline format: 1.0
ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
-
-ExecutorRegistration: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler):
- Registration methods should have overload that accepts delivery Executor: `setOnRtpRxNoticeListener`
+ Method should return Collection<CharSequence> (or subclass) instead of raw array; was `java.lang.CharSequence[]`
GenericException: android.app.prediction.AppPredictor#finalize():
-
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
GenericException: android.hardware.location.ContextHubClient#finalize():
-
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
GenericException: android.service.autofill.augmented.FillWindow#finalize():
-
-
-
-IntentBuilderName: android.app.search.SearchAction#getIntent():
-
-IntentBuilderName: android.app.smartspace.SmartspaceAction#getIntent():
- Methods creating an Intent should be named `create<Foo>Intent()`, was `getIntent`
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
KotlinKeyword: android.app.Notification#when:
-
+ Avoid field names that are Kotlin hard keywords ("when"); see https://android.github.io/kotlin-guides/interop.html#no-hard-keywords
-MissingGetterMatchingBuilder: android.os.NewUserRequest.Builder#setAdmin():
- android.os.NewUserRequest does not declare a `getAdmin()` method matching method android.os.NewUserRequest.Builder.setAdmin()
-MissingGetterMatchingBuilder: android.os.NewUserRequest.Builder#setEphemeral():
- android.os.NewUserRequest does not declare a `getEphemeral()` method matching method android.os.NewUserRequest.Builder.setEphemeral()
-MissingGetterMatchingBuilder: android.security.keystore.KeyGenParameterSpec.Builder#setUid(int):
- android.security.keystore.KeyGenParameterSpec does not declare a `getUid()` method matching method android.security.keystore.KeyGenParameterSpec.Builder.setUid(int)
-MissingGetterMatchingBuilder: android.service.autofill.Dataset.Builder#setFieldInlinePresentation(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.service.autofill.InlinePresentation):
- android.service.autofill.Dataset does not declare a `getFieldInlinePresentation()` method matching method android.service.autofill.Dataset.Builder.setFieldInlinePresentation(android.view.autofill.AutofillId,android.view.autofill.AutofillValue,java.util.regex.Pattern,android.service.autofill.InlinePresentation)
MissingGetterMatchingBuilder: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallViaAudioProcessing(boolean):
android.telecom.CallScreeningService.CallResponse does not declare a `shouldScreenCallViaAudioProcessing()` method matching method android.telecom.CallScreeningService.CallResponse.Builder.setShouldScreenCallViaAudioProcessing(boolean)
MissingGetterMatchingBuilder: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
@@ -38,175 +22,135 @@ MissingGetterMatchingBuilder: android.telephony.mbms.DownloadRequest.Builder#set
MissingNullability: android.media.soundtrigger.SoundTriggerDetectionService#onUnbind(android.content.Intent) parameter #0:
-
+ Missing nullability on parameter `intent` in method `onUnbind`
MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #0:
-
+ Missing nullability on parameter `inputId` in method `onEvent`
MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #1:
-
+ Missing nullability on parameter `eventType` in method `onEvent`
MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #2:
-
+ Missing nullability on parameter `eventArgs` in method `onEvent`
MissingNullability: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context) parameter #0:
-
+ Missing nullability on parameter `base` in method `attachBaseContext`
MissingNullability: android.provider.ContactsContract.MetadataSync#CONTENT_URI:
-
+ Missing nullability on field `CONTENT_URI` in class `class android.provider.ContactsContract.MetadataSync`
MissingNullability: android.provider.ContactsContract.MetadataSync#METADATA_AUTHORITY_URI:
-
+ Missing nullability on field `METADATA_AUTHORITY_URI` in class `class android.provider.ContactsContract.MetadataSync`
MissingNullability: android.provider.ContactsContract.MetadataSyncState#CONTENT_URI:
-
+ Missing nullability on field `CONTENT_URI` in class `class android.provider.ContactsContract.MetadataSyncState`
MissingNullability: android.provider.SearchIndexablesProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #0:
-
+ Missing nullability on parameter `context` in method `attachInfo`
MissingNullability: android.provider.SearchIndexablesProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #1:
-
+ Missing nullability on parameter `info` in method `attachInfo`
MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#onUnbind(android.content.Intent) parameter #0:
-
+ Missing nullability on parameter `intent` in method `onUnbind`
MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
-
+ Missing nullability on parameter `fd` in method `dump`
MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
-
+ Missing nullability on parameter `pw` in method `dump`
MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
-
+ Missing nullability on parameter `args` in method `dump`
MissingNullability: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context) parameter #0:
-
+ Missing nullability on parameter `base` in method `attachBaseContext`
MissingNullability: android.telephony.NetworkService#onUnbind(android.content.Intent) parameter #0:
-
-MissingNullability: android.telephony.SubscriptionPlan.Builder#createRecurringDaily(java.time.ZonedDateTime) parameter #0:
-
-MissingNullability: android.telephony.SubscriptionPlan.Builder#createRecurringMonthly(java.time.ZonedDateTime) parameter #0:
-
-MissingNullability: android.telephony.SubscriptionPlan.Builder#createRecurringWeekly(java.time.ZonedDateTime) parameter #0:
-
+ Missing nullability on parameter `intent` in method `onUnbind`
MissingNullability: android.telephony.data.DataService#onUnbind(android.content.Intent) parameter #0:
-
+ Missing nullability on parameter `intent` in method `onUnbind`
MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
-
+ Missing nullability on method `setServiceId` return
MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String) parameter #0:
-
-
-
-NoSettingsProvider: android.provider.Settings.Secure#FAST_PAIR_SCAN_ENABLED:
- New setting keys are not allowed (Field: FAST_PAIR_SCAN_ENABLED); use getters/setters in relevant manager class
-
-
-OnNameExpected: android.service.smartspace.SmartspaceService#notifySmartspaceEvent(android.app.smartspace.SmartspaceSessionId, android.app.smartspace.SmartspaceTargetEvent):
- Methods implemented by developers should follow the on<Something> style, was `notifySmartspaceEvent`
+ Missing nullability on parameter `serviceId` in method `setServiceId`
ProtectedMember: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context):
-
+ Protected methods not allowed; must be public: method android.printservice.recommendation.RecommendationService.attachBaseContext(android.content.Context)}
ProtectedMember: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
-
+ Protected methods not allowed; must be public: method android.service.contentcapture.ContentCaptureService.dump(java.io.FileDescriptor,java.io.PrintWriter,String[])}
ProtectedMember: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
-
-
-
-RethrowRemoteException: android.app.WallpaperManager#getWallpaperDimAmount():
- Methods calling system APIs should rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
-RethrowRemoteException: android.app.WallpaperManager#getWallpaperDimmingAmount():
- Methods calling system APIs should rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
-RethrowRemoteException: android.app.WallpaperManager#setWallpaperDimAmount(float):
- Methods calling system APIs should rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
-RethrowRemoteException: android.app.WallpaperManager#setWallpaperDimmingAmount(float):
- Methods calling system APIs should rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
+ Protected methods not allowed; must be public: method android.service.notification.NotificationAssistantService.attachBaseContext(android.content.Context)}
SamShouldBeLast: android.accounts.AccountManager#addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 6, "callback", in android.accounts.AccountManager.addAccount) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.accounts.AccountManager.addOnAccountsUpdatedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, String[]):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.accounts.AccountManager.addOnAccountsUpdatedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 4, "callback", in android.accounts.AccountManager.confirmCredentials) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#editProperties(String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 3, "callback", in android.accounts.AccountManager.editProperties) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 3, "callback", in android.accounts.AccountManager.finishSession) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 3, "callback", in android.accounts.AccountManager.getAccountsByTypeAndFeatures) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#getAuthToken(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 5, "callback", in android.accounts.AccountManager.getAuthToken) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#getAuthToken(android.accounts.Account, String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 5, "callback", in android.accounts.AccountManager.getAuthToken) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#getAuthToken(android.accounts.Account, String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 4, "callback", in android.accounts.AccountManager.getAuthToken) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#getAuthTokenByFeatures(String, String, String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 7, "callback", in android.accounts.AccountManager.getAuthTokenByFeatures) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 3, "callback", in android.accounts.AccountManager.hasFeatures) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#isCredentialsUpdateSuggested(android.accounts.Account, String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 3, "callback", in android.accounts.AccountManager.isCredentialsUpdateSuggested) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 2, "callback", in android.accounts.AccountManager.removeAccount) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 3, "callback", in android.accounts.AccountManager.removeAccount) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#renameAccount(android.accounts.Account, String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 3, "callback", in android.accounts.AccountManager.renameAccount) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#startAddAccountSession(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 6, "callback", in android.accounts.AccountManager.startAddAccountSession) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#startUpdateCredentialsSession(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 5, "callback", in android.accounts.AccountManager.startUpdateCredentialsSession) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.accounts.AccountManager#updateCredentials(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 5, "callback", in android.accounts.AccountManager.updateCredentials) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.app.AlarmManager#set(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 4, "listener", in android.app.AlarmManager.set) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.app.AlarmManager#setExact(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 4, "listener", in android.app.AlarmManager.setExact) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.app.AlarmManager#setWindow(int, long, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 5, "listener", in android.app.AlarmManager.setWindow) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.app.WallpaperInfo#dump(android.util.Printer, String):
-
+ SAM-compatible parameters (such as parameter 1, "pw", in android.app.WallpaperInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.app.WallpaperManager#addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler):
-
-SamShouldBeLast: android.app.admin.DevicePolicyManager#installSystemUpdate(android.content.ComponentName, android.net.Uri, java.util.concurrent.Executor, android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.app.WallpaperManager.addOnColorsChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.content.IntentFilter#dump(android.util.Printer, String):
-
+ SAM-compatible parameters (such as parameter 1, "du", in android.content.IntentFilter.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.content.pm.ApplicationInfo#dump(android.util.Printer, String):
-
+ SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ApplicationInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.content.pm.PackageItemInfo#dumpBack(android.util.Printer, String):
-
+ SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpBack) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.content.pm.PackageItemInfo#dumpFront(android.util.Printer, String):
-
+ SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpFront) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.content.pm.ResolveInfo#dump(android.util.Printer, String):
-
+ SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ResolveInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.Location#dump(android.util.Printer, String):
-
+ SAM-compatible parameters (such as parameter 1, "pw", in android.location.Location.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
-
-SamShouldBeLast: android.location.LocationManager#registerGnssMeasurementsCallback(java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
-
-SamShouldBeLast: android.location.LocationManager#registerGnssNavigationMessageCallback(java.util.concurrent.Executor, android.location.GnssNavigationMessage.Callback):
-
-SamShouldBeLast: android.location.LocationManager#registerGnssStatusCallback(java.util.concurrent.Executor, android.location.GnssStatus.Callback):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
-
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, java.util.concurrent.Executor, android.location.LocationListener):
-
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, java.util.concurrent.Executor, android.location.LocationListener):
-
+ SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
-
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, java.util.concurrent.Executor, android.location.LocationListener):
-
+ SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
-
+ SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
-
+ SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.AudioFocusRequest.Builder#setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioFocusRequest.Builder.setOnAudioFocusChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int):
-
+ SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.requestAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.AudioRecord#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
-SamShouldBeLast: android.media.AudioRecord#registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback):
-
-SamShouldBeLast: android.media.AudioRecordingMonitor#registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioRecord.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.AudioRouting#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioRouting.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.AudioTrack#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioTrack.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.media.MediaCodec#setOnFrameRenderedListener(android.media.MediaCodec.OnFrameRenderedListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaCodec.setOnFrameRenderedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.MediaPlayer#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaPlayer.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.MediaPlayer#setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler):
@@ -215,82 +159,65 @@ SamShouldBeLast: android.media.MediaPlayer#setOnDrmPreparedListener(android.medi
SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaPlayer.setOnDrmPreparedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.MediaPlayer#setOnMediaTimeDiscontinuityListener(android.media.MediaPlayer.OnMediaTimeDiscontinuityListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaPlayer.setOnMediaTimeDiscontinuityListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler):
- SAM-compatible parameters (such as parameter 2, "listener", in android.media.MediaPlayer.setOnRtpRxNoticeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.MediaPlayer#setOnSubtitleDataListener(android.media.MediaPlayer.OnSubtitleDataListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaPlayer.setOnSubtitleDataListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.MediaRecorder#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
-SamShouldBeLast: android.media.MediaRecorder#registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaRecorder.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName):
-
+ SAM-compatible parameters (such as parameter 1, "sessionListener", in android.media.session.MediaSessionManager.addOnActiveSessionsChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 1, "sessionListener", in android.media.session.MediaSessionManager.addOnActiveSessionsChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.session.MediaSessionManager#addOnSession2TokensChangedListener(android.media.session.MediaSessionManager.OnSession2TokensChangedListener, android.os.Handler):
-
-SamShouldBeLast: android.media.session.MediaSessionManager#registerCallback(java.util.concurrent.Executor, android.media.session.MediaSessionManager.Callback):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.media.session.MediaSessionManager.addOnSession2TokensChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.nfc.NfcAdapter#enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle):
-
+ SAM-compatible parameters (such as parameter 2, "callback", in android.nfc.NfcAdapter.enableReaderMode) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.nfc.NfcAdapter#ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 3, "tagRemovedListener", in android.nfc.NfcAdapter.ignore) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.nfc.NfcAdapter#setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity):
-
+ SAM-compatible parameters (such as parameter 1, "callback", in android.nfc.NfcAdapter.setBeamPushUrisCallback) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.nfc.NfcAdapter#setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...):
-
+ SAM-compatible parameters (such as parameter 1, "callback", in android.nfc.NfcAdapter.setNdefPushMessageCallback) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.nfc.NfcAdapter#setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...):
-
+ SAM-compatible parameters (such as parameter 1, "callback", in android.nfc.NfcAdapter.setOnNdefPushCompleteCallback) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Binder#attachInterface(android.os.IInterface, String):
-
+ SAM-compatible parameters (such as parameter 1, "owner", in android.os.Binder.attachInterface) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Binder#linkToDeath(android.os.IBinder.DeathRecipient, int):
-
+ SAM-compatible parameters (such as parameter 1, "recipient", in android.os.Binder.linkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Binder#unlinkToDeath(android.os.IBinder.DeathRecipient, int):
-
+ SAM-compatible parameters (such as parameter 1, "recipient", in android.os.Binder.unlinkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Handler#dump(android.util.Printer, String):
-
+ SAM-compatible parameters (such as parameter 1, "pw", in android.os.Handler.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Handler#postAtTime(Runnable, Object, long):
-
+ SAM-compatible parameters (such as parameter 1, "r", in android.os.Handler.postAtTime) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Handler#postAtTime(Runnable, long):
-
+ SAM-compatible parameters (such as parameter 1, "r", in android.os.Handler.postAtTime) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Handler#postDelayed(Runnable, Object, long):
-
+ SAM-compatible parameters (such as parameter 1, "r", in android.os.Handler.postDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Handler#postDelayed(Runnable, long):
-
+ SAM-compatible parameters (such as parameter 1, "r", in android.os.Handler.postDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Handler#removeCallbacks(Runnable, Object):
-
+ SAM-compatible parameters (such as parameter 1, "r", in android.os.Handler.removeCallbacks) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.IBinder#linkToDeath(android.os.IBinder.DeathRecipient, int):
-
+ SAM-compatible parameters (such as parameter 1, "recipient", in android.os.IBinder.linkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.IBinder#unlinkToDeath(android.os.IBinder.DeathRecipient, int):
-
+ SAM-compatible parameters (such as parameter 1, "recipient", in android.os.IBinder.unlinkToDeath) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.RecoverySystem#verifyPackage(java.io.File, android.os.RecoverySystem.ProgressListener, java.io.File):
-
+ SAM-compatible parameters (such as parameter 2, "listener", in android.os.RecoverySystem.verifyPackage) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.security.KeyChain#choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, String[], java.security.Principal[], String, int, String):
SAM-compatible parameters (such as parameter 2, "response", in android.security.KeyChain.choosePrivateKeyAlias) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.security.KeyChain#choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, String[], java.security.Principal[], android.net.Uri, String):
SAM-compatible parameters (such as parameter 2, "response", in android.security.KeyChain.choosePrivateKeyAlias) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.View#postDelayed(Runnable, long):
-
+ SAM-compatible parameters (such as parameter 1, "action", in android.view.View.postDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.View#postOnAnimationDelayed(Runnable, long):
-
+ SAM-compatible parameters (such as parameter 1, "action", in android.view.View.postOnAnimationDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.View#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long):
-
+ SAM-compatible parameters (such as parameter 2, "what", in android.view.View.scheduleDrawable) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.Window#addOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.view.Window.addOnFrameMetricsAvailableListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.accessibility.AccessibilityManager#addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addAccessibilityStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.accessibility.AccessibilityManager#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addTouchExplorationStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams):
-
-
-
-ServiceName: android.content.Context#CLOUDSEARCH_SERVICE:
-
-
-UserHandleName: android.app.search.SearchAction.Builder#setUserHandle(android.os.UserHandle):
- Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `setUserHandle`
-UserHandleName: android.app.search.SearchTarget.Builder#setUserHandle(android.os.UserHandle):
-
-UserHandleName: android.app.smartspace.SmartspaceAction.Builder#setUserHandle(android.os.UserHandle):
- Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `setUserHandle`
+ SAM-compatible parameters (such as parameter 2, "filePathCallback", in android.webkit.WebChromeClient.onShowFileChooser) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 01604e6becf0..0a906bee6fad 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -1,920 +1,270 @@
// Baseline format: 1.0
AcronymName: android.app.NotificationChannel#isImportanceLockedByOEM():
-
+ Acronyms should not be capitalized in method names: was `isImportanceLockedByOEM`, should this be `isImportanceLockedByOem`?
AcronymName: android.app.NotificationChannel#setImportanceLockedByOEM(boolean):
-
-
-
-ActionValue: android.location.Location#EXTRA_NO_GPS_LOCATION:
-
-ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED:
-
-ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER:
-
-ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER:
-
-ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_ADDITIONAL_CALL_INFO:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CALL_RAT_TYPE:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CHILD_NUMBER:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CNA:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CNAP:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CODEC:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_DIALSTRING:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_DISPLAY_TEXT:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_EMERGENCY_CALL:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_IS_CALL_PULL:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_OI:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_OIR:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_REMOTE_URI:
-
-ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_USSD:
-
-ActionValue: android.telephony.ims.ImsReasonInfo#EXTRA_MSG_SERVICE_NOT_AUTHORIZED:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_CLEANUP:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_DOWNLOAD_RESULT_INTERNAL:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_FILE_DESCRIPTOR_REQUEST:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_FD_COUNT:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_FINAL_URI:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_FREE_URI_LIST:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_PAUSED_LIST:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_PAUSED_URI_LIST:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_SERVICE_ID:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_TEMP_FILES_IN_USE:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_TEMP_FILE_ROOT:
-
-ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_TEMP_LIST:
-
-
-
-AllUpper: android.media.audiopolicy.AudioProductStrategy#sDefaultAttributes:
- Constant field names must be named with only upper case characters: `android.media.audiopolicy.AudioProductStrategy#sDefaultAttributes`, should be `S_DEFAULT_ATTRIBUTES`?
-
-
-ArrayReturn: android.app.UiAutomation#executeShellCommandRw(String):
-
-ArrayReturn: android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel#KeyphraseSoundModel(java.util.UUID, java.util.UUID, byte[], android.hardware.soundtrigger.SoundTrigger.Keyphrase[]) parameter #3:
-
-ArrayReturn: android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel#KeyphraseSoundModel(java.util.UUID, java.util.UUID, byte[], android.hardware.soundtrigger.SoundTrigger.Keyphrase[], int) parameter #3:
-
-ArrayReturn: android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel#getKeyphrases():
-
-ArrayReturn: android.location.GnssMeasurementsEvent#GnssMeasurementsEvent(android.location.GnssClock, android.location.GnssMeasurement[]) parameter #1:
-
+ Acronyms should not be capitalized in method names: was `setImportanceLockedByOEM`, should this be `setImportanceLockedByOem`?
+
+
ArrayReturn: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #10:
-
+ Method parameter should be Collection<Descriptor> (or subclass) instead of raw array; was `android.media.audiofx.AudioEffect.Descriptor[]`
ArrayReturn: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #11:
-
-ArrayReturn: android.metrics.LogMaker#LogMaker(Object[]) parameter #0:
-
-ArrayReturn: android.metrics.LogMaker#deserialize(Object[]) parameter #0:
-
-ArrayReturn: android.metrics.LogMaker#serialize():
-
-ArrayReturn: android.net.TestNetworkManager#createTunInterface(android.net.LinkAddress[]) parameter #0:
-
-ArrayReturn: android.os.HwBlob#wrapArray(boolean[]):
-
-ArrayReturn: android.os.HwBlob#wrapArray(byte[]):
-
-ArrayReturn: android.os.HwBlob#wrapArray(double[]):
-
-ArrayReturn: android.os.HwBlob#wrapArray(float[]):
-
-ArrayReturn: android.os.HwBlob#wrapArray(int[]):
-
-ArrayReturn: android.os.HwBlob#wrapArray(long[]):
-
-ArrayReturn: android.os.HwBlob#wrapArray(short[]):
-
-ArrayReturn: android.os.NativeHandle#NativeHandle(java.io.FileDescriptor[], int[], boolean) parameter #0:
-
-ArrayReturn: android.os.NativeHandle#getFileDescriptors():
-
-ArrayReturn: android.security.keystore.AttestationUtils#attestDeviceIds(android.content.Context, int[], byte[]):
-
-ArrayReturn: android.telephony.ims.ImsUtListener#onUtConfigurationCallBarringQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
-
-ArrayReturn: android.telephony.ims.ImsUtListener#onUtConfigurationCallForwardQueried(int, android.telephony.ims.ImsCallForwardInfo[]) parameter #1:
-
-ArrayReturn: android.telephony.ims.ImsUtListener#onUtConfigurationCallWaitingQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
-
-ArrayReturn: android.telephony.ims.stub.ImsRegistrationImplBase#onSubscriberAssociatedUriChanged(android.net.Uri[]) parameter #0:
-
+ Method parameter should be Collection<Descriptor> (or subclass) instead of raw array; was `android.media.audiofx.AudioEffect.Descriptor[]`
ArrayReturn: android.view.Display#getSupportedWideColorGamut():
-
+ Method should return Collection<ColorSpace> (or subclass) instead of raw array; was `android.graphics.ColorSpace[]`
ArrayReturn: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #0:
-
-ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
-
+ Method parameter should be Collection<View> (or subclass) instead of raw array; was `android.view.View[]`
ArrayReturn: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillOptions(CharSequence[]) parameter #0:
-
-ArrayReturn: android.view.inspector.InspectableProperty#enumMapping():
-
-ArrayReturn: android.view.inspector.InspectableProperty#flagMapping():
-
-
-
-AutoBoxing: android.os.HwBlob#wrapArray(byte[]):
-
-AutoBoxing: android.os.HwBlob#wrapArray(double[]):
-
-AutoBoxing: android.os.HwBlob#wrapArray(float[]):
-
-AutoBoxing: android.os.HwBlob#wrapArray(int[]):
-
-AutoBoxing: android.os.HwBlob#wrapArray(long[]):
-
-AutoBoxing: android.os.HwBlob#wrapArray(short[]):
-
-AutoBoxing: android.os.VintfObject#getTargetFrameworkCompatibilityMatrixVersion():
-
-
-
-BannedThrow: android.app.ActivityTaskManager#removeStacksInWindowingModes(int[]):
-
-BannedThrow: android.app.ActivityTaskManager#removeStacksWithActivityTypes(int[]):
-
-BannedThrow: android.app.ActivityTaskManager#setTaskWindowingMode(int, int, boolean):
-
-BannedThrow: android.app.ActivityTaskManager#setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean):
-
-BannedThrow: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]):
-
-BannedThrow: android.media.audiofx.AudioEffect#getParameter(int, byte[]):
-
-BannedThrow: android.media.audiofx.AudioEffect#getParameter(int, int[]):
-
-BannedThrow: android.media.audiofx.AudioEffect#getParameter(int, short[]):
-
-BannedThrow: android.media.audiofx.AudioEffect#getParameter(int[], short[]):
-
-BannedThrow: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]):
-
-BannedThrow: android.media.audiofx.AudioEffect#setParameter(int, byte[]):
-
-BannedThrow: android.media.audiofx.AudioEffect#setParameter(int, int):
-
-BannedThrow: android.media.audiofx.AudioEffect#setParameter(int, short):
-
-BannedThrow: android.media.audiofx.AudioEffect#setParameter(int[], byte[]):
-
-BannedThrow: android.media.audiofx.AudioEffect#setParameter(int[], int[]):
-
-BannedThrow: android.media.audiopolicy.AudioMix.Builder#Builder(android.media.audiopolicy.AudioMixingRule):
-
-BannedThrow: android.media.audiopolicy.AudioMix.Builder#build():
-
-BannedThrow: android.media.audiopolicy.AudioMix.Builder#setDevice(android.media.AudioDeviceInfo):
-
-BannedThrow: android.media.audiopolicy.AudioMix.Builder#setFormat(android.media.AudioFormat):
-
-BannedThrow: android.media.audiopolicy.AudioMix.Builder#setRouteFlags(int):
-
-BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#addMixRule(int, Object):
-
-BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#addRule(android.media.AudioAttributes, int):
-
-BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#excludeMixRule(int, Object):
-
-BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#excludeRule(android.media.AudioAttributes, int):
-
-BannedThrow: android.media.audiopolicy.AudioPolicy#createAudioRecordSink(android.media.audiopolicy.AudioMix):
-
-BannedThrow: android.media.audiopolicy.AudioPolicy#createAudioTrackSource(android.media.audiopolicy.AudioMix):
-
-BannedThrow: android.media.audiopolicy.AudioPolicy#setFocusDuckingBehavior(int):
-
-BannedThrow: android.media.audiopolicy.AudioPolicy.Builder#addMix(android.media.audiopolicy.AudioMix):
-
-BannedThrow: android.media.audiopolicy.AudioPolicy.Builder#setLooper(android.os.Looper):
-
-BannedThrow: android.os.HwBinder#getService(String, String):
-
-BannedThrow: android.os.HwBinder#getService(String, String, boolean):
-
-BannedThrow: android.os.Process#getThreadScheduler(int):
-
-
-
-BuilderSetStyle: android.media.audiopolicy.AudioMixingRule.Builder#allowPrivilegedPlaybackCapture(boolean):
-
-BuilderSetStyle: android.media.audiopolicy.AudioMixingRule.Builder#excludeMixRule(int, Object):
-
-BuilderSetStyle: android.media.audiopolicy.AudioMixingRule.Builder#excludeRule(android.media.AudioAttributes, int):
-
-BuilderSetStyle: android.net.NetworkCapabilities.Builder#removeCapability(int):
-
-BuilderSetStyle: android.net.NetworkCapabilities.Builder#removeTransportType(int):
-
-BuilderSetStyle: android.net.metrics.RaEvent.Builder#updateDnsslLifetime(long):
-
-BuilderSetStyle: android.net.metrics.RaEvent.Builder#updatePrefixPreferredLifetime(long):
-
-BuilderSetStyle: android.net.metrics.RaEvent.Builder#updatePrefixValidLifetime(long):
-
-BuilderSetStyle: android.net.metrics.RaEvent.Builder#updateRdnssLifetime(long):
-
-BuilderSetStyle: android.net.metrics.RaEvent.Builder#updateRouteInfoLifetime(long):
-
-BuilderSetStyle: android.net.metrics.RaEvent.Builder#updateRouterLifetime(long):
-
-BuilderSetStyle: android.os.StrictMode.ThreadPolicy.Builder#detectExplicitGc():
-
-BuilderSetStyle: android.os.StrictMode.VmPolicy.Builder#detectIncorrectContextUse():
-
-BuilderSetStyle: android.os.StrictMode.VmPolicy.Builder#permitIncorrectContextUse():
-
+ Method parameter should be Collection<CharSequence> (or subclass) instead of raw array; was `java.lang.CharSequence[]`
-CallbackInterface: android.app.prediction.AppPredictor.Callback:
-
-CallbackInterface: android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback:
-
-CallbackInterface: android.widget.Magnifier.Callback:
-
+AutoBoxing: android.os.VintfObject#getTargetFrameworkCompatibilityMatrixVersion():
+ Must avoid boxed primitives (`java.lang.Long`)
-CallbackMethodName: android.os.RemoteCallback:
-
+BuilderSetStyle: android.os.StrictMode.ThreadPolicy.Builder#detectExplicitGc():
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.os.StrictMode.ThreadPolicy.Builder.detectExplicitGc()
+BuilderSetStyle: android.os.StrictMode.VmPolicy.Builder#permitIncorrectContextUse():
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.os.StrictMode.VmPolicy.Builder.permitIncorrectContextUse()
ConcreteCollection: android.content.AutofillOptions#disabledActivities:
-
+ Field type is concrete collection (`android.util.ArrayMap`); must be higher-level interface
ConcreteCollection: android.content.AutofillOptions#whitelistedActivitiesForAugmentedAutofill:
-
+ Field type is concrete collection (`android.util.ArraySet`); must be higher-level interface
ConcreteCollection: android.content.ContentCaptureOptions#ContentCaptureOptions(int, int, int, int, int, android.util.ArraySet<android.content.ComponentName>) parameter #5:
-
+ Parameter type is concrete collection (`android.util.ArraySet`); must be higher-level interface
ConcreteCollection: android.content.ContentCaptureOptions#whitelistedComponents:
-
+ Field type is concrete collection (`android.util.ArraySet`); must be higher-level interface
ConcreteCollection: android.database.sqlite.SQLiteDebug.PagerStats#dbStats:
-
-ConcreteCollection: android.os.HwParcel#readBoolVector():
-
-ConcreteCollection: android.os.HwParcel#readDoubleVector():
-
-ConcreteCollection: android.os.HwParcel#readFloatVector():
-
-ConcreteCollection: android.os.HwParcel#readInt16Vector():
-
-ConcreteCollection: android.os.HwParcel#readInt32Vector():
-
-ConcreteCollection: android.os.HwParcel#readInt64Vector():
-
-ConcreteCollection: android.os.HwParcel#readInt8Vector():
-
-ConcreteCollection: android.os.HwParcel#readNativeHandleVector():
-
-ConcreteCollection: android.os.HwParcel#readStringVector():
-
-ConcreteCollection: android.os.HwParcel#writeBoolVector(java.util.ArrayList<java.lang.Boolean>) parameter #0:
-
-ConcreteCollection: android.os.HwParcel#writeDoubleVector(java.util.ArrayList<java.lang.Double>) parameter #0:
-
-ConcreteCollection: android.os.HwParcel#writeFloatVector(java.util.ArrayList<java.lang.Float>) parameter #0:
-
-ConcreteCollection: android.os.HwParcel#writeInt16Vector(java.util.ArrayList<java.lang.Short>) parameter #0:
-
-ConcreteCollection: android.os.HwParcel#writeInt32Vector(java.util.ArrayList<java.lang.Integer>) parameter #0:
-
-ConcreteCollection: android.os.HwParcel#writeInt64Vector(java.util.ArrayList<java.lang.Long>) parameter #0:
-
-ConcreteCollection: android.os.HwParcel#writeInt8Vector(java.util.ArrayList<java.lang.Byte>) parameter #0:
-
-ConcreteCollection: android.os.HwParcel#writeNativeHandleVector(java.util.ArrayList<android.os.NativeHandle>) parameter #0:
-
-ConcreteCollection: android.os.HwParcel#writeStringVector(java.util.ArrayList<java.lang.String>) parameter #0:
-
+ Field type is concrete collection (`java.util.ArrayList`); must be higher-level interface
ConcreteCollection: android.service.autofill.CompositeUserData#getFieldClassificationAlgorithms():
-
+ Return type is concrete collection (`android.util.ArrayMap`); must be higher-level interface
ConcreteCollection: android.service.autofill.CompositeUserData#getFieldClassificationArgs():
-
+ Return type is concrete collection (`android.util.ArrayMap`); must be higher-level interface
ConcreteCollection: android.service.autofill.InternalTransformation#batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>) parameter #2:
-
+ Parameter type is concrete collection (`java.util.ArrayList`); must be higher-level interface
ConcreteCollection: android.service.autofill.UserData#getFieldClassificationAlgorithms():
-
-ConcreteCollection: android.telephony.ims.ImsConferenceState#mParticipants:
-
+ Return type is concrete collection (`android.util.ArrayMap`); must be higher-level interface
ContextFirst: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #1:
-
-
-
-ContextNameSuffix: android.telephony.mbms.vendor.MbmsGroupCallServiceBase:
-
+ Context is distinct, so it must be the first argument (method `get`)
EndsWithImpl: android.view.contentcapture.ViewNode.ViewStructureImpl:
-
+ Don't expose your implementation details: `ViewStructureImpl` ends with `Impl`
Enum: android.view.inspector.InspectableProperty.ValueType:
-
-
-
-EqualsAndHashCode: android.app.prediction.AppPredictionContext#equals(Object):
-
-EqualsAndHashCode: android.app.prediction.AppTarget#equals(Object):
-
-EqualsAndHashCode: android.app.prediction.AppTargetEvent#equals(Object):
-
-EqualsAndHashCode: android.net.apf.ApfCapabilities#equals(Object):
-
-EqualsAndHashCode: android.net.metrics.ApfProgramEvent#equals(Object):
-
-EqualsAndHashCode: android.net.metrics.ApfStats#equals(Object):
-
-EqualsAndHashCode: android.net.metrics.DhcpClientEvent#equals(Object):
-
-EqualsAndHashCode: android.net.metrics.IpManagerEvent#equals(Object):
-
-EqualsAndHashCode: android.net.metrics.IpReachabilityEvent#equals(Object):
-
-EqualsAndHashCode: android.net.metrics.NetworkEvent#equals(Object):
-
-EqualsAndHashCode: android.net.metrics.RaEvent#equals(Object):
-
-EqualsAndHashCode: android.net.metrics.ValidationProbeEvent#equals(Object):
-
-EqualsAndHashCode: android.os.IncidentManager.PendingReport#equals(Object):
-
+ Enums are discouraged in Android APIs
+
+
EqualsAndHashCode: android.os.StrictMode.ViolationInfo#hashCode():
-
+ Must override both equals and hashCode; missing one in android.os.StrictMode.ViolationInfo
-ExecutorRegistration: android.content.pm.PackageManager#addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener):
-
-ExecutorRegistration: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler):
-
ExecutorRegistration: android.media.audiofx.AudioEffect#setParameterListener(android.media.audiofx.AudioEffect.OnParameterChangeListener):
-
-ExecutorRegistration: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener):
-
-ExecutorRegistration: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener):
-
-ExecutorRegistration: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyVolumeCallback(android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback):
-
-ExecutorRegistration: android.os.IncidentManager#cancelAuthorization(android.os.IncidentManager.AuthListener):
-
-ExecutorRegistration: android.os.IncidentManager#requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener):
-
-ExecutorRegistration: android.os.RemoteCallback#RemoteCallback(android.os.RemoteCallback.OnResultListener, android.os.Handler):
-
+ Registration methods should have overload that accepts delivery Executor: `setParameterListener`
ExecutorRegistration: android.permission.PermissionControllerManager#countPermissionApps(java.util.List<java.lang.String>, int, android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, android.os.Handler):
-
+ Registration methods should have overload that accepts delivery Executor: `countPermissionApps`
ExecutorRegistration: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler):
-
+ Registration methods should have overload that accepts delivery Executor: `getAppPermissions`
ExecutorRegistration: android.service.watchdog.ExplicitHealthCheckService#setCallback(android.os.RemoteCallback):
-
-ExecutorRegistration: android.telephony.ims.stub.ImsCallSessionImplBase#setListener(android.telephony.ims.ImsCallSessionListener):
-
-ExecutorRegistration: android.telephony.ims.stub.ImsUtImplBase#setListener(android.telephony.ims.ImsUtListener):
-
-ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
-
-ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
-
-ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback):
-
-ExecutorRegistration: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
-
-ExecutorRegistration: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#startGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, android.telephony.mbms.GroupCallCallback):
-
-ExecutorRegistration: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int):
-
-ExecutorRegistration: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback):
-
+ Registration methods should have overload that accepts delivery Executor: `setCallback`
ExecutorRegistration: android.window.WindowOrganizer#applySyncTransaction(android.window.WindowContainerTransaction, android.window.WindowContainerTransactionCallback):
-
+ Registration methods should have overload that accepts delivery Executor: `applySyncTransaction`
ForbiddenSuperClass: android.app.AppDetailsActivity:
-
+ AppDetailsActivity should not extend `Activity`. Activity subclasses are impossible to compose. Expose a composable API instead.
-GenericException: android.app.prediction.AppPredictor#finalize():
-
GenericException: android.service.autofill.CharSequenceTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
-
+ Methods must not throw generic exceptions (`java.lang.Exception`)
GenericException: android.service.autofill.DateTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
-
+ Methods must not throw generic exceptions (`java.lang.Exception`)
GenericException: android.service.autofill.ImageTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
-
-GenericException: android.service.autofill.augmented.FillWindow#finalize():
-
-
-
-GetterOnBuilder: android.hardware.display.BrightnessConfiguration.Builder#getMaxCorrectionsByCategory():
-
-GetterOnBuilder: android.hardware.display.BrightnessConfiguration.Builder#getMaxCorrectionsByPackageName():
-
+ Methods must not throw generic exceptions (`java.lang.Exception`)
-GetterSetterNames: android.app.NotificationChannel#isBlockableSystem():
-
-GetterSetterNames: android.app.NotificationChannel#isImportanceLockedByCriticalDeviceFunction():
-
-GetterSetterNames: android.app.NotificationChannel#isImportanceLockedByOEM():
-
GetterSetterNames: android.location.GnssClock#setBiasNanos(double):
-
+ Symmetric method for `hasBiasNanos` must be named `setHasBiasNanos`; was `setBiasNanos`
GetterSetterNames: android.location.GnssClock#setBiasUncertaintyNanos(double):
-
+ Symmetric method for `hasBiasUncertaintyNanos` must be named `setHasBiasUncertaintyNanos`; was `setBiasUncertaintyNanos`
GetterSetterNames: android.location.GnssClock#setDriftNanosPerSecond(double):
-
+ Symmetric method for `hasDriftNanosPerSecond` must be named `setHasDriftNanosPerSecond`; was `setDriftNanosPerSecond`
GetterSetterNames: android.location.GnssClock#setDriftUncertaintyNanosPerSecond(double):
-
+ Symmetric method for `hasDriftUncertaintyNanosPerSecond` must be named `setHasDriftUncertaintyNanosPerSecond`; was `setDriftUncertaintyNanosPerSecond`
GetterSetterNames: android.location.GnssClock#setElapsedRealtimeNanos(long):
-
+ Symmetric method for `hasElapsedRealtimeNanos` must be named `setHasElapsedRealtimeNanos`; was `setElapsedRealtimeNanos`
GetterSetterNames: android.location.GnssClock#setElapsedRealtimeUncertaintyNanos(double):
-
+ Symmetric method for `hasElapsedRealtimeUncertaintyNanos` must be named `setHasElapsedRealtimeUncertaintyNanos`; was `setElapsedRealtimeUncertaintyNanos`
GetterSetterNames: android.location.GnssClock#setFullBiasNanos(long):
-
+ Symmetric method for `hasFullBiasNanos` must be named `setHasFullBiasNanos`; was `setFullBiasNanos`
GetterSetterNames: android.location.GnssClock#setLeapSecond(int):
-
+ Symmetric method for `hasLeapSecond` must be named `setHasLeapSecond`; was `setLeapSecond`
GetterSetterNames: android.location.GnssClock#setReferenceCarrierFrequencyHzForIsb(double):
-
+ Symmetric method for `hasReferenceCarrierFrequencyHzForIsb` must be named `setHasReferenceCarrierFrequencyHzForIsb`; was `setReferenceCarrierFrequencyHzForIsb`
GetterSetterNames: android.location.GnssClock#setReferenceCodeTypeForIsb(String):
-
+ Symmetric method for `hasReferenceCodeTypeForIsb` must be named `setHasReferenceCodeTypeForIsb`; was `setReferenceCodeTypeForIsb`
GetterSetterNames: android.location.GnssClock#setReferenceConstellationTypeForIsb(int):
-
+ Symmetric method for `hasReferenceConstellationTypeForIsb` must be named `setHasReferenceConstellationTypeForIsb`; was `setReferenceConstellationTypeForIsb`
GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
-
+ Symmetric method for `hasTimeUncertaintyNanos` must be named `setHasTimeUncertaintyNanos`; was `setTimeUncertaintyNanos`
GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double):
-
+ Symmetric method for `hasBasebandCn0DbHz` must be named `setHasBasebandCn0DbHz`; was `setBasebandCn0DbHz`
GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
-
+ Symmetric method for `hasCarrierFrequencyHz` must be named `setHasCarrierFrequencyHz`; was `setCarrierFrequencyHz`
GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
-
+ Symmetric method for `hasCodeType` must be named `setHasCodeType`; was `setCodeType`
GetterSetterNames: android.location.GnssMeasurement#setCorrelationVectors(java.util.Collection<android.location.CorrelationVector>):
-
+ Symmetric method for `hasCorrelationVectors` must be named `setHasCorrelationVectors`; was `setCorrelationVectors`
GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasNanos(double):
-
+ Symmetric method for `hasFullInterSignalBiasNanos` must be named `setHasFullInterSignalBiasNanos`; was `setFullInterSignalBiasNanos`
GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasUncertaintyNanos(double):
-
+ Symmetric method for `hasFullInterSignalBiasUncertaintyNanos` must be named `setHasFullInterSignalBiasUncertaintyNanos`; was `setFullInterSignalBiasUncertaintyNanos`
GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasNanos(double):
-
+ Symmetric method for `hasSatelliteInterSignalBiasNanos` must be named `setHasSatelliteInterSignalBiasNanos`; was `setSatelliteInterSignalBiasNanos`
GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasUncertaintyNanos(double):
-
+ Symmetric method for `hasSatelliteInterSignalBiasUncertaintyNanos` must be named `setHasSatelliteInterSignalBiasUncertaintyNanos`; was `setSatelliteInterSignalBiasUncertaintyNanos`
GetterSetterNames: android.location.GnssMeasurement#setSatellitePvt(android.location.SatellitePvt):
-
+ Symmetric method for `hasSatellitePvt` must be named `setHasSatellitePvt`; was `setSatellitePvt`
GetterSetterNames: android.location.GnssMeasurement#setSnrInDb(double):
-
-GetterSetterNames: android.location.LocationRequest#isLocationSettingsIgnored():
-
-GetterSetterNames: android.location.LocationRequest#isLowPowerMode():
-
+ Symmetric method for `hasSnrInDb` must be named `setHasSnrInDb`; was `setSnrInDb`
GetterSetterNames: android.net.NetworkPolicyManager#getRestrictBackground():
Symmetric method for `setRestrictBackground` must be named `isRestrictBackground`; was `getRestrictBackground`
-GetterSetterNames: android.os.IncidentReportArgs#isAll():
-
-GetterSetterNames: android.service.notification.NotificationStats#setDirectReplied():
-
-GetterSetterNames: android.service.notification.NotificationStats#setExpanded():
-
-GetterSetterNames: android.service.notification.NotificationStats#setSeen():
-
-GetterSetterNames: android.service.notification.NotificationStats#setSnoozed():
-
-GetterSetterNames: android.service.notification.NotificationStats#setViewedSettings():
-
-GetterSetterNames: android.view.View#isAutofilled():
-
-GetterSetterNames: android.view.View#isDefaultFocusHighlightEnabled():
-
-
-
-IllegalStateException: android.media.audiopolicy.AudioMix.Builder#build():
-
-
-
-IntentBuilderName: android.app.backup.BackupManager#getConfigurationIntent(String):
-
-IntentBuilderName: android.app.backup.BackupManager#getDataManagementIntent(String):
-
+
+
IntentBuilderName: android.hardware.soundtrigger.KeyphraseEnrollmentInfo#getManageKeyphraseIntent(int, String, java.util.Locale):
-
+ Methods creating an Intent should be named `create<Foo>Intent()`, was `getManageKeyphraseIntent`
IntentName: android.provider.Settings.Secure#VOICE_INTERACTION_SERVICE:
-
+ Intent action constant name must be ACTION_FOO: VOICE_INTERACTION_SERVICE
IntentName: android.provider.Telephony.Sms.Intents#SMS_CARRIER_PROVISION_ACTION:
-
-IntentName: android.service.notification.Adjustment#KEY_CONTEXTUAL_ACTIONS:
-
+ Intent action constant name must be ACTION_FOO: SMS_CARRIER_PROVISION_ACTION
-InterfaceConstant: android.service.autofill.AutofillFieldClassificationService#SERVICE_INTERFACE:
-
-InterfaceConstant: android.service.autofill.augmented.AugmentedAutofillService#SERVICE_INTERFACE:
-
-InterfaceConstant: android.service.contentcapture.ContentCaptureService#SERVICE_INTERFACE:
-
-InterfaceConstant: android.service.notification.NotificationAssistantService#SERVICE_INTERFACE:
-
-InterfaceConstant: android.telecom.PhoneAccountSuggestionService#SERVICE_INTERFACE:
-
-
-
-InternalField: android.media.audiopolicy.AudioProductStrategy#sDefaultAttributes:
- Internal field sDefaultAttributes must not be exposed
-InternalField: android.telephony.ims.ImsConferenceState#mParticipants:
-
+KotlinOperator: android.os.PackageTagsList#contains(android.os.PackageTagsList):
+ Method can be invoked as a "in" operator from Kotlin: `contains` (this is usually desirable; just make sure it makes sense for this type of object)
+KotlinOperator: android.util.SparseArrayMap#get(int, K):
+ Method can be invoked with an indexing operator from Kotlin: `get` (this is usually desirable; just make sure it makes sense for this type of object)
-KotlinOperator: android.os.WorkSource#get(int):
-
-KotlinOperator: android.util.SparseArrayMap#get(int, K):
-
-KotlinOperator: android.util.SparseArrayMap#get(int, String):
-
-
-
-ListenerInterface: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener:
-
-ListenerInterface: android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener:
-
-ListenerInterface: android.os.IncidentManager.AuthListener:
-
-ListenerInterface: android.telephony.ims.ImsCallSessionListener:
-
-ListenerInterface: android.telephony.ims.ImsUtListener:
-
-
-
-ListenerLast: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) parameter #4:
-
-ListenerLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper) parameter #2:
-
ListenerLast: android.permission.PermissionControllerManager#countPermissionApps(java.util.List<java.lang.String>, int, android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, android.os.Handler) parameter #3:
-
+ Listeners should always be at end of argument list (method `countPermissionApps`)
ListenerLast: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler) parameter #2:
-
-ListenerLast: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) parameter #1:
-
-ListenerLast: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) parameter #1:
-
+ Listeners should always be at end of argument list (method `getAppPermissions`)
ManagerConstructor: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context):
-
-
-
-ManagerLookup: android.telephony.ims.ImsMmTelManager#createForSubscriptionId(int):
-
-ManagerLookup: android.telephony.ims.ProvisioningManager#createForSubscriptionId(int):
-
-
-
-MethodNameTense: android.telephony.ims.feature.CapabilityChangeRequest#getCapabilitiesToEnable():
-
-
-
-MethodNameUnits: android.telephony.ims.ImsCallForwardInfo#getTimeSeconds():
-
+ Managers must always be obtained from Context; no direct constructors
MinMaxConstant: android.os.UserHandle#MIN_SECONDARY_USER_ID:
-
+ If min/max could change in future, make them dynamic methods: android.os.UserHandle#MIN_SECONDARY_USER_ID
MinMaxConstant: android.view.autofill.AutofillManager#MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS:
-
-
-
-MissingGetterMatchingBuilder: android.app.AppOpsManager.HistoricalOpsRequest.Builder#setFlags(int):
-
-MissingGetterMatchingBuilder: android.app.AppOpsManager.HistoricalOpsRequest.Builder#setOpNames(java.util.List<java.lang.String>):
-
-MissingGetterMatchingBuilder: android.app.AppOpsManager.HistoricalOpsRequest.Builder#setPackageName(String):
-
-MissingGetterMatchingBuilder: android.app.AppOpsManager.HistoricalOpsRequest.Builder#setUid(int):
-
-MissingGetterMatchingBuilder: android.content.integrity.RuleSet.Builder#addRules(java.util.List<android.content.integrity.Rule>):
-
-MissingGetterMatchingBuilder: android.hardware.display.BrightnessConfiguration.Builder#addCorrectionByCategory(int, android.hardware.display.BrightnessCorrection):
-
-MissingGetterMatchingBuilder: android.hardware.display.BrightnessConfiguration.Builder#addCorrectionByPackageName(String, android.hardware.display.BrightnessCorrection):
-
-MissingGetterMatchingBuilder: android.hardware.display.BrightnessConfiguration.Builder#setDescription(String):
-
-MissingGetterMatchingBuilder: android.hardware.lights.LightsRequest.Builder#setLight(android.hardware.lights.Light, android.hardware.lights.LightState):
-
+ If min/max could change in future, make them dynamic methods: android.view.autofill.AutofillManager#MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS
+
+
MissingGetterMatchingBuilder: android.media.VolumeShaper.Configuration.Builder#setOptionFlags(int):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioMix.Builder#setDevice(android.media.AudioDeviceInfo):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioMix.Builder#setFormat(android.media.AudioFormat):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioMix.Builder#setRouteFlags(int):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioMixingRule.Builder#addMixRule(int, Object):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioMixingRule.Builder#addRule(android.media.AudioAttributes, int):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioPolicy.Builder#addMix(android.media.audiopolicy.AudioMix):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyVolumeCallback(android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioPolicy.Builder#setIsAudioFocusPolicy(boolean):
-
+ android.media.VolumeShaper.Configuration does not declare a `getOptionFlags()` method matching method android.media.VolumeShaper.Configuration.Builder.setOptionFlags(int)
MissingGetterMatchingBuilder: android.media.audiopolicy.AudioPolicy.Builder#setIsTestFocusPolicy(boolean):
-
-MissingGetterMatchingBuilder: android.media.audiopolicy.AudioPolicy.Builder#setLooper(android.os.Looper):
-
-MissingGetterMatchingBuilder: android.net.CaptivePortalData.Builder#setBytesRemaining(long):
-
-MissingGetterMatchingBuilder: android.net.CaptivePortalData.Builder#setExpiryTime(long):
-
-MissingGetterMatchingBuilder: android.net.CaptivePortalData.Builder#setRefreshTime(long):
-
-MissingGetterMatchingBuilder: android.net.NetworkCapabilities.Builder#addCapability(int):
-
-MissingGetterMatchingBuilder: android.net.NetworkCapabilities.Builder#setRequestorPackageName(String):
-
-MissingGetterMatchingBuilder: android.net.NetworkCapabilities.Builder#setRequestorUid(int):
-
-MissingGetterMatchingBuilder: android.net.TetheringManager.TetheringRequest.Builder#setShouldShowEntitlementUi(boolean):
-
-MissingGetterMatchingBuilder: android.net.TetheringManager.TetheringRequest.Builder#setStaticIpv4Addresses(android.net.LinkAddress, android.net.LinkAddress):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfProgramEvent.Builder#setActualLifetime(long):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfProgramEvent.Builder#setCurrentRas(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfProgramEvent.Builder#setFilteredRas(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfProgramEvent.Builder#setFlags(boolean, boolean):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfProgramEvent.Builder#setLifetime(long):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfProgramEvent.Builder#setProgramLength(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfStats.Builder#setDroppedRas(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfStats.Builder#setDurationMs(long):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfStats.Builder#setMatchingRas(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfStats.Builder#setMaxProgramSize(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfStats.Builder#setParseErrors(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfStats.Builder#setProgramUpdates(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfStats.Builder#setProgramUpdatesAll(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfStats.Builder#setProgramUpdatesAllowingMulticast(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfStats.Builder#setReceivedRas(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.ApfStats.Builder#setZeroLifetimeRas(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.DhcpClientEvent.Builder#setDurationMs(int):
-
-MissingGetterMatchingBuilder: android.net.metrics.DhcpClientEvent.Builder#setMsg(String):
-
-MissingGetterMatchingBuilder: android.net.metrics.ValidationProbeEvent.Builder#setDurationMs(long):
-
-MissingGetterMatchingBuilder: android.net.metrics.ValidationProbeEvent.Builder#setProbeType(int, boolean):
-
-MissingGetterMatchingBuilder: android.net.metrics.ValidationProbeEvent.Builder#setReturnCode(int):
-
+ android.media.audiopolicy.AudioPolicy does not declare a `isIsTestFocusPolicy()` method matching method android.media.audiopolicy.AudioPolicy.Builder.setIsTestFocusPolicy(boolean)
MissingGetterMatchingBuilder: android.security.keystore.KeyGenParameterSpec.Builder#setUniqueIdIncluded(boolean):
-
-MissingGetterMatchingBuilder: android.service.autofill.Dataset.Builder#setFieldInlinePresentation(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.service.autofill.InlinePresentation):
-
-MissingGetterMatchingBuilder: android.service.autofill.augmented.FillResponse.Builder#setClientState(android.os.Bundle):
-
-MissingGetterMatchingBuilder: android.service.autofill.augmented.FillResponse.Builder#setFillWindow(android.service.autofill.augmented.FillWindow):
-
-MissingGetterMatchingBuilder: android.service.autofill.augmented.FillResponse.Builder#setInlineSuggestions(java.util.List<android.service.autofill.Dataset>):
-
-MissingGetterMatchingBuilder: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallViaAudioProcessing(boolean):
-
+ android.security.keystore.KeyGenParameterSpec does not declare a `isUniqueIdIncluded()` method matching method android.security.keystore.KeyGenParameterSpec.Builder.setUniqueIdIncluded(boolean)
MissingGetterMatchingBuilder: android.telecom.ConnectionRequest.Builder#setIsAdhocConferenceCall(boolean):
-
+ android.telecom.ConnectionRequest does not declare a `isIsAdhocConferenceCall()` method matching method android.telecom.ConnectionRequest.Builder.setIsAdhocConferenceCall(boolean)
MissingGetterMatchingBuilder: android.telecom.ConnectionRequest.Builder#setRttPipeFromInCall(android.os.ParcelFileDescriptor):
-
+ android.telecom.ConnectionRequest does not declare a `getRttPipeFromInCall()` method matching method android.telecom.ConnectionRequest.Builder.setRttPipeFromInCall(android.os.ParcelFileDescriptor)
MissingGetterMatchingBuilder: android.telecom.ConnectionRequest.Builder#setRttPipeToInCall(android.os.ParcelFileDescriptor):
-
+ android.telecom.ConnectionRequest does not declare a `getRttPipeToInCall()` method matching method android.telecom.ConnectionRequest.Builder.setRttPipeToInCall(android.os.ParcelFileDescriptor)
MissingGetterMatchingBuilder: android.telecom.ConnectionRequest.Builder#setShouldShowIncomingCallUi(boolean):
-
-MissingGetterMatchingBuilder: android.telecom.PhoneAccount.Builder#setGroupId(String):
-
-MissingGetterMatchingBuilder: android.telephony.NetworkRegistrationInfo.Builder#setEmergencyOnly(boolean):
-
-MissingGetterMatchingBuilder: android.telephony.ims.ImsSsData.Builder#setCallForwardingInfo(java.util.List<android.telephony.ims.ImsCallForwardInfo>):
-
-MissingGetterMatchingBuilder: android.telephony.ims.stub.ImsFeatureConfiguration.Builder#addFeature(int, int):
-
-MissingGetterMatchingBuilder: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
-
+ android.telecom.ConnectionRequest does not declare a `shouldShowIncomingCallUi()` method matching method android.telecom.ConnectionRequest.Builder.setShouldShowIncomingCallUi(boolean)
MissingGetterMatchingBuilder: android.view.Display.Mode.Builder#setResolution(int, int):
android.view.Display.Mode does not declare a `getResolution()` method matching method android.view.Display.Mode.Builder.setResolution(int,int)
MissingNullability: android.app.Activity#onMovedToDisplay(int, android.content.res.Configuration) parameter #1:
-
-MissingNullability: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int) parameter #0:
-
+ Missing nullability on parameter `config` in method `onMovedToDisplay`
MissingNullability: android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName) parameter #0:
-
-MissingNullability: android.app.ActivityManager#forceStopPackage(String) parameter #0:
-
-MissingNullability: android.app.ActivityManager#getPackageImportance(String) parameter #0:
-
+ Missing nullability on parameter `activity` in method `alwaysShowUnsupportedCompileSdkWarning`
MissingNullability: android.app.ActivityManager#holdLock(android.os.IBinder, int) parameter #0:
-
-MissingNullability: android.app.ActivityManager#removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener) parameter #0:
-
+ Missing nullability on parameter `token` in method `holdLock`
MissingNullability: android.app.ActivityManager#scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int) parameter #0:
-
+ Missing nullability on parameter `packages` in method `scheduleApplicationInfoChanged`
MissingNullability: android.app.ActivityManager.TaskDescription#getIconFilename():
-
+ Missing nullability on method `getIconFilename` return
MissingNullability: android.app.ActivityTaskManager#clearLaunchParamsForPackages(java.util.List<java.lang.String>) parameter #0:
-
-MissingNullability: android.app.ActivityTaskManager#listAllStacks():
-
-MissingNullability: android.app.ActivityTaskManager#moveTopActivityToPinnedStack(int, android.graphics.Rect) parameter #1:
-
-MissingNullability: android.app.ActivityTaskManager#removeStacksInWindowingModes(int[]) parameter #0:
-
-MissingNullability: android.app.ActivityTaskManager#removeStacksWithActivityTypes(int[]) parameter #0:
-
-MissingNullability: android.app.ActivityTaskManager#resizeDockedStack(android.graphics.Rect, android.graphics.Rect) parameter #0:
-
-MissingNullability: android.app.ActivityTaskManager#resizeDockedStack(android.graphics.Rect, android.graphics.Rect) parameter #1:
-
-MissingNullability: android.app.ActivityTaskManager#resizePinnedStack(int, android.graphics.Rect, boolean) parameter #1:
-
+ Missing nullability on parameter `packageNames` in method `clearLaunchParamsForPackages`
MissingNullability: android.app.ActivityTaskManager#resizeTask(int, android.graphics.Rect) parameter #1:
-
-MissingNullability: android.app.ActivityTaskManager#setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) parameter #4:
-
+ Missing nullability on parameter `bounds` in method `resizeTask`
MissingNullability: android.app.ActivityTaskManager#supportsMultiWindow(android.content.Context) parameter #0:
-
+ Missing nullability on parameter `context` in method `supportsMultiWindow`
MissingNullability: android.app.ActivityTaskManager#supportsSplitScreenMultiWindow(android.content.Context) parameter #0:
-
+ Missing nullability on parameter `context` in method `supportsSplitScreenMultiWindow`
MissingNullability: android.app.AppDetailsActivity#onCreate(android.os.Bundle) parameter #0:
-
-MissingNullability: android.app.AppOpsManager#getOpStrs():
-
+ Missing nullability on parameter `savedInstanceState` in method `onCreate`
MissingNullability: android.app.AppOpsManager#isOperationActive(int, int, String) parameter #2:
-
+ Missing nullability on parameter `packageName` in method `isOperationActive`
MissingNullability: android.app.AppOpsManager#opToPermission(int):
-
+ Missing nullability on method `opToPermission` return
MissingNullability: android.app.AppOpsManager#permissionToOpCode(String) parameter #0:
-
-MissingNullability: android.app.AppOpsManager#setMode(String, int, String, int) parameter #0:
-
-MissingNullability: android.app.AppOpsManager#setMode(String, int, String, int) parameter #2:
-
+ Missing nullability on parameter `permission` in method `permissionToOpCode`
MissingNullability: android.app.AppOpsManager#setMode(int, int, String, int) parameter #2:
-
-MissingNullability: android.app.AppOpsManager#setUidMode(String, int, int) parameter #0:
-
-MissingNullability: android.app.AppOpsManager.HistoricalOp#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.app.AppOpsManager.HistoricalOps#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.app.AppOpsManager.HistoricalUidOps#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.app.AppOpsManager.OpEntry#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `packageName` in method `setMode`
MissingNullability: android.app.NotificationManager#allowAssistantAdjustment(String) parameter #0:
-
+ Missing nullability on parameter `capability` in method `allowAssistantAdjustment`
MissingNullability: android.app.NotificationManager#disallowAssistantAdjustment(String) parameter #0:
-
+ Missing nullability on parameter `capability` in method `disallowAssistantAdjustment`
MissingNullability: android.app.NotificationManager#getEffectsSuppressor():
-
-MissingNullability: android.app.NotificationManager#matchesCallFilter(android.os.Bundle) parameter #0:
-
-MissingNullability: android.app.PictureInPictureParams#getActions():
-
-MissingNullability: android.app.PictureInPictureParams#getSourceRectHint():
-
+ Missing nullability on method `getEffectsSuppressor` return
MissingNullability: android.app.TimePickerDialog#getTimePicker():
-
-MissingNullability: android.app.UiAutomation#executeShellCommandRw(String):
-
-MissingNullability: android.app.UiAutomation#executeShellCommandRw(String) parameter #0:
-
-MissingNullability: android.app.UiAutomation#grantRuntimePermission(String, String, android.os.UserHandle) parameter #0:
-
-MissingNullability: android.app.UiAutomation#grantRuntimePermission(String, String, android.os.UserHandle) parameter #1:
-
-MissingNullability: android.app.UiAutomation#grantRuntimePermission(String, String, android.os.UserHandle) parameter #2:
-
-MissingNullability: android.app.UiAutomation#revokeRuntimePermission(String, String, android.os.UserHandle) parameter #0:
-
-MissingNullability: android.app.UiAutomation#revokeRuntimePermission(String, String, android.os.UserHandle) parameter #1:
-
-MissingNullability: android.app.UiAutomation#revokeRuntimePermission(String, String, android.os.UserHandle) parameter #2:
-
-MissingNullability: android.app.WallpaperManager#setWallpaperComponent(android.content.ComponentName) parameter #0:
-
+ Missing nullability on method `getTimePicker` return
MissingNullability: android.app.WindowConfiguration#compareTo(android.app.WindowConfiguration) parameter #0:
-
+ Missing nullability on parameter `that` in method `compareTo`
MissingNullability: android.app.WindowConfiguration#getAppBounds():
-
+ Missing nullability on method `getAppBounds` return
MissingNullability: android.app.WindowConfiguration#getBounds():
-
+ Missing nullability on method `getBounds` return
MissingNullability: android.app.WindowConfiguration#setAppBounds(android.graphics.Rect) parameter #0:
-
+ Missing nullability on parameter `rect` in method `setAppBounds`
MissingNullability: android.app.WindowConfiguration#setBounds(android.graphics.Rect) parameter #0:
-
+ Missing nullability on parameter `rect` in method `setBounds`
MissingNullability: android.app.WindowConfiguration#setTo(android.app.WindowConfiguration) parameter #0:
-
+ Missing nullability on parameter `other` in method `setTo`
MissingNullability: android.app.WindowConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `dest` in method `writeToParcel`
MissingNullability: android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts(android.os.UserHandle):
-
+ Missing nullability on method `getOwnerInstalledCaCerts` return
MissingNullability: android.app.admin.SecurityLog.SecurityEvent#SecurityEvent(long, byte[]) parameter #1:
-
-MissingNullability: android.app.backup.BackupManager#getConfigurationIntent(String):
-
-MissingNullability: android.app.backup.BackupManager#getConfigurationIntent(String) parameter #0:
-
-MissingNullability: android.app.backup.BackupManager#getDataManagementIntent(String):
-
-MissingNullability: android.app.backup.BackupManager#getDataManagementIntent(String) parameter #0:
-
-MissingNullability: android.app.backup.BackupManager#getDestinationString(String):
-
-MissingNullability: android.app.backup.BackupManager#getDestinationString(String) parameter #0:
-
-MissingNullability: android.app.prediction.AppPredictionSessionId#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `data` in method `SecurityEvent`
MissingNullability: android.app.prediction.AppPredictor#getSessionId():
-
-MissingNullability: android.app.prediction.AppTarget#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.app.prediction.AppTargetEvent#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.app.prediction.AppTargetId#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on method `getSessionId` return
MissingNullability: android.content.AutofillOptions#forWhitelistingItself():
-
+ Missing nullability on method `forWhitelistingItself` return
MissingNullability: android.content.AutofillOptions#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `parcel` in method `writeToParcel`
MissingNullability: android.content.ContentCaptureOptions#forWhitelistingItself():
-
+ Missing nullability on method `forWhitelistingItself` return
MissingNullability: android.content.ContentCaptureOptions#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `parcel` in method `writeToParcel`
MissingNullability: android.content.ContentResolver#getSyncAdapterPackagesForAuthorityAsUser(String, int):
-
+ Missing nullability on method `getSyncAdapterPackagesForAuthorityAsUser` return
MissingNullability: android.content.ContentResolver#getSyncAdapterPackagesForAuthorityAsUser(String, int) parameter #0:
-
-MissingNullability: android.content.Context#getDisplay():
-
-MissingNullability: android.content.Context#getUser():
-
-MissingNullability: android.content.ContextWrapper#getDisplay():
-
-MissingNullability: android.content.ContextWrapper#setContentCaptureOptions(android.content.ContentCaptureOptions) parameter #0:
-
+ Missing nullability on parameter `authority` in method `getSyncAdapterPackagesForAuthorityAsUser`
MissingNullability: android.content.pm.ActivityInfo#isTranslucentOrFloating(android.content.res.TypedArray) parameter #0:
-
+ Missing nullability on parameter `attributes` in method `isTranslucentOrFloating`
MissingNullability: android.content.pm.LauncherApps#LauncherApps(android.content.Context) parameter #0:
-
-MissingNullability: android.content.pm.PackageInstaller.SessionParams#setGrantedRuntimePermissions(String[]) parameter #0:
-
+ Missing nullability on parameter `context` in method `LauncherApps`
MissingNullability: android.content.pm.PackageManager#getHoldLockToken():
- Missing nullability on method `BINDER` return
+ Missing nullability on method `getHoldLockToken` return
MissingNullability: android.content.pm.PackageManager#getNamesForUids(int[]) parameter #0:
-
+ Missing nullability on parameter `uids` in method `getNamesForUids`
MissingNullability: android.content.pm.PackageManager#holdLock(android.os.IBinder, int) parameter #0:
-
+ Missing nullability on parameter `token` in method `holdLock`
MissingNullability: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context) parameter #0:
-
+ Missing nullability on parameter `context` in method `ShortcutManager`
MissingNullability: android.content.pm.UserInfo#UserInfo(android.content.pm.UserInfo) parameter #0:
Missing nullability on parameter `orig` in method `UserInfo`
MissingNullability: android.content.pm.UserInfo#UserInfo(int, String, String, int) parameter #1:
@@ -942,1469 +292,477 @@ MissingNullability: android.content.pm.UserInfo#userType:
MissingNullability: android.content.pm.UserInfo#writeToParcel(android.os.Parcel, int) parameter #0:
Missing nullability on parameter `dest` in method `writeToParcel`
MissingNullability: android.content.res.AssetManager#getOverlayablesToString(String) parameter #0:
-
+ Missing nullability on parameter `packageName` in method `getOverlayablesToString`
MissingNullability: android.content.res.Configuration#windowConfiguration:
-
-MissingNullability: android.content.rollback.PackageRollbackInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.content.rollback.RollbackInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on field `windowConfiguration` in class `class android.content.res.Configuration`
MissingNullability: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]) parameter #0:
-
+ Missing nullability on parameter `printer` in method `dump`
MissingNullability: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]) parameter #1:
-
+ Missing nullability on parameter `args` in method `dump`
MissingNullability: android.database.sqlite.SQLiteDebug#getDatabaseInfo():
-
+ Missing nullability on method `getDatabaseInfo` return
MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#DbStats(String, long, long, int, int, int, int) parameter #0:
-
+ Missing nullability on parameter `dbName` in method `DbStats`
MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#cache:
-
+ Missing nullability on field `cache` in class `class android.database.sqlite.SQLiteDebug.DbStats`
MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#dbName:
-
+ Missing nullability on field `dbName` in class `class android.database.sqlite.SQLiteDebug.DbStats`
MissingNullability: android.database.sqlite.SQLiteDebug.PagerStats#dbStats:
-
+ Missing nullability on field `dbStats` in class `class android.database.sqlite.SQLiteDebug.PagerStats`
MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #0:
-
+ Missing nullability on parameter `db` in method `SQLiteDirectCursorDriver`
MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #1:
-
+ Missing nullability on parameter `sql` in method `SQLiteDirectCursorDriver`
MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #2:
-
+ Missing nullability on parameter `editTable` in method `SQLiteDirectCursorDriver`
MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #3:
-
+ Missing nullability on parameter `cancellationSignal` in method `SQLiteDirectCursorDriver`
MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#cursorRequeried(android.database.Cursor) parameter #0:
-
+ Missing nullability on parameter `cursor` in method `cursorRequeried`
MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]):
-
+ Missing nullability on method `query` return
MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]) parameter #0:
-
+ Missing nullability on parameter `factory` in method `query`
MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]) parameter #1:
-
+ Missing nullability on parameter `selectionArgs` in method `query`
MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#setBindArguments(String[]) parameter #0:
-
+ Missing nullability on parameter `bindArgs` in method `setBindArguments`
MissingNullability: android.database.sqlite.SQLiteGlobal#getDefaultJournalMode():
-
+ Missing nullability on method `getDefaultJournalMode` return
MissingNullability: android.database.sqlite.SQLiteGlobal#getDefaultSyncMode():
-
+ Missing nullability on method `getDefaultSyncMode` return
MissingNullability: android.database.sqlite.SQLiteGlobal#getWALSyncMode():
-
+ Missing nullability on method `getWALSyncMode` return
MissingNullability: android.graphics.ImageDecoder#createSource(android.content.res.Resources, java.io.InputStream, int) parameter #0:
-
-MissingNullability: android.graphics.ImageDecoder#createSource(android.content.res.Resources, java.io.InputStream, int) parameter #1:
-
+ Missing nullability on parameter `res` in method `createSource`
MissingNullability: android.graphics.drawable.AdaptiveIconDrawable#getSafeZone():
-
+ Missing nullability on method `getSafeZone` return
MissingNullability: android.graphics.drawable.ColorDrawable#getXfermode():
-
-MissingNullability: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) parameter #0:
-
+ Missing nullability on method `getXfermode` return
MissingNullability: android.hardware.camera2.CameraManager#getCameraIdListNoLazy():
-
-MissingNullability: android.hardware.display.AmbientBrightnessDayStats#getBucketBoundaries():
-
-MissingNullability: android.hardware.display.AmbientBrightnessDayStats#getLocalDate():
-
-MissingNullability: android.hardware.display.AmbientBrightnessDayStats#getStats():
-
-MissingNullability: android.hardware.display.AmbientBrightnessDayStats#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on method `getCameraIdListNoLazy` return
MissingNullability: android.hardware.display.AmbientDisplayConfiguration#AmbientDisplayConfiguration(android.content.Context) parameter #0:
-
-MissingNullability: android.hardware.display.BrightnessChangeEvent#luxTimestamps:
-
-MissingNullability: android.hardware.display.BrightnessChangeEvent#luxValues:
-
-MissingNullability: android.hardware.display.BrightnessChangeEvent#packageName:
-
-MissingNullability: android.hardware.display.BrightnessChangeEvent#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.hardware.display.BrightnessConfiguration#getCurve():
-
-MissingNullability: android.hardware.display.BrightnessConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.hardware.display.BrightnessConfiguration.Builder#Builder(float[], float[]) parameter #0:
-
-MissingNullability: android.hardware.display.BrightnessConfiguration.Builder#Builder(float[], float[]) parameter #1:
-
-MissingNullability: android.hardware.display.BrightnessCorrection#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.hardware.display.DisplayManager#getAmbientBrightnessStats():
-
-MissingNullability: android.hardware.display.DisplayManager#getBrightnessConfiguration():
-
-MissingNullability: android.hardware.display.DisplayManager#getBrightnessEvents():
-
-MissingNullability: android.hardware.display.DisplayManager#getStableDisplaySize():
-
-MissingNullability: android.hardware.display.DisplayManager#setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration) parameter #0:
-
+ Missing nullability on parameter `context` in method `AmbientDisplayConfiguration`
MissingNullability: android.location.GnssClock#set(android.location.GnssClock) parameter #0:
-
+ Missing nullability on parameter `clock` in method `set`
MissingNullability: android.location.GnssMeasurement#set(android.location.GnssMeasurement) parameter #0:
-
-MissingNullability: android.location.GnssMeasurementsEvent#GnssMeasurementsEvent(android.location.GnssClock, android.location.GnssMeasurement[]) parameter #0:
-
-MissingNullability: android.location.GnssMeasurementsEvent#GnssMeasurementsEvent(android.location.GnssClock, android.location.GnssMeasurement[]) parameter #1:
-
+ Missing nullability on parameter `measurement` in method `set`
MissingNullability: android.location.GnssNavigationMessage#set(android.location.GnssNavigationMessage) parameter #0:
-
+ Missing nullability on parameter `navigationMessage` in method `set`
MissingNullability: android.location.GnssNavigationMessage#setData(byte[]) parameter #0:
-
-MissingNullability: android.location.LocationManager#getTestProviderCurrentRequests(String) parameter #0:
-
-MissingNullability: android.location.LocationRequest#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.media.AudioAttributes#SDK_USAGES:
- Missing nullability on field `SDK_USAGES` in class `class android.media.AudioAttributes`
+ Missing nullability on parameter `value` in method `setData`
MissingNullability: android.media.AudioAttributes#getSdkUsages():
Missing nullability on method `getSdkUsages` return
-MissingNullability: android.media.AudioFocusInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
MissingNullability: android.media.AudioManager#getPublicStreamTypes():
Missing nullability on method `getPublicStreamTypes` return
MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #3:
-
+ Missing nullability on parameter `clientFormat` in method `AudioRecordingConfiguration`
MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #4:
-
+ Missing nullability on parameter `devFormat` in method `AudioRecordingConfiguration`
MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #6:
-
+ Missing nullability on parameter `packageName` in method `AudioRecordingConfiguration`
MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #10:
-
+ Missing nullability on parameter `clientEffects` in method `AudioRecordingConfiguration`
MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #11:
-
+ Missing nullability on parameter `deviceEffects` in method `AudioRecordingConfiguration`
MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #3:
-
+ Missing nullability on parameter `clientFormat` in method `AudioRecordingConfiguration`
MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #4:
-
+ Missing nullability on parameter `devFormat` in method `AudioRecordingConfiguration`
MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #6:
-
-MissingNullability: android.media.AudioSystem#streamToString(int):
- Missing nullability on method `streamToString` return
+ Missing nullability on parameter `packageName` in method `AudioRecordingConfiguration`
MissingNullability: android.media.PlaybackParams#setAudioStretchMode(int):
-
+ Missing nullability on method `setAudioStretchMode` return
MissingNullability: android.media.audiofx.AudioEffect#EFFECT_TYPE_NULL:
-
+ Missing nullability on field `EFFECT_TYPE_NULL` in class `class android.media.audiofx.AudioEffect`
MissingNullability: android.media.audiofx.AudioEffect#byteArrayToInt(byte[]) parameter #0:
-
+ Missing nullability on parameter `valueBuf` in method `byteArrayToInt`
MissingNullability: android.media.audiofx.AudioEffect#byteArrayToShort(byte[]) parameter #0:
-
+ Missing nullability on parameter `valueBuf` in method `byteArrayToShort`
MissingNullability: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]) parameter #0:
-
+ Missing nullability on parameter `param` in method `getParameter`
MissingNullability: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]) parameter #1:
-
+ Missing nullability on parameter `value` in method `getParameter`
MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, byte[]) parameter #1:
-
+ Missing nullability on parameter `value` in method `getParameter`
MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, int[]) parameter #1:
-
+ Missing nullability on parameter `value` in method `getParameter`
MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, short[]) parameter #1:
-
+ Missing nullability on parameter `value` in method `getParameter`
MissingNullability: android.media.audiofx.AudioEffect#getParameter(int[], short[]) parameter #0:
-
+ Missing nullability on parameter `param` in method `getParameter`
MissingNullability: android.media.audiofx.AudioEffect#getParameter(int[], short[]) parameter #1:
-
+ Missing nullability on parameter `value` in method `getParameter`
MissingNullability: android.media.audiofx.AudioEffect#intToByteArray(int):
-
+ Missing nullability on method `intToByteArray` return
MissingNullability: android.media.audiofx.AudioEffect#isEffectTypeAvailable(java.util.UUID) parameter #0:
-
+ Missing nullability on parameter `type` in method `isEffectTypeAvailable`
MissingNullability: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]) parameter #0:
-
+ Missing nullability on parameter `param` in method `setParameter`
MissingNullability: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]) parameter #1:
-
+ Missing nullability on parameter `value` in method `setParameter`
MissingNullability: android.media.audiofx.AudioEffect#setParameter(int, byte[]) parameter #1:
-
+ Missing nullability on parameter `value` in method `setParameter`
MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], byte[]) parameter #0:
-
+ Missing nullability on parameter `param` in method `setParameter`
MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], byte[]) parameter #1:
-
+ Missing nullability on parameter `value` in method `setParameter`
MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], int[]) parameter #0:
-
+ Missing nullability on parameter `param` in method `setParameter`
MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], int[]) parameter #1:
-
+ Missing nullability on parameter `value` in method `setParameter`
MissingNullability: android.media.audiofx.AudioEffect#setParameterListener(android.media.audiofx.AudioEffect.OnParameterChangeListener) parameter #0:
-
+ Missing nullability on parameter `listener` in method `setParameterListener`
MissingNullability: android.media.audiofx.AudioEffect#shortToByteArray(short):
-
+ Missing nullability on method `shortToByteArray` return
MissingNullability: android.media.audiofx.AudioEffect.Descriptor#Descriptor(android.os.Parcel) parameter #0:
-
+ Missing nullability on parameter `in` in method `Descriptor`
MissingNullability: android.media.audiofx.AudioEffect.Descriptor#writeToParcel(android.os.Parcel) parameter #0:
-
+ Missing nullability on parameter `dest` in method `writeToParcel`
MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #0:
-
+ Missing nullability on parameter `effect` in method `onParameterChange`
MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #2:
-
+ Missing nullability on parameter `param` in method `onParameterChange`
MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #3:
-
-MissingNullability: android.media.audiopolicy.AudioMix.Builder#Builder(android.media.audiopolicy.AudioMixingRule) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioMix.Builder#build():
-
-MissingNullability: android.media.audiopolicy.AudioMix.Builder#setDevice(android.media.AudioDeviceInfo):
-
-MissingNullability: android.media.audiopolicy.AudioMix.Builder#setFormat(android.media.AudioFormat):
-
-MissingNullability: android.media.audiopolicy.AudioMix.Builder#setFormat(android.media.AudioFormat) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioMix.Builder#setRouteFlags(int):
-
-MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addMixRule(int, Object):
-
-MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addMixRule(int, Object) parameter #1:
-
-MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addRule(android.media.AudioAttributes, int):
-
-MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addRule(android.media.AudioAttributes, int) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#build():
-
-MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeMixRule(int, Object):
-
-MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeMixRule(int, Object) parameter #1:
-
-MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeRule(android.media.AudioAttributes, int):
-
-MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeRule(android.media.AudioAttributes, int) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioRecordSink(android.media.audiopolicy.AudioMix):
-
-MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioRecordSink(android.media.audiopolicy.AudioMix) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioTrackSource(android.media.audiopolicy.AudioMix):
-
-MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioTrackSource(android.media.audiopolicy.AudioMix) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy#setRegistration(String) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy#toLogFriendlyString():
-
-MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusAbandon(android.media.AudioFocusInfo) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusGrant(android.media.AudioFocusInfo, int) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusLoss(android.media.AudioFocusInfo, boolean) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(android.media.AudioFocusInfo, int) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener#onMixStateUpdate(android.media.audiopolicy.AudioMix) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy.Builder#Builder(android.content.Context) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener) parameter #0:
-
-MissingNullability: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener) parameter #0:
-
-MissingNullability: android.metrics.LogMaker#LogMaker(Object[]) parameter #0:
-
-MissingNullability: android.metrics.LogMaker#addTaggedData(int, Object):
-
-MissingNullability: android.metrics.LogMaker#addTaggedData(int, Object) parameter #1:
-
-MissingNullability: android.metrics.LogMaker#clearCategory():
-
-MissingNullability: android.metrics.LogMaker#clearPackageName():
-
-MissingNullability: android.metrics.LogMaker#clearSubtype():
-
-MissingNullability: android.metrics.LogMaker#clearTaggedData(int):
-
-MissingNullability: android.metrics.LogMaker#clearType():
-
-MissingNullability: android.metrics.LogMaker#deserialize(Object[]) parameter #0:
-
-MissingNullability: android.metrics.LogMaker#getCounterName():
-
-MissingNullability: android.metrics.LogMaker#getPackageName():
-
-MissingNullability: android.metrics.LogMaker#getTaggedData(int):
-
-MissingNullability: android.metrics.LogMaker#isSubsetOf(android.metrics.LogMaker) parameter #0:
-
-MissingNullability: android.metrics.LogMaker#isValidValue(Object) parameter #0:
-
-MissingNullability: android.metrics.LogMaker#serialize():
-
-MissingNullability: android.metrics.LogMaker#setCategory(int):
-
-MissingNullability: android.metrics.LogMaker#setPackageName(String):
-
-MissingNullability: android.metrics.LogMaker#setPackageName(String) parameter #0:
-
-MissingNullability: android.metrics.LogMaker#setSubtype(int):
-
-MissingNullability: android.metrics.LogMaker#setType(int):
-
-MissingNullability: android.metrics.MetricsReader#next():
-
-MissingNullability: android.net.NetworkCapabilities#getCapabilities():
-
-MissingNullability: android.net.StaticIpConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.net.TestNetworkInterface#CREATOR:
-
-MissingNullability: android.net.TestNetworkInterface#TestNetworkInterface(android.os.ParcelFileDescriptor, String) parameter #0:
-
-MissingNullability: android.net.TestNetworkInterface#TestNetworkInterface(android.os.ParcelFileDescriptor, String) parameter #1:
-
-MissingNullability: android.net.TestNetworkInterface#getFileDescriptor():
-
-MissingNullability: android.net.TestNetworkInterface#getInterfaceName():
-
-MissingNullability: android.net.TestNetworkInterface#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.net.TestNetworkManager#createTapInterface():
-
-MissingNullability: android.net.TestNetworkManager#createTunInterface(android.net.LinkAddress[]):
-
-MissingNullability: android.net.apf.ApfCapabilities#CREATOR:
-
-MissingNullability: android.net.apf.ApfCapabilities#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.net.metrics.DhcpClientEvent.Builder#setMsg(String) parameter #0:
-
+ Missing nullability on parameter `value` in method `onParameterChange`
MissingNullability: android.os.Build#is64BitAbi(String) parameter #0:
-
+ Missing nullability on parameter `abi` in method `is64BitAbi`
MissingNullability: android.os.Build.VERSION#ACTIVE_CODENAMES:
-
+ Missing nullability on field `ACTIVE_CODENAMES` in class `class android.os.Build.VERSION`
MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...):
-
+ Missing nullability on method `buildPath` return
MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...) parameter #0:
-
+ Missing nullability on parameter `base` in method `buildPath`
MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...) parameter #1:
-
+ Missing nullability on parameter `segments` in method `buildPath`
MissingNullability: android.os.FileUtils#contains(java.io.File, java.io.File) parameter #0:
-
+ Missing nullability on parameter `dir` in method `contains`
MissingNullability: android.os.FileUtils#contains(java.io.File, java.io.File) parameter #1:
-
-MissingNullability: android.os.HwBinder#getService(String, String):
-
-MissingNullability: android.os.HwBinder#getService(String, String) parameter #0:
-
-MissingNullability: android.os.HwBinder#getService(String, String) parameter #1:
-
-MissingNullability: android.os.HwBinder#getService(String, String, boolean):
-
-MissingNullability: android.os.HwBinder#getService(String, String, boolean) parameter #0:
-
-MissingNullability: android.os.HwBinder#getService(String, String, boolean) parameter #1:
-
-MissingNullability: android.os.HwBinder#onTransact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #1:
-
-MissingNullability: android.os.HwBinder#onTransact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #2:
-
-MissingNullability: android.os.HwBinder#registerService(String) parameter #0:
-
-MissingNullability: android.os.HwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #1:
-
-MissingNullability: android.os.HwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #2:
-
-MissingNullability: android.os.HwBlob#copyToBoolArray(long, boolean[], int) parameter #1:
-
-MissingNullability: android.os.HwBlob#copyToDoubleArray(long, double[], int) parameter #1:
-
-MissingNullability: android.os.HwBlob#copyToFloatArray(long, float[], int) parameter #1:
-
-MissingNullability: android.os.HwBlob#copyToInt16Array(long, short[], int) parameter #1:
-
-MissingNullability: android.os.HwBlob#copyToInt32Array(long, int[], int) parameter #1:
-
-MissingNullability: android.os.HwBlob#copyToInt64Array(long, long[], int) parameter #1:
-
-MissingNullability: android.os.HwBlob#copyToInt8Array(long, byte[], int) parameter #1:
-
-MissingNullability: android.os.HwBlob#getString(long):
-
-MissingNullability: android.os.HwBlob#putBlob(long, android.os.HwBlob) parameter #1:
-
-MissingNullability: android.os.HwBlob#putBoolArray(long, boolean[]) parameter #1:
-
-MissingNullability: android.os.HwBlob#putDoubleArray(long, double[]) parameter #1:
-
-MissingNullability: android.os.HwBlob#putFloatArray(long, float[]) parameter #1:
-
-MissingNullability: android.os.HwBlob#putInt16Array(long, short[]) parameter #1:
-
-MissingNullability: android.os.HwBlob#putInt32Array(long, int[]) parameter #1:
-
-MissingNullability: android.os.HwBlob#putInt64Array(long, long[]) parameter #1:
-
-MissingNullability: android.os.HwBlob#putInt8Array(long, byte[]) parameter #1:
-
-MissingNullability: android.os.HwBlob#putString(long, String) parameter #1:
-
-MissingNullability: android.os.HwBlob#wrapArray(boolean[]):
-
-MissingNullability: android.os.HwBlob#wrapArray(byte[]):
-
-MissingNullability: android.os.HwBlob#wrapArray(double[]):
-
-MissingNullability: android.os.HwBlob#wrapArray(float[]):
-
-MissingNullability: android.os.HwBlob#wrapArray(int[]):
-
-MissingNullability: android.os.HwBlob#wrapArray(long[]):
-
-MissingNullability: android.os.HwBlob#wrapArray(short[]):
-
-MissingNullability: android.os.HwParcel#enforceInterface(String) parameter #0:
-
-MissingNullability: android.os.HwParcel#readBoolVector():
-
-MissingNullability: android.os.HwParcel#readBuffer(long):
-
-MissingNullability: android.os.HwParcel#readDoubleVector():
-
-MissingNullability: android.os.HwParcel#readEmbeddedBuffer(long, long, long, boolean):
-
-MissingNullability: android.os.HwParcel#readFloatVector():
-
-MissingNullability: android.os.HwParcel#readInt16Vector():
-
-MissingNullability: android.os.HwParcel#readInt32Vector():
-
-MissingNullability: android.os.HwParcel#readInt64Vector():
-
-MissingNullability: android.os.HwParcel#readInt8Vector():
-
-MissingNullability: android.os.HwParcel#readString():
-
-MissingNullability: android.os.HwParcel#readStringVector():
-
-MissingNullability: android.os.HwParcel#readStrongBinder():
-
-MissingNullability: android.os.HwParcel#writeBoolVector(java.util.ArrayList<java.lang.Boolean>) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeBuffer(android.os.HwBlob) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeDoubleVector(java.util.ArrayList<java.lang.Double>) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeFloatVector(java.util.ArrayList<java.lang.Float>) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeInt16Vector(java.util.ArrayList<java.lang.Short>) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeInt32Vector(java.util.ArrayList<java.lang.Integer>) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeInt64Vector(java.util.ArrayList<java.lang.Long>) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeInt8Vector(java.util.ArrayList<java.lang.Byte>) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeInterfaceToken(String) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeString(String) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeStringVector(java.util.ArrayList<java.lang.String>) parameter #0:
-
-MissingNullability: android.os.HwParcel#writeStrongBinder(android.os.IHwBinder) parameter #0:
-
-MissingNullability: android.os.IHwBinder#linkToDeath(android.os.IHwBinder.DeathRecipient, long) parameter #0:
-
-MissingNullability: android.os.IHwBinder#queryLocalInterface(String):
-
-MissingNullability: android.os.IHwBinder#queryLocalInterface(String) parameter #0:
-
-MissingNullability: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #1:
-
-MissingNullability: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #2:
-
-MissingNullability: android.os.IHwBinder#unlinkToDeath(android.os.IHwBinder.DeathRecipient) parameter #0:
-
-MissingNullability: android.os.IHwInterface#asBinder():
-
-MissingNullability: android.os.IncidentManager#approveReport(android.net.Uri) parameter #0:
-
-MissingNullability: android.os.IncidentManager#cancelAuthorization(android.os.IncidentManager.AuthListener) parameter #0:
-
-MissingNullability: android.os.IncidentManager#deleteIncidentReports(android.net.Uri) parameter #0:
-
-MissingNullability: android.os.IncidentManager#denyReport(android.net.Uri) parameter #0:
-
-MissingNullability: android.os.IncidentManager#getIncidentReport(android.net.Uri) parameter #0:
-
-MissingNullability: android.os.IncidentManager#getIncidentReportList(String) parameter #0:
-
-MissingNullability: android.os.IncidentManager#getPendingReports():
-
-MissingNullability: android.os.IncidentManager#reportIncident(android.os.IncidentReportArgs) parameter #0:
-
-MissingNullability: android.os.IncidentManager#requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener) parameter #1:
-
-MissingNullability: android.os.IncidentManager#requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener) parameter #3:
-
-MissingNullability: android.os.IncidentManager.IncidentReport#IncidentReport(android.os.Parcel) parameter #0:
-
-MissingNullability: android.os.IncidentManager.IncidentReport#getInputStream():
-
-MissingNullability: android.os.IncidentManager.IncidentReport#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.os.IncidentReportArgs#IncidentReportArgs(android.os.Parcel) parameter #0:
-
-MissingNullability: android.os.IncidentReportArgs#addHeader(byte[]) parameter #0:
-
-MissingNullability: android.os.IncidentReportArgs#readFromParcel(android.os.Parcel) parameter #0:
-
-MissingNullability: android.os.IncidentReportArgs#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `file` in method `contains`
MissingNullability: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor):
-
+ Missing nullability on method `getFile` return
MissingNullability: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor) parameter #0:
-
-MissingNullability: android.os.RemoteCallback#RemoteCallback(android.os.RemoteCallback.OnResultListener) parameter #0:
-
-MissingNullability: android.os.RemoteCallback#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `fd` in method `getFile`
MissingNullability: android.os.StrictMode#setViolationLogger(android.os.StrictMode.ViolationLogger) parameter #0:
-
+ Missing nullability on parameter `listener` in method `setViolationLogger`
MissingNullability: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel) parameter #0:
-
+ Missing nullability on parameter `in` in method `ViolationInfo`
MissingNullability: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel, boolean) parameter #0:
-
+ Missing nullability on parameter `in` in method `ViolationInfo`
MissingNullability: android.os.StrictMode.ViolationInfo#broadcastIntentAction:
-
+ Missing nullability on field `broadcastIntentAction` in class `class android.os.StrictMode.ViolationInfo`
MissingNullability: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String) parameter #0:
-
+ Missing nullability on parameter `pw` in method `dump`
MissingNullability: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String) parameter #1:
-
+ Missing nullability on parameter `prefix` in method `dump`
MissingNullability: android.os.StrictMode.ViolationInfo#getStackTrace():
-
+ Missing nullability on method `getStackTrace` return
MissingNullability: android.os.StrictMode.ViolationInfo#getViolationClass():
-
+ Missing nullability on method `getViolationClass` return
MissingNullability: android.os.StrictMode.ViolationInfo#getViolationDetails():
-
+ Missing nullability on method `getViolationDetails` return
MissingNullability: android.os.StrictMode.ViolationInfo#tags:
-
+ Missing nullability on field `tags` in class `class android.os.StrictMode.ViolationInfo`
MissingNullability: android.os.StrictMode.ViolationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `dest` in method `writeToParcel`
MissingNullability: android.os.StrictMode.ViolationLogger#log(android.os.StrictMode.ViolationInfo) parameter #0:
-
-MissingNullability: android.os.UserHandle#of(int):
-
+ Missing nullability on parameter `info` in method `log`
MissingNullability: android.os.VibrationEffect#RINGTONES:
-
+ Missing nullability on field `RINGTONES` in class `class android.os.VibrationEffect`
MissingNullability: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #0:
-
+ Missing nullability on parameter `uri` in method `get`
MissingNullability: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #1:
-
+ Missing nullability on parameter `context` in method `get`
MissingNullability: android.os.VibrationEffect#get(int):
-
+ Missing nullability on method `get` return
MissingNullability: android.os.VibrationEffect#get(int, boolean):
-
+ Missing nullability on method `get` return
MissingNullability: android.os.VintfObject#getHalNamesAndVersions():
-
+ Missing nullability on method `getHalNamesAndVersions` return
MissingNullability: android.os.VintfObject#getSepolicyVersion():
-
+ Missing nullability on method `getSepolicyVersion` return
MissingNullability: android.os.VintfObject#getTargetFrameworkCompatibilityMatrixVersion():
-
+ Missing nullability on method `getTargetFrameworkCompatibilityMatrixVersion` return
MissingNullability: android.os.VintfObject#getVndkSnapshots():
-
+ Missing nullability on method `getVndkSnapshots` return
MissingNullability: android.os.VintfObject#report():
-
+ Missing nullability on method `report` return
MissingNullability: android.os.VintfRuntimeInfo#getCpuInfo():
-
+ Missing nullability on method `getCpuInfo` return
MissingNullability: android.os.VintfRuntimeInfo#getHardwareId():
-
+ Missing nullability on method `getHardwareId` return
MissingNullability: android.os.VintfRuntimeInfo#getKernelVersion():
-
+ Missing nullability on method `getKernelVersion` return
MissingNullability: android.os.VintfRuntimeInfo#getNodeName():
-
+ Missing nullability on method `getNodeName` return
MissingNullability: android.os.VintfRuntimeInfo#getOsName():
-
+ Missing nullability on method `getOsName` return
MissingNullability: android.os.VintfRuntimeInfo#getOsRelease():
-
+ Missing nullability on method `getOsRelease` return
MissingNullability: android.os.VintfRuntimeInfo#getOsVersion():
-
+ Missing nullability on method `getOsVersion` return
MissingNullability: android.os.WorkSource#add(int, String) parameter #1:
-
-MissingNullability: android.os.WorkSource#addReturningNewbs(android.os.WorkSource) parameter #0:
-
-MissingNullability: android.os.WorkSource#getName(int):
-
-MissingNullability: android.os.WorkSource#setReturningDiffs(android.os.WorkSource) parameter #0:
-
+ Missing nullability on parameter `name` in method `add`
MissingNullability: android.os.health.HealthKeys.Constants#Constants(Class) parameter #0:
-
+ Missing nullability on parameter `clazz` in method `Constants`
MissingNullability: android.os.health.HealthKeys.Constants#getDataType():
-
+ Missing nullability on method `getDataType` return
MissingNullability: android.os.health.HealthKeys.Constants#getKeys(int):
-
+ Missing nullability on method `getKeys` return
MissingNullability: android.os.health.HealthStats#HealthStats(android.os.Parcel) parameter #0:
-
+ Missing nullability on parameter `in` in method `HealthStats`
MissingNullability: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.Parcel) parameter #0:
-
+ Missing nullability on parameter `in` in method `HealthStatsParceler`
MissingNullability: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.health.HealthStatsWriter) parameter #0:
-
+ Missing nullability on parameter `writer` in method `HealthStatsParceler`
MissingNullability: android.os.health.HealthStatsParceler#getHealthStats():
-
+ Missing nullability on method `getHealthStats` return
MissingNullability: android.os.health.HealthStatsParceler#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `out` in method `writeToParcel`
MissingNullability: android.os.health.HealthStatsWriter#HealthStatsWriter(android.os.health.HealthKeys.Constants) parameter #0:
-
+ Missing nullability on parameter `constants` in method `HealthStatsWriter`
MissingNullability: android.os.health.HealthStatsWriter#addMeasurements(int, String, long) parameter #1:
-
+ Missing nullability on parameter `name` in method `addMeasurements`
MissingNullability: android.os.health.HealthStatsWriter#addStats(int, String, android.os.health.HealthStatsWriter) parameter #1:
-
+ Missing nullability on parameter `name` in method `addStats`
MissingNullability: android.os.health.HealthStatsWriter#addStats(int, String, android.os.health.HealthStatsWriter) parameter #2:
-
+ Missing nullability on parameter `value` in method `addStats`
MissingNullability: android.os.health.HealthStatsWriter#addTimers(int, String, android.os.health.TimerStat) parameter #1:
-
+ Missing nullability on parameter `name` in method `addTimers`
MissingNullability: android.os.health.HealthStatsWriter#addTimers(int, String, android.os.health.TimerStat) parameter #2:
-
+ Missing nullability on parameter `value` in method `addTimers`
MissingNullability: android.os.health.HealthStatsWriter#flattenToParcel(android.os.Parcel) parameter #0:
-
+ Missing nullability on parameter `out` in method `flattenToParcel`
MissingNullability: android.os.storage.StorageVolume#getPath():
-
-MissingNullability: android.permission.RuntimePermissionPresentationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on method `getPath` return
MissingNullability: android.provider.CalendarContract.Calendars#SYNC_WRITABLE_COLUMNS:
-
+ Missing nullability on field `SYNC_WRITABLE_COLUMNS` in class `class android.provider.CalendarContract.Calendars`
MissingNullability: android.provider.CalendarContract.Events#SYNC_WRITABLE_COLUMNS:
-
-MissingNullability: android.provider.ContactsContract.CommonDataKinds.Phone#ENTERPRISE_CONTENT_URI:
-
+ Missing nullability on field `SYNC_WRITABLE_COLUMNS` in class `class android.provider.CalendarContract.Events`
MissingNullability: android.provider.ContactsContract.RawContactsEntity#CORP_CONTENT_URI:
-
-MissingNullability: android.provider.DeviceConfig#getProperty(String, String):
-
-MissingNullability: android.provider.DeviceConfig#getString(String, String, String):
-
-MissingNullability: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle) parameter #0:
-
-MissingNullability: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle) parameter #1:
-
-MissingNullability: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle) parameter #2:
-
-MissingNullability: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle) parameter #0:
-
-MissingNullability: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle) parameter #1:
-
-MissingNullability: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle) parameter #2:
-
-MissingNullability: android.provider.MediaStore#scanFile(android.content.Context, java.io.File):
-
-MissingNullability: android.provider.MediaStore#scanFile(android.content.Context, java.io.File) parameter #0:
-
-MissingNullability: android.provider.MediaStore#scanFile(android.content.Context, java.io.File) parameter #1:
-
-MissingNullability: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File):
-
-MissingNullability: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File) parameter #0:
-
-MissingNullability: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File) parameter #1:
-
-MissingNullability: android.provider.MediaStore#scanVolume(android.content.Context, java.io.File) parameter #0:
-
-MissingNullability: android.provider.MediaStore#scanVolume(android.content.Context, java.io.File) parameter #1:
-
-MissingNullability: android.provider.MediaStore#waitForIdle(android.content.Context) parameter #0:
-
-MissingNullability: android.security.KeyStoreException#KeyStoreException(int, String) parameter #1:
-
-MissingNullability: android.security.keystore.AttestationUtils#attestDeviceIds(android.content.Context, int[], byte[]) parameter #0:
-
+ Missing nullability on field `CORP_CONTENT_URI` in class `class android.provider.ContactsContract.RawContactsEntity`
MissingNullability: android.security.keystore.KeyProtection.Builder#setBoundToSpecificSecureUserId(long):
-
-MissingNullability: android.service.autofill.AutofillFieldClassificationService#onBind(android.content.Intent):
-
-MissingNullability: android.service.autofill.AutofillFieldClassificationService#onBind(android.content.Intent) parameter #0:
-
+ Missing nullability on method `setBoundToSpecificSecureUserId` return
MissingNullability: android.service.autofill.CompositeUserData#getCategoryIds():
-
+ Missing nullability on method `getCategoryIds` return
MissingNullability: android.service.autofill.CompositeUserData#getDefaultFieldClassificationArgs():
-
+ Missing nullability on method `getDefaultFieldClassificationArgs` return
MissingNullability: android.service.autofill.CompositeUserData#getFieldClassificationAlgorithms():
-
+ Missing nullability on method `getFieldClassificationAlgorithms` return
MissingNullability: android.service.autofill.CompositeUserData#getFieldClassificationArgs():
-
+ Missing nullability on method `getFieldClassificationArgs` return
MissingNullability: android.service.autofill.CompositeUserData#getValues():
-
+ Missing nullability on method `getValues` return
MissingNullability: android.service.autofill.CompositeUserData#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `parcel` in method `writeToParcel`
MissingNullability: android.service.autofill.UserData#getFieldClassificationAlgorithms():
-
-MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
-
-MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
-
-MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
-
-MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#onUnbind(android.content.Intent) parameter #0:
-
-MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
-
-MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
-
-MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
-
-MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #0:
-
-MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #1:
-
-MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #2:
-
-MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #3:
-
-MissingNullability: android.service.notification.Adjustment#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context) parameter #0:
-
-MissingNullability: android.service.notification.NotificationStats#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(String, CharSequence, CharSequence) parameter #0:
-
-MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(String, CharSequence, CharSequence) parameter #1:
-
-MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(String, CharSequence, CharSequence) parameter #2:
-
-MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(android.os.Parcel) parameter #0:
-
-MissingNullability: android.service.notification.SnoozeCriterion#getConfirmation():
-
-MissingNullability: android.service.notification.SnoozeCriterion#getExplanation():
-
-MissingNullability: android.service.notification.SnoozeCriterion#getId():
-
-MissingNullability: android.service.notification.SnoozeCriterion#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on method `getFieldClassificationAlgorithms` return
MissingNullability: android.telecom.Call.Details#getTelecomCallId():
-
-MissingNullability: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallFurther(boolean):
-
-MissingNullability: android.telecom.Conference#getPrimaryConnection():
-
-MissingNullability: android.telecom.PhoneAccountSuggestionService#onBind(android.content.Intent):
-
-MissingNullability: android.telecom.PhoneAccountSuggestionService#onBind(android.content.Intent) parameter #0:
-
-MissingNullability: android.telephony.CallQuality#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.DataSpecificRegistrationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.LteVopsSupportInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.NetworkRegistrationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on method `getTelecomCallId` return
MissingNullability: android.telephony.ServiceState#addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo) parameter #0:
-
+ Missing nullability on parameter `nri` in method `addNetworkRegistrationInfo`
MissingNullability: android.telephony.ServiceState#setCellBandwidths(int[]) parameter #0:
-
+ Missing nullability on parameter `bandwidths` in method `setCellBandwidths`
MissingNullability: android.telephony.SmsManager#checkSmsShortCodeDestination(String, String) parameter #0:
-
+ Missing nullability on parameter `destAddress` in method `checkSmsShortCodeDestination`
MissingNullability: android.telephony.SmsManager#checkSmsShortCodeDestination(String, String) parameter #1:
-
-MissingNullability: android.telephony.TelephonyManager#checkCarrierPrivilegesForPackage(String) parameter #0:
-
-MissingNullability: android.telephony.TelephonyManager#getCarrierPackageNamesForIntent(android.content.Intent):
-
-MissingNullability: android.telephony.TelephonyManager#getCarrierPackageNamesForIntent(android.content.Intent) parameter #0:
-
+ Missing nullability on parameter `countryIso` in method `checkSmsShortCodeDestination`
MissingNullability: android.telephony.TelephonyManager#getLine1AlphaTag():
-
+ Missing nullability on method `getLine1AlphaTag` return
MissingNullability: android.telephony.TelephonyManager#getRadioHalVersion():
-
-MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #0:
-
-MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #1:
-
-MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #2:
-
-MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #3:
-
-MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #4:
-
-MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #5:
-
-MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #6:
-
+ Missing nullability on method `getRadioHalVersion` return
MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #0:
-
+ Missing nullability on parameter `mccmnc` in method `setCarrierTestOverride`
MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #1:
-
+ Missing nullability on parameter `imsi` in method `setCarrierTestOverride`
MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #2:
-
+ Missing nullability on parameter `iccid` in method `setCarrierTestOverride`
MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #3:
-
+ Missing nullability on parameter `gid1` in method `setCarrierTestOverride`
MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #4:
-
+ Missing nullability on parameter `gid2` in method `setCarrierTestOverride`
MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #5:
-
+ Missing nullability on parameter `plmn` in method `setCarrierTestOverride`
MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #6:
-
+ Missing nullability on parameter `spn` in method `setCarrierTestOverride`
MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #7:
-
+ Missing nullability on parameter `carrierPriviledgeRules` in method `setCarrierTestOverride`
MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #8:
-
-MissingNullability: android.telephony.ims.ImsCallForwardInfo#getNumber():
-
-MissingNullability: android.telephony.ims.ImsCallForwardInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile) parameter #2:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile) parameter #3:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String):
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String, String):
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String, String) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtra(String, String) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraBoolean(String) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraBoolean(String, boolean) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraInt(String) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtraInt(String, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getCallExtras():
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getMediaProfile():
-
-MissingNullability: android.telephony.ims.ImsCallProfile#getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtra(String, String) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtra(String, String) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtraBoolean(String, boolean) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#setCallExtraInt(String, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#updateCallExtras(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#updateCallType(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#updateMediaProfile(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallProfile#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtendFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo) parameter #2:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo) parameter #2:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHeld(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHoldFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionHoldReceived(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionInitiated(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionProgressing(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionRemoveParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionResumeFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionResumeReceived(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionResumed(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionRttMessageReceived(String) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionSuppServiceReceived(android.telephony.ims.ImsSuppServiceNotification) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionTerminated(android.telephony.ims.ImsReasonInfo) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUpdateFailed(android.telephony.ims.ImsReasonInfo) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUpdateReceived(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUpdated(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsCallSessionListener#callSessionUssdMessageReceived(int, String) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsConferenceState#getConnectionStateForStatus(String) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsConferenceState#mParticipants:
-
-MissingNullability: android.telephony.ims.ImsConferenceState#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsExternalCallState#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsReasonInfo#ImsReasonInfo(int, int, String) parameter #2:
-
-MissingNullability: android.telephony.ims.ImsReasonInfo#getExtraMessage():
-
-MissingNullability: android.telephony.ims.ImsReasonInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsService#createMmTelFeature(int):
-
-MissingNullability: android.telephony.ims.ImsService#createRcsFeature(int):
-
-MissingNullability: android.telephony.ims.ImsService#getConfig(int):
-
-MissingNullability: android.telephony.ims.ImsService#getRegistration(int):
-
-MissingNullability: android.telephony.ims.ImsService#onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsService#querySupportedImsFeatures():
-
-MissingNullability: android.telephony.ims.ImsSsData#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsSsInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsStreamMediaProfile#copyFrom(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsStreamMediaProfile#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsSuppServiceNotification#ImsSuppServiceNotification(int, int, int, int, String, String[]) parameter #4:
-
-MissingNullability: android.telephony.ims.ImsSuppServiceNotification#ImsSuppServiceNotification(int, int, int, int, String, String[]) parameter #5:
-
-MissingNullability: android.telephony.ims.ImsSuppServiceNotification#history:
-
-MissingNullability: android.telephony.ims.ImsSuppServiceNotification#number:
-
-MissingNullability: android.telephony.ims.ImsSuppServiceNotification#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsUtListener#onSupplementaryServiceIndication(android.telephony.ims.ImsSsData) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationCallBarringQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationCallForwardQueried(int, android.telephony.ims.ImsCallForwardInfo[]) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationCallWaitingQueried(int, android.telephony.ims.ImsSsInfo[]) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationQueried(int, android.os.Bundle) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationQueryFailed(int, android.telephony.ims.ImsReasonInfo) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsUtListener#onUtConfigurationUpdateFailed(int, android.telephony.ims.ImsReasonInfo) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSendSessionModifyResponse(android.telecom.VideoProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetCamera(String) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetCamera(String, int) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetDisplaySurface(android.view.Surface) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetPauseImage(android.net.Uri) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#onSetPreviewSurface(android.view.Surface) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#receiveSessionModifyRequest(android.telecom.VideoProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #1:
-
-MissingNullability: android.telephony.ims.ImsVideoCallProvider#receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile) parameter #2:
-
-MissingNullability: android.telephony.ims.feature.CapabilityChangeRequest#getCapabilitiesToDisable():
-
-MissingNullability: android.telephony.ims.feature.CapabilityChangeRequest#getCapabilitiesToEnable():
-
-MissingNullability: android.telephony.ims.feature.CapabilityChangeRequest#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.feature.ImsFeature#changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy) parameter #0:
-
-MissingNullability: android.telephony.ims.feature.ImsFeature#changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy) parameter #1:
-
-MissingNullability: android.telephony.ims.feature.MmTelFeature#queryCapabilityStatus():
-
-MissingNullability: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#accept(int, android.telephony.ims.ImsStreamMediaProfile) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#deflect(String) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#extendToConference(String[]) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getCallId():
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getCallProfile():
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getImsVideoCallProvider():
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getLocalCallProfile():
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getProperty(String):
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getProperty(String) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#getRemoteCallProfile():
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#hold(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#inviteParticipants(String[]) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#removeParticipants(String[]) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#resume(android.telephony.ims.ImsStreamMediaProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendDtmf(char, android.os.Message) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendRttMessage(String) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendRttModifyRequest(android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#sendUssd(String) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#setListener(android.telephony.ims.ImsCallSessionListener) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#start(String, android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#start(String, android.telephony.ims.ImsCallProfile) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#startConference(String[], android.telephony.ims.ImsCallProfile) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#startConference(String[], android.telephony.ims.ImsCallProfile) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase#update(int, android.telephony.ims.ImsStreamMediaProfile) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsCallSessionImplBase.State#toString(int):
-
-MissingNullability: android.telephony.ims.stub.ImsConfigImplBase#getConfigString(int):
-
-MissingNullability: android.telephony.ims.stub.ImsConfigImplBase#notifyProvisionedValueChanged(int, String) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsConfigImplBase#setConfig(int, String) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration#getServiceFeatures():
-
-MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration.Builder#addFeature(int, int):
-
-MissingNullability: android.telephony.ims.stub.ImsFeatureConfiguration.Builder#build():
-
-MissingNullability: android.telephony.ims.stub.ImsMultiEndpointImplBase#onImsExternalCallStateUpdate(java.util.List<android.telephony.ims.ImsExternalCallState>) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsRegistrationImplBase#onDeregistered(android.telephony.ims.ImsReasonInfo) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsRegistrationImplBase#onSubscriberAssociatedUriChanged(android.net.Uri[]) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsRegistrationImplBase#onTechnologyChangeFailed(int, android.telephony.ims.ImsReasonInfo) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#getSmsFormat():
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsReceived(int, String, byte[]) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsReceived(int, String, byte[]) parameter #2:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, String, byte[]) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, String, byte[]) parameter #2:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, int, String, byte[]) parameter #2:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, int, String, byte[]) parameter #3:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#sendSms(int, int, String, String, boolean, byte[]) parameter #2:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#sendSms(int, int, String, String, boolean, byte[]) parameter #3:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#sendSms(int, int, String, String, boolean, byte[]) parameter #5:
-
-MissingNullability: android.telephony.ims.stub.ImsUtImplBase#queryCallForward(int, String) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsUtImplBase#setListener(android.telephony.ims.ImsUtListener) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsUtImplBase#transact(android.os.Bundle) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsUtImplBase#updateCallBarring(int, int, String[]) parameter #2:
-
-MissingNullability: android.telephony.ims.stub.ImsUtImplBase#updateCallBarringForServiceClass(int, int, String[], int) parameter #2:
-
-MissingNullability: android.telephony.ims.stub.ImsUtImplBase#updateCallForward(int, int, String, int, int) parameter #2:
-
-MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
-
-MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String) parameter #0:
-
-MissingNullability: android.telephony.mbms.FileInfo#FileInfo(android.net.Uri, String) parameter #0:
-
-MissingNullability: android.telephony.mbms.FileInfo#FileInfo(android.net.Uri, String) parameter #1:
-
-MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #0:
-
-MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #1:
-
-MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #2:
-
-MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #3:
-
-MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #4:
-
-MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #5:
-
-MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #6:
-
-MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #0:
-
-MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #1:
-
-MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #2:
-
-MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #3:
-
-MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #4:
-
-MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #5:
-
-MissingNullability: android.telephony.mbms.UriPathPair#getContentUri():
-
-MissingNullability: android.telephony.mbms.UriPathPair#getFilePathUri():
-
-MissingNullability: android.telephony.mbms.UriPathPair#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#asBinder():
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#cancelDownload(android.telephony.mbms.DownloadRequest) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#download(android.telephony.mbms.DownloadRequest) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #2:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestUpdateFileServices(int, java.util.List<java.lang.String>) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#setTempFileRootDirectory(int, String) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#onBind(android.content.Intent):
-
-MissingNullability: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#onBind(android.content.Intent) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#asBinder():
-
-MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#getPlaybackUri(int, String) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #2:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#requestUpdateStreamingServices(int, java.util.List<java.lang.String>) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback) parameter #2:
-
-MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#stopStreaming(int, String) parameter #1:
-
-MissingNullability: android.telephony.mbms.vendor.VendorUtils#getAppReceiverFromPackageName(android.content.Context, String):
-
-MissingNullability: android.telephony.mbms.vendor.VendorUtils#getAppReceiverFromPackageName(android.content.Context, String) parameter #0:
-
-MissingNullability: android.telephony.mbms.vendor.VendorUtils#getAppReceiverFromPackageName(android.content.Context, String) parameter #1:
-
+ Missing nullability on parameter `apn` in method `setCarrierTestOverride`
MissingNullability: android.text.Selection.MemoryTextWatcher#afterTextChanged(android.text.Editable) parameter #0:
-
+ Missing nullability on parameter `s` in method `afterTextChanged`
MissingNullability: android.text.Selection.MemoryTextWatcher#beforeTextChanged(CharSequence, int, int, int) parameter #0:
-
+ Missing nullability on parameter `s` in method `beforeTextChanged`
MissingNullability: android.text.Selection.MemoryTextWatcher#onTextChanged(CharSequence, int, int, int) parameter #0:
-
+ Missing nullability on parameter `s` in method `onTextChanged`
MissingNullability: android.transition.TransitionManager#getTransition(android.transition.Scene):
-
+ Missing nullability on method `getTransition` return
MissingNullability: android.transition.TransitionManager#getTransition(android.transition.Scene) parameter #0:
-
+ Missing nullability on parameter `scene` in method `getTransition`
MissingNullability: android.util.FeatureFlagUtils#getAllFeatureFlags():
-
+ Missing nullability on method `getAllFeatureFlags` return
MissingNullability: android.util.FeatureFlagUtils#isEnabled(android.content.Context, String) parameter #0:
-
+ Missing nullability on parameter `context` in method `isEnabled`
MissingNullability: android.util.FeatureFlagUtils#isEnabled(android.content.Context, String) parameter #1:
-
+ Missing nullability on parameter `feature` in method `isEnabled`
MissingNullability: android.util.FeatureFlagUtils#setEnabled(android.content.Context, String, boolean) parameter #0:
-
+ Missing nullability on parameter `context` in method `setEnabled`
MissingNullability: android.util.FeatureFlagUtils#setEnabled(android.content.Context, String, boolean) parameter #1:
-
+ Missing nullability on parameter `feature` in method `setEnabled`
MissingNullability: android.util.TimeUtils#formatDuration(long):
-
+ Missing nullability on method `formatDuration` return
MissingNullability: android.util.proto.EncodedBuffer#dumpBuffers(String) parameter #0:
-
+ Missing nullability on parameter `tag` in method `dumpBuffers`
MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #0:
-
+ Missing nullability on parameter `tag` in method `dumpByteString`
MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #1:
-
+ Missing nullability on parameter `prefix` in method `dumpByteString`
MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #2:
-
+ Missing nullability on parameter `buf` in method `dumpByteString`
MissingNullability: android.util.proto.EncodedBuffer#getBytes(int):
-
+ Missing nullability on method `getBytes` return
MissingNullability: android.util.proto.EncodedBuffer#getDebugString():
-
+ Missing nullability on method `getDebugString` return
MissingNullability: android.util.proto.EncodedBuffer#writeRawBuffer(byte[]) parameter #0:
-
+ Missing nullability on parameter `val` in method `writeRawBuffer`
MissingNullability: android.util.proto.EncodedBuffer#writeRawBuffer(byte[], int, int) parameter #0:
-
-MissingNullability: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.FileDescriptor) parameter #0:
-
-MissingNullability: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.OutputStream) parameter #0:
-
-MissingNullability: android.util.proto.ProtoOutputStream#dump(String) parameter #0:
-
-MissingNullability: android.util.proto.ProtoOutputStream#getBytes():
-
-MissingNullability: android.util.proto.ProtoOutputStream#write(long, String) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#write(long, byte[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writeBytes(long, byte[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writeObject(long, byte[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedBool(long, boolean[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedDouble(long, double[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedEnum(long, int[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedFixed32(long, int[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedFixed64(long, long[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedFloat(long, float[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedInt32(long, int[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedInt64(long, long[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedSFixed32(long, int[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedSFixed64(long, long[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedSInt32(long, int[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedSInt64(long, long[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedUInt32(long, int[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writePackedUInt64(long, long[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writeRepeatedBytes(long, byte[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writeRepeatedObject(long, byte[]) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writeRepeatedString(long, String) parameter #1:
-
-MissingNullability: android.util.proto.ProtoOutputStream#writeString(long, String) parameter #1:
-
+ Missing nullability on parameter `val` in method `writeRawBuffer`
MissingNullability: android.util.proto.ProtoParseException#ProtoParseException(String) parameter #0:
-
-MissingNullability: android.util.proto.ProtoStream#FIELD_TYPE_NAMES:
-
-MissingNullability: android.util.proto.ProtoStream#getFieldCountString(long):
-
-MissingNullability: android.util.proto.ProtoStream#getFieldIdString(long):
-
-MissingNullability: android.util.proto.ProtoStream#getFieldTypeString(long):
-
-MissingNullability: android.util.proto.ProtoStream#getWireTypeString(int):
-
-MissingNullability: android.util.proto.ProtoStream#token2String(long):
-
+ Missing nullability on parameter `msg` in method `ProtoParseException`
MissingNullability: android.util.proto.WireTypeMismatchException#WireTypeMismatchException(String) parameter #0:
-
+ Missing nullability on parameter `msg` in method `WireTypeMismatchException`
MissingNullability: android.view.Choreographer#postCallback(int, Runnable, Object) parameter #1:
-
+ Missing nullability on parameter `action` in method `postCallback`
MissingNullability: android.view.Choreographer#postCallback(int, Runnable, Object) parameter #2:
-
+ Missing nullability on parameter `token` in method `postCallback`
MissingNullability: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long) parameter #1:
-
+ Missing nullability on parameter `action` in method `postCallbackDelayed`
MissingNullability: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long) parameter #2:
-
+ Missing nullability on parameter `token` in method `postCallbackDelayed`
MissingNullability: android.view.Choreographer#removeCallbacks(int, Runnable, Object) parameter #1:
-
+ Missing nullability on parameter `action` in method `removeCallbacks`
MissingNullability: android.view.Choreographer#removeCallbacks(int, Runnable, Object) parameter #2:
-
+ Missing nullability on parameter `token` in method `removeCallbacks`
MissingNullability: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #0:
-
+ Missing nullability on parameter `views` in method `sort`
MissingNullability: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #3:
-
+ Missing nullability on parameter `root` in method `sort`
MissingNullability: android.view.KeyEvent#actionToString(int):
-
-MissingNullability: android.view.SurfaceControlViewHost#SurfaceControlViewHost(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #0:
-
-MissingNullability: android.view.SurfaceControlViewHost#SurfaceControlViewHost(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #1:
-
-MissingNullability: android.view.SurfaceControlViewHost#SurfaceControlViewHost(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #2:
-
-MissingNullability: android.view.SurfaceControlViewHost#addView(android.view.View, android.view.WindowManager.LayoutParams) parameter #0:
-
-MissingNullability: android.view.SurfaceControlViewHost#addView(android.view.View, android.view.WindowManager.LayoutParams) parameter #1:
-
+ Missing nullability on method `actionToString` return
MissingNullability: android.view.SurfaceControlViewHost#relayout(android.view.WindowManager.LayoutParams) parameter #0:
-
+ Missing nullability on parameter `attrs` in method `relayout`
MissingNullability: android.view.View#getTooltipView():
-
+ Missing nullability on method `getTooltipView` return
MissingNullability: android.view.View#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #0:
-
+ Missing nullability on parameter `background` in method `isDefaultFocusHighlightNeeded`
MissingNullability: android.view.View#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #1:
-
+ Missing nullability on parameter `foreground` in method `isDefaultFocusHighlightNeeded`
MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #0:
-
+ Missing nullability on parameter `tree` in method `startRenderingCommandsCapture`
MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #1:
-
+ Missing nullability on parameter `executor` in method `startRenderingCommandsCapture`
MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #2:
-
-MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>) parameter #0:
-
-MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>) parameter #1:
-
-MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>) parameter #2:
-
+ Missing nullability on parameter `callback` in method `startRenderingCommandsCapture`
MissingNullability: android.view.WindowManager#holdLock(android.os.IBinder, int) parameter #0:
-
+ Missing nullability on parameter `token` in method `holdLock`
MissingNullability: android.view.WindowManager.LayoutParams#accessibilityTitle:
-
-MissingNullability: android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener#onAccessibilityServicesStateChanged(android.view.accessibility.AccessibilityManager) parameter #0:
-
-MissingNullability: android.view.accessibility.AccessibilityNodeInfo#setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger) parameter #0:
-
+ Missing nullability on field `accessibilityTitle` in class `class android.view.WindowManager.LayoutParams`
MissingNullability: android.view.accessibility.AccessibilityNodeInfo#writeToParcelNoRecycle(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `parcel` in method `writeToParcelNoRecycle`
MissingNullability: android.view.accessibility.AccessibilityWindowInfo#setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger) parameter #0:
-
-MissingNullability: android.view.contentcapture.ContentCaptureEvent#writeToParcel(android.os.Parcel, int) parameter #0:
-
+ Missing nullability on parameter `counter` in method `setNumInstancesInUseCounter`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#asyncNewChild(int):
-
+ Missing nullability on method `asyncNewChild` return
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getAutofillId():
-
+ Missing nullability on method `getAutofillId` return
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getExtras():
-
+ Missing nullability on method `getExtras` return
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getHint():
-
+ Missing nullability on method `getHint` return
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getNode():
-
+ Missing nullability on method `getNode` return
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getTempRect():
-
+ Missing nullability on method `getTempRect` return
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getText():
-
+ Missing nullability on method `getText` return
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newChild(int):
-
+ Missing nullability on method `newChild` return
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newHtmlInfoBuilder(String):
-
+ Missing nullability on method `newHtmlInfoBuilder` return
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newHtmlInfoBuilder(String) parameter #0:
-
+ Missing nullability on parameter `tagName` in method `newHtmlInfoBuilder`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillHints(String[]) parameter #0:
-
+ Missing nullability on parameter `hints` in method `setAutofillHints`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillId(android.view.autofill.AutofillId) parameter #0:
-
+ Missing nullability on parameter `id` in method `setAutofillId`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillId(android.view.autofill.AutofillId, int) parameter #0:
-
+ Missing nullability on parameter `parentId` in method `setAutofillId`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillOptions(CharSequence[]) parameter #0:
-
+ Missing nullability on parameter `options` in method `setAutofillOptions`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillValue(android.view.autofill.AutofillValue) parameter #0:
-
+ Missing nullability on parameter `value` in method `setAutofillValue`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setClassName(String) parameter #0:
-
+ Missing nullability on parameter `className` in method `setClassName`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setContentDescription(CharSequence) parameter #0:
-
+ Missing nullability on parameter `contentDescription` in method `setContentDescription`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHint(CharSequence) parameter #0:
-
+ Missing nullability on parameter `hint` in method `setHint`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHintIdEntry(String) parameter #0:
-
+ Missing nullability on parameter `entryName` in method `setHintIdEntry`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHtmlInfo(android.view.ViewStructure.HtmlInfo) parameter #0:
-
+ Missing nullability on parameter `htmlInfo` in method `setHtmlInfo`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #1:
-
+ Missing nullability on parameter `packageName` in method `setId`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #2:
-
+ Missing nullability on parameter `typeName` in method `setId`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #3:
-
+ Missing nullability on parameter `entryName` in method `setId`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setLocaleList(android.os.LocaleList) parameter #0:
-
+ Missing nullability on parameter `localeList` in method `setLocaleList`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setText(CharSequence) parameter #0:
-
+ Missing nullability on parameter `text` in method `setText`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setText(CharSequence, int, int) parameter #0:
-
+ Missing nullability on parameter `text` in method `setText`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTextLines(int[], int[]) parameter #0:
-
+ Missing nullability on parameter `charOffsets` in method `setTextLines`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTextLines(int[], int[]) parameter #1:
-
+ Missing nullability on parameter `baselines` in method `setTextLines`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTransformation(android.graphics.Matrix) parameter #0:
-
+ Missing nullability on parameter `matrix` in method `setTransformation`
MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setWebDomain(String) parameter #0:
-
+ Missing nullability on parameter `domain` in method `setWebDomain`
MissingNullability: android.widget.CalendarView#getBoundsForDate(long, android.graphics.Rect) parameter #1:
-
+ Missing nullability on parameter `outBounds` in method `getBoundsForDate`
MissingNullability: android.widget.ImageView#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #0:
-
+ Missing nullability on parameter `background` in method `isDefaultFocusHighlightNeeded`
MissingNullability: android.widget.ImageView#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #1:
-
+ Missing nullability on parameter `foreground` in method `isDefaultFocusHighlightNeeded`
MissingNullability: android.widget.Magnifier#getMagnifierDefaultSize():
-
+ Missing nullability on method `getMagnifierDefaultSize` return
MissingNullability: android.widget.Magnifier#setOnOperationCompleteCallback(android.widget.Magnifier.Callback) parameter #0:
-
+ Missing nullability on parameter `callback` in method `setOnOperationCompleteCallback`
MissingNullability: android.widget.NumberPicker#getDisplayedValueForCurrentSelection():
-
+ Missing nullability on method `getDisplayedValueForCurrentSelection` return
MissingNullability: android.widget.PopupMenu#getMenuListView():
-
+ Missing nullability on method `getMenuListView` return
MissingNullability: android.widget.TimePicker#getAmView():
-
+ Missing nullability on method `getAmView` return
MissingNullability: android.widget.TimePicker#getHourView():
-
+ Missing nullability on method `getHourView` return
MissingNullability: android.widget.TimePicker#getMinuteView():
-
+ Missing nullability on method `getMinuteView` return
MissingNullability: android.widget.TimePicker#getPmView():
-
+ Missing nullability on method `getPmView` return
MutableBareField: android.content.AutofillOptions#appDisabledExpiration:
-
+ Bare field appDisabledExpiration must be marked final, or moved behind accessors if mutable
MutableBareField: android.content.AutofillOptions#augmentedAutofillEnabled:
-
+ Bare field augmentedAutofillEnabled must be marked final, or moved behind accessors if mutable
MutableBareField: android.content.AutofillOptions#disabledActivities:
-
+ Bare field disabledActivities must be marked final, or moved behind accessors if mutable
MutableBareField: android.content.AutofillOptions#whitelistedActivitiesForAugmentedAutofill:
-
+ Bare field whitelistedActivitiesForAugmentedAutofill must be marked final, or moved behind accessors if mutable
MutableBareField: android.content.pm.UserInfo#convertedFromPreCreated:
Bare field convertedFromPreCreated must be marked final, or moved behind accessors if mutable
MutableBareField: android.content.pm.UserInfo#creationTime:
@@ -2438,588 +796,230 @@ MutableBareField: android.content.pm.UserInfo#serialNumber:
MutableBareField: android.content.pm.UserInfo#userType:
Bare field userType must be marked final, or moved behind accessors if mutable
MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#cache:
-
+ Bare field cache must be marked final, or moved behind accessors if mutable
MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#dbName:
-
+ Bare field dbName must be marked final, or moved behind accessors if mutable
MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#dbSize:
-
+ Bare field dbSize must be marked final, or moved behind accessors if mutable
MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#lookaside:
-
+ Bare field lookaside must be marked final, or moved behind accessors if mutable
MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#pageSize:
-
+ Bare field pageSize must be marked final, or moved behind accessors if mutable
MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#dbStats:
-
+ Bare field dbStats must be marked final, or moved behind accessors if mutable
MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#largestMemAlloc:
-
+ Bare field largestMemAlloc must be marked final, or moved behind accessors if mutable
MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#memoryUsed:
-
+ Bare field memoryUsed must be marked final, or moved behind accessors if mutable
MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#pageCacheOverflow:
-
+ Bare field pageCacheOverflow must be marked final, or moved behind accessors if mutable
MutableBareField: android.os.StrictMode.ViolationInfo#broadcastIntentAction:
-
+ Bare field broadcastIntentAction must be marked final, or moved behind accessors if mutable
MutableBareField: android.os.StrictMode.ViolationInfo#durationMillis:
-
+ Bare field durationMillis must be marked final, or moved behind accessors if mutable
MutableBareField: android.os.StrictMode.ViolationInfo#numAnimationsRunning:
-
+ Bare field numAnimationsRunning must be marked final, or moved behind accessors if mutable
MutableBareField: android.os.StrictMode.ViolationInfo#numInstances:
-
+ Bare field numInstances must be marked final, or moved behind accessors if mutable
MutableBareField: android.os.StrictMode.ViolationInfo#tags:
-
+ Bare field tags must be marked final, or moved behind accessors if mutable
MutableBareField: android.os.StrictMode.ViolationInfo#violationNumThisLoop:
-
+ Bare field violationNumThisLoop must be marked final, or moved behind accessors if mutable
MutableBareField: android.os.StrictMode.ViolationInfo#violationUptimeMillis:
-
+ Bare field violationUptimeMillis must be marked final, or moved behind accessors if mutable
NoByteOrShort: android.media.audiofx.AudioEffect#byteArrayToShort(byte[]):
-
+ Should avoid odd sized primitives; use `int` instead of `short` in method android.media.audiofx.AudioEffect.byteArrayToShort(byte[])
NoByteOrShort: android.media.audiofx.AudioEffect#setParameter(int, short) parameter #1:
-
+ Should avoid odd sized primitives; use `int` instead of `short` in parameter value in android.media.audiofx.AudioEffect.setParameter(int param, short value)
NoByteOrShort: android.media.audiofx.AudioEffect#shortToByteArray(short) parameter #0:
-
-NoByteOrShort: android.os.HwBlob#getInt16(long):
-
-NoByteOrShort: android.os.HwBlob#getInt8(long):
-
-NoByteOrShort: android.os.HwBlob#putInt16(long, short) parameter #1:
-
-NoByteOrShort: android.os.HwBlob#putInt8(long, byte) parameter #1:
-
-NoByteOrShort: android.os.HwParcel#readInt16():
-
-NoByteOrShort: android.os.HwParcel#readInt8():
-
-NoByteOrShort: android.os.HwParcel#writeInt16(short) parameter #0:
-
-NoByteOrShort: android.os.HwParcel#writeInt8(byte) parameter #0:
-
+ Should avoid odd sized primitives; use `int` instead of `short` in parameter value in android.media.audiofx.AudioEffect.shortToByteArray(short value)
NoByteOrShort: android.util.proto.EncodedBuffer#readRawByte():
-
+ Should avoid odd sized primitives; use `int` instead of `byte` in method android.util.proto.EncodedBuffer.readRawByte()
NoByteOrShort: android.util.proto.EncodedBuffer#writeRawByte(byte) parameter #0:
-
-
-
-NoClone: android.net.util.SocketUtils#bindSocketToInterface(java.io.FileDescriptor, String) parameter #0:
-
-NoClone: android.net.util.SocketUtils#closeSocket(java.io.FileDescriptor) parameter #0:
-
-NoClone: android.os.NativeHandle#NativeHandle(java.io.FileDescriptor, boolean) parameter #0:
-
-NoClone: android.os.NativeHandle#getFileDescriptor():
-
-NoClone: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor) parameter #0:
-
-NoClone: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
-
-NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
-
-NoClone: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.FileDescriptor) parameter #0:
-
+ Should avoid odd sized primitives; use `int` instead of `byte` in parameter val in android.util.proto.EncodedBuffer.writeRawByte(byte val)
NoSettingsProvider: android.provider.Settings.Global#APP_OPS_CONSTANTS:
-
-NoSettingsProvider: android.provider.Settings.Global#AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES:
-
+ New setting keys are not allowed (Field: APP_OPS_CONSTANTS); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Global#AUTOMATIC_POWER_SAVE_MODE:
-
+ New setting keys are not allowed (Field: AUTOMATIC_POWER_SAVE_MODE); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Global#BATTERY_SAVER_CONSTANTS:
-
+ New setting keys are not allowed (Field: BATTERY_SAVER_CONSTANTS); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Global#DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD:
-
+ New setting keys are not allowed (Field: DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Global#DYNAMIC_POWER_SAVINGS_ENABLED:
-
+ New setting keys are not allowed (Field: DYNAMIC_POWER_SAVINGS_ENABLED); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Global#HIDDEN_API_BLACKLIST_EXEMPTIONS:
-
+ New setting keys are not allowed (Field: HIDDEN_API_BLACKLIST_EXEMPTIONS); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Global#HIDDEN_API_POLICY:
-
+ New setting keys are not allowed (Field: HIDDEN_API_POLICY); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Global#HIDE_ERROR_DIALOGS:
-
-NoSettingsProvider: android.provider.Settings.Global#LOCATION_GLOBAL_KILL_SWITCH:
-
-NoSettingsProvider: android.provider.Settings.Global#LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST:
-
+ New setting keys are not allowed (Field: HIDE_ERROR_DIALOGS); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Global#LOW_POWER_MODE:
-
+ New setting keys are not allowed (Field: LOW_POWER_MODE); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Global#LOW_POWER_MODE_STICKY:
-
-NoSettingsProvider: android.provider.Settings.Global#NOTIFICATION_BUBBLES:
-
+ New setting keys are not allowed (Field: LOW_POWER_MODE_STICKY); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Global#OVERLAY_DISPLAY_DEVICES:
-
-NoSettingsProvider: android.provider.Settings.Global#TETHER_OFFLOAD_DISABLED:
-
-NoSettingsProvider: android.provider.Settings.Global#USE_OPEN_WIFI_PACKAGE:
-
+ New setting keys are not allowed (Field: OVERLAY_DISPLAY_DEVICES); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:
-
+ New setting keys are not allowed (Field: ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_CAPABILITY:
-
+ New setting keys are not allowed (Field: ACCESSIBILITY_MAGNIFICATION_CAPABILITY); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE:
-
-NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_ALL:
-
-NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN:
-
-NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW:
-
+ New setting keys are not allowed (Field: ACCESSIBILITY_MAGNIFICATION_MODE); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE:
-
-NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_FEATURE_FIELD_CLASSIFICATION:
-
+ New setting keys are not allowed (Field: ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_SERVICE:
-
-NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT:
-
-NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE:
-
-NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE:
-
-NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_USER_DATA_MAX_VALUE_LENGTH:
-
-NoSettingsProvider: android.provider.Settings.Secure#AUTOFILL_USER_DATA_MIN_VALUE_LENGTH:
-
+ New setting keys are not allowed (Field: AUTOFILL_SERVICE); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#CONTENT_CAPTURE_ENABLED:
-
+ New setting keys are not allowed (Field: CONTENT_CAPTURE_ENABLED); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#DISABLED_PRINT_SERVICES:
-
-NoSettingsProvider: android.provider.Settings.Secure#DOZE_ALWAYS_ON:
-
+ New setting keys are not allowed (Field: DISABLED_PRINT_SERVICES); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#ENABLED_VR_LISTENERS:
-
+ New setting keys are not allowed (Field: ENABLED_VR_LISTENERS); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#IMMERSIVE_MODE_CONFIRMATIONS:
-
-NoSettingsProvider: android.provider.Settings.Secure#LOCATION_ACCESS_CHECK_DELAY_MILLIS:
-
-NoSettingsProvider: android.provider.Settings.Secure#LOCATION_ACCESS_CHECK_INTERVAL_MILLIS:
-
-NoSettingsProvider: android.provider.Settings.Secure#LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS:
-
-NoSettingsProvider: android.provider.Settings.Secure#LOCK_SCREEN_SHOW_NOTIFICATIONS:
-
-NoSettingsProvider: android.provider.Settings.Secure#NFC_PAYMENT_DEFAULT_COMPONENT:
-
+ New setting keys are not allowed (Field: IMMERSIVE_MODE_CONFIRMATIONS); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#NOTIFICATION_BADGING:
-
+ New setting keys are not allowed (Field: NOTIFICATION_BADGING); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#POWER_MENU_LOCKED_SHOW_CONTENT:
-
+ New setting keys are not allowed (Field: POWER_MENU_LOCKED_SHOW_CONTENT); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#SYNC_PARENT_SOUNDS:
-
-NoSettingsProvider: android.provider.Settings.Secure#USER_SETUP_COMPLETE:
-
+ New setting keys are not allowed (Field: SYNC_PARENT_SOUNDS); use getters/setters in relevant manager class
NoSettingsProvider: android.provider.Settings.Secure#VOICE_INTERACTION_SERVICE:
-
+ New setting keys are not allowed (Field: VOICE_INTERACTION_SERVICE); use getters/setters in relevant manager class
-NotCloseable: android.app.prediction.AppPredictor:
-
-NotCloseable: android.net.EthernetManager.TetheredInterfaceRequest:
-
-NotCloseable: android.os.HwParcel:
-
-NotCloseable: android.telephony.ims.stub.ImsUtImplBase:
-
-
-
-NullableCollection: android.os.UserManager#createProfileForUser(String, String, int, int, String[]) parameter #4:
- Type of parameter disallowedPackages in android.os.UserManager.createProfileForUser(String name, String userType, int flags, int userId, String[] disallowedPackages) is a nullable collection (`java.lang.String[]`); must be non-null
-
-
-OnNameExpected: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.PrintWriter, String[]):
-
-OnNameExpected: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
-
OnNameExpected: android.service.notification.ConditionProviderService#isBound():
-
-OnNameExpected: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
-
-OnNameExpected: android.service.quicksettings.TileService#isQuickSettingsSupported():
-
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
OnNameExpected: android.service.watchdog.ExplicitHealthCheckService#setCallback(android.os.RemoteCallback):
-
-OnNameExpected: android.telephony.ims.ImsService#createMmTelFeature(int):
-
-OnNameExpected: android.telephony.ims.ImsService#createRcsFeature(int):
-
-OnNameExpected: android.telephony.ims.ImsService#disableIms(int):
-
-OnNameExpected: android.telephony.ims.ImsService#enableIms(int):
-
-OnNameExpected: android.telephony.ims.ImsService#getConfig(int):
-
-OnNameExpected: android.telephony.ims.ImsService#getRegistration(int):
-
-OnNameExpected: android.telephony.ims.ImsService#querySupportedImsFeatures():
-
-OnNameExpected: android.telephony.ims.ImsService#readyForFeatureCreation():
-
-OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#dispose(int):
-
-OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
-
-OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#startGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, android.telephony.mbms.GroupCallCallback):
-
-OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#stopGroupCall(int, long):
-
-OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>):
-
-
-
-OptionalBuilderConstructorArgument: android.app.prediction.AppTargetEvent.Builder#Builder(android.app.prediction.AppTarget, int) parameter #0:
-
-OptionalBuilderConstructorArgument: android.net.CaptivePortalData.Builder#Builder(android.net.CaptivePortalData) parameter #0:
-
-OptionalBuilderConstructorArgument: android.os.VibrationAttributes.Builder#Builder(android.media.AudioAttributes, android.os.VibrationEffect) parameter #1:
-
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
PackageLayering: android.util.FeatureFlagUtils:
-
+ Method parameter type `android.content.Context` violates package layering: nothing in `package android.util` should depend on `package android.content`
-ParcelConstructor: android.os.IncidentManager.IncidentReport#IncidentReport(android.os.Parcel):
-
-ParcelConstructor: android.os.IncidentReportArgs#IncidentReportArgs(android.os.Parcel):
-
ParcelConstructor: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel):
-
+ Parcelable inflation is exposed through CREATOR, not raw constructors, in android.os.StrictMode.ViolationInfo
ParcelConstructor: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.Parcel):
-
-ParcelConstructor: android.service.notification.SnoozeCriterion#SnoozeCriterion(android.os.Parcel):
-
+ Parcelable inflation is exposed through CREATOR, not raw constructors, in android.os.health.HealthStatsParceler
ParcelCreator: android.app.WindowConfiguration:
-
-ParcelCreator: android.net.metrics.ApfProgramEvent:
-
-ParcelCreator: android.net.metrics.ApfStats:
-
-ParcelCreator: android.net.metrics.DhcpClientEvent:
-
-ParcelCreator: android.net.metrics.DhcpErrorEvent:
-
-ParcelCreator: android.net.metrics.IpConnectivityLog.Event:
-
-ParcelCreator: android.net.metrics.IpManagerEvent:
-
-ParcelCreator: android.net.metrics.IpReachabilityEvent:
-
-ParcelCreator: android.net.metrics.NetworkEvent:
-
-ParcelCreator: android.net.metrics.RaEvent:
-
-ParcelCreator: android.net.metrics.ValidationProbeEvent:
-
+ Parcelable requires a `CREATOR` field; missing in android.app.WindowConfiguration
ParcelCreator: android.service.autofill.InternalOnClickAction:
-
+ Parcelable requires a `CREATOR` field; missing in android.service.autofill.InternalOnClickAction
ParcelCreator: android.service.autofill.InternalSanitizer:
-
+ Parcelable requires a `CREATOR` field; missing in android.service.autofill.InternalSanitizer
ParcelCreator: android.service.autofill.InternalTransformation:
-
+ Parcelable requires a `CREATOR` field; missing in android.service.autofill.InternalTransformation
ParcelCreator: android.service.autofill.InternalValidator:
-
+ Parcelable requires a `CREATOR` field; missing in android.service.autofill.InternalValidator
ParcelNotFinal: android.app.WindowConfiguration:
-
+ Parcelable classes must be final: android.app.WindowConfiguration is not final
ParcelNotFinal: android.content.pm.UserInfo:
Parcelable classes must be final: android.content.pm.UserInfo is not final
-ParcelNotFinal: android.net.metrics.IpConnectivityLog.Event:
-
-ParcelNotFinal: android.os.IncidentManager.IncidentReport:
-
ParcelNotFinal: android.os.health.HealthStatsParceler:
-
+ Parcelable classes must be final: android.os.health.HealthStatsParceler is not final
ParcelNotFinal: android.service.autofill.InternalOnClickAction:
-
+ Parcelable classes must be final: android.service.autofill.InternalOnClickAction is not final
ParcelNotFinal: android.service.autofill.InternalSanitizer:
-
+ Parcelable classes must be final: android.service.autofill.InternalSanitizer is not final
ParcelNotFinal: android.service.autofill.InternalTransformation:
-
+ Parcelable classes must be final: android.service.autofill.InternalTransformation is not final
ParcelNotFinal: android.service.autofill.InternalValidator:
-
+ Parcelable classes must be final: android.service.autofill.InternalValidator is not final
ProtectedMember: android.app.AppDetailsActivity#onCreate(android.os.Bundle):
-
-ProtectedMember: android.os.VibrationEffect#scale(int, float, int):
-
-ProtectedMember: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
-
-ProtectedMember: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.PrintWriter, String[]):
-
-ProtectedMember: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
-
-ProtectedMember: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
-
-ProtectedMember: android.util.proto.ProtoStream#FIELD_TYPE_NAMES:
-
+ Protected methods not allowed; must be public: method android.app.AppDetailsActivity.onCreate(android.os.Bundle)}
ProtectedMember: android.view.View#resetResolvedDrawables():
-
+ Protected methods not allowed; must be public: method android.view.View.resetResolvedDrawables()}
ProtectedMember: android.view.ViewGroup#resetResolvedDrawables():
-
+ Protected methods not allowed; must be public: method android.view.ViewGroup.resetResolvedDrawables()}
-RawAidl: android.telephony.mbms.vendor.MbmsDownloadServiceBase:
-
-RawAidl: android.telephony.mbms.vendor.MbmsStreamingServiceBase:
-
+RethrowRemoteException: android.app.ActivityManager#resumeAppSwitches():
+ Methods calling system APIs should rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
-RethrowRemoteException: android.app.ActivityManager#resumeAppSwitches():
-
-RethrowRemoteException: android.os.HwBinder#getService(String, String):
-
-RethrowRemoteException: android.os.HwBinder#getService(String, String, boolean):
-
-RethrowRemoteException: android.os.HwBinder#onTransact(int, android.os.HwParcel, android.os.HwParcel, int):
-
-RethrowRemoteException: android.os.HwBinder#registerService(String):
-
-RethrowRemoteException: android.os.HwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int):
-
-RethrowRemoteException: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int):
-
-RethrowRemoteException: android.telephony.ims.ImsService#onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#cancelDownload(android.telephony.mbms.DownloadRequest):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#dispose(int):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#download(android.telephony.mbms.DownloadRequest):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#listPendingDownloads(int):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestUpdateFileServices(int, java.util.List<java.lang.String>):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#resetDownloadKnowledge(android.telephony.mbms.DownloadRequest):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#setTempFileRootDirectory(int, String):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#dispose(int):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#dispose(int):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#getPlaybackUri(int, String):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#requestUpdateStreamingServices(int, java.util.List<java.lang.String>):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback):
-
-RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#stopStreaming(int, String):
-
-
-
-SamShouldBeLast: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int):
-
SamShouldBeLast: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]):
-
+ SAM-compatible parameters (such as parameter 1, "printer", in android.database.sqlite.SQLiteDebug.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]):
-
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper):
-
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, java.util.concurrent.Executor, android.location.LocationListener):
-
-SamShouldBeLast: android.os.BugreportManager#startBugreport(android.os.ParcelFileDescriptor, android.os.ParcelFileDescriptor, android.os.BugreportParams, java.util.concurrent.Executor, android.os.BugreportManager.BugreportCallback):
-
-SamShouldBeLast: android.os.IHwBinder#linkToDeath(android.os.IHwBinder.DeathRecipient, long):
-
+ SAM-compatible parameters (such as parameter 1, "factory", in android.database.sqlite.SQLiteDirectCursorDriver.query) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String):
-
+ SAM-compatible parameters (such as parameter 1, "pw", in android.os.StrictMode.ViolationInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.permission.PermissionControllerManager#countPermissionApps(java.util.List<java.lang.String>, int, android.permission.PermissionControllerManager.OnCountPermissionAppsResultCallback, android.os.Handler):
-
+ SAM-compatible parameters (such as parameter 3, "callback", in android.permission.PermissionControllerManager.countPermissionApps) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler):
-
-SamShouldBeLast: android.permission.PermissionControllerManager#revokeRuntimePermissions(java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, java.util.concurrent.Executor, android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback):
-
+ SAM-compatible parameters (such as parameter 2, "callback", in android.permission.PermissionControllerManager.getAppPermissions) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.service.autofill.CharSequenceTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
-
+ SAM-compatible parameters (such as parameter 1, "finder", in android.service.autofill.CharSequenceTransformation.apply) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.service.autofill.DateTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
-
+ SAM-compatible parameters (such as parameter 1, "finder", in android.service.autofill.DateTransformation.apply) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.service.autofill.ImageTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
-
+ SAM-compatible parameters (such as parameter 1, "finder", in android.service.autofill.ImageTransformation.apply) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.service.autofill.InternalTransformation#batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>):
-
-SamShouldBeLast: android.telephony.ims.ImsMmTelManager#getFeatureState(java.util.function.Consumer<java.lang.Integer>, java.util.concurrent.Executor):
-
+ SAM-compatible parameters (such as parameter 1, "finder", in android.service.autofill.InternalTransformation.batchApply) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.Choreographer#postCallback(int, Runnable, Object):
-
+ SAM-compatible parameters (such as parameter 2, "action", in android.view.Choreographer.postCallback) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long):
-
+ SAM-compatible parameters (such as parameter 2, "action", in android.view.Choreographer.postCallbackDelayed) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.Choreographer#removeCallbacks(int, Runnable, Object):
-
-SamShouldBeLast: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>):
-
-SamShouldBeLast: android.view.accessibility.AccessibilityManager#addAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, android.os.Handler):
-
-
-
-ServiceName: android.Manifest.permission#BIND_CELL_BROADCAST_SERVICE:
-
-ServiceName: android.app.AppOpsManager#OPSTR_BIND_ACCESSIBILITY_SERVICE:
-
-ServiceName: android.provider.Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE:
-
-ServiceName: android.provider.Settings.Secure#AUTOFILL_SERVICE:
-
-ServiceName: android.provider.Settings.Secure#VOICE_INTERACTION_SERVICE:
-
-
-
-SetterReturnsThis: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener):
-
-SetterReturnsThis: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener):
-
-
-
-StartWithLower: android.content.pm.PackageManager#BINDER():
- Method name must start with lowercase char: BINDER
-
-
-StaticFinalBuilder: android.content.integrity.RuleSet.Builder:
-
-StaticFinalBuilder: android.hardware.display.BrightnessConfiguration.Builder:
-
-StaticFinalBuilder: android.media.audiopolicy.AudioMix.Builder:
-
-StaticFinalBuilder: android.media.audiopolicy.AudioMixingRule.Builder:
-
-StaticFinalBuilder: android.media.audiopolicy.AudioPolicy.Builder:
-
-StaticFinalBuilder: android.net.CaptivePortalData.Builder:
-
-StaticFinalBuilder: android.net.TetheringManager.TetheringRequest.Builder:
-
-StaticFinalBuilder: android.telephony.ims.stub.ImsFeatureConfiguration.Builder:
-
+ SAM-compatible parameters (such as parameter 2, "action", in android.view.Choreographer.removeCallbacks) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
StaticUtils: android.os.health.HealthKeys:
-
+ Fully-static utility classes must not have constructor
StaticUtils: android.service.autofill.InternalTransformation:
-
-StaticUtils: android.telephony.mbms.vendor.VendorUtils:
-
+ Fully-static utility classes must not have constructor
StaticUtils: android.util.FeatureFlagUtils:
-
-StaticUtils: android.util.proto.ProtoStream:
-
+ Fully-static utility classes must not have constructor
StreamFiles: android.os.Environment#buildPath(java.io.File, java.lang.String...):
-
+ Methods accepting `File` should also accept `FileDescriptor` or streams: method android.os.Environment.buildPath(java.io.File,java.lang.String...)
StreamFiles: android.os.FileUtils#contains(java.io.File, java.io.File):
-
-StreamFiles: android.provider.MediaStore#scanFile(android.content.Context, java.io.File):
-
-StreamFiles: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File):
-
-StreamFiles: android.provider.MediaStore#scanVolume(android.content.Context, java.io.File):
-
+ Methods accepting `File` should also accept `FileDescriptor` or streams: method android.os.FileUtils.contains(java.io.File,java.io.File)
UseIcu: android.hardware.soundtrigger.KeyphraseEnrollmentInfo#getKeyphraseMetadata(String, java.util.Locale) parameter #1:
-
+ Type `java.util.Locale` should be replaced with richer ICU type `android.icu.util.ULocale`
UseIcu: android.hardware.soundtrigger.KeyphraseEnrollmentInfo#getManageKeyphraseIntent(int, String, java.util.Locale) parameter #2:
-
+ Type `java.util.Locale` should be replaced with richer ICU type `android.icu.util.ULocale`
UseIcu: android.hardware.soundtrigger.KeyphraseMetadata#supportsLocale(java.util.Locale) parameter #0:
-
-UseIcu: android.hardware.soundtrigger.SoundTrigger.Keyphrase#Keyphrase(int, int, java.util.Locale, String, int[]) parameter #2:
-
-UseIcu: android.hardware.soundtrigger.SoundTrigger.Keyphrase#getLocale():
-
-
-
-UseParcelFileDescriptor: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.FileDescriptor) parameter #0:
-
+ Type `java.util.Locale` should be replaced with richer ICU type `android.icu.util.ULocale`
-UserHandle: android.app.ActivityManager#switchUser(android.os.UserHandle):
-
UserHandle: android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts(android.os.UserHandle):
-
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
UserHandle: android.app.usage.StorageStatsManager#queryCratesForPackage(java.util.UUID, String, android.os.UserHandle):
-
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
UserHandle: android.app.usage.StorageStatsManager#queryCratesForUser(java.util.UUID, android.os.UserHandle):
-
-UserHandle: android.companion.CompanionDeviceManager#isDeviceAssociated(String, android.net.MacAddress, android.os.UserHandle):
-
-UserHandle: android.companion.CompanionDeviceManager#isDeviceAssociatedForWifiConnection(String, android.net.MacAddress, android.os.UserHandle):
-
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
UserHandle: android.content.pm.PackageManager#getInstallReason(String, android.os.UserHandle):
-
-UserHandle: android.content.pm.PackageManager#getPermissionFlags(String, String, android.os.UserHandle):
-
-UserHandle: android.content.pm.PackageManager#grantRuntimePermission(String, String, android.os.UserHandle):
-
-UserHandle: android.content.pm.PackageManager#revokeRuntimePermission(String, String, android.os.UserHandle):
-
-UserHandle: android.content.pm.PackageManager#revokeRuntimePermission(String, String, android.os.UserHandle, String):
-
-UserHandle: android.content.pm.PackageManager#updatePermissionFlags(String, String, int, int, android.os.UserHandle):
-
-UserHandle: android.location.LocationManager#setLocationEnabledForUser(boolean, android.os.UserHandle):
-
-UserHandle: android.permission.PermissionControllerManager#applyStagedRuntimePermissionBackup(String, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
-
-UserHandle: android.permission.PermissionControllerManager#getRuntimePermissionBackup(android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<byte[]>):
-
-UserHandle: android.permission.PermissionControllerManager#stageAndApplyRuntimePermissionsBackup(byte[], android.os.UserHandle):
-
-UserHandle: android.telecom.TelecomManager#getDefaultDialerPackage(android.os.UserHandle):
-
+ When a method overload is needed to target a specific UserHandle, callers should be directed to use Context.createPackageContextAsUser() and re-obtain the relevant Manager, and no new API should be added
UserHandleName: android.content.AutofillOptions:
-
+ Classes holding a set of parameters should be called `FooParams`, was `AutofillOptions`
UserHandleName: android.content.ContentCaptureOptions:
-
-UserHandleName: android.os.IncidentReportArgs:
-
-UserHandleName: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle):
-
-UserHandleName: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle):
-
-
-
-VisiblySynchronized: PsiClassObjectAccessExpression:
-
-VisiblySynchronized: PsiThisExpression:
-
-VisiblySynchronized: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int):
-
-VisiblySynchronized: android.app.ActivityManager#removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener):
-
-VisiblySynchronized: android.content.ContentProviderClient#setDetectNotResponding(long):
-
+ Classes holding a set of parameters should be called `FooParams`, was `ContentCaptureOptions`
+
+
+VisiblySynchronized: PsiThisExpression:this:
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.content.res.AssetManager.getApkPaths()
VisiblySynchronized: android.content.res.AssetManager#getApkPaths():
-
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.content.res.AssetManager.getApkPaths()
VisiblySynchronized: android.content.res.AssetManager#getLastResourceResolution():
-
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.content.res.AssetManager.getLastResourceResolution()
VisiblySynchronized: android.content.res.AssetManager#getOverlayablesToString(String):
-
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.content.res.AssetManager.getOverlayablesToString(String)
VisiblySynchronized: android.content.res.AssetManager#setResourceResolutionLoggingEnabled(boolean):
-
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.content.res.AssetManager.setResourceResolutionLoggingEnabled(boolean)
VisiblySynchronized: android.os.MessageQueue#removeSyncBarrier(int):
-
+ Internal locks must not be exposed (synchronizing on this or class is still externally observable): method android.os.MessageQueue.removeSyncBarrier(int)
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index e9c29b8aa0a5..c802d20a5a57 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -261,8 +261,10 @@ public class KeyguardManager {
CharSequence title, CharSequence description, int userId,
boolean disallowBiometricsIfPolicyExists) {
Intent intent = this.createConfirmDeviceCredentialIntent(title, description, userId);
- intent.putExtra(EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS,
- disallowBiometricsIfPolicyExists);
+ if (intent != null) {
+ intent.putExtra(EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS,
+ disallowBiometricsIfPolicyExists);
+ }
return intent;
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4d4a57db84be..44dc28d2b0fa 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1414,11 +1414,9 @@ public class PackageParser {
final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
final ParseResult<android.content.pm.SigningDetails> result;
if (skipVerify) {
- // systemDir APKs are already trusted, save time by not verifying; since the signature
- // is not verified and some system apps can have their V2+ signatures stripped allow
- // pulling the certs from the jar signature.
+ // systemDir APKs are already trusted, save time by not verifying
result = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
- input, apkPath, SigningDetails.SignatureSchemeVersion.JAR);
+ input, apkPath, minSignatureScheme);
} else {
result = ApkSignatureVerifier.verify(input, apkPath, minSignatureScheme);
}
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index cc62d5337c02..1c1f58a19abc 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -168,15 +168,6 @@
"name": "CtsIncrementalInstallHostTestCases"
},
{
- "name": "CtsInstallHostTestCases"
- },
- {
- "name": "CtsStagedInstallHostTestCases"
- },
- {
- "name": "CtsExtractNativeLibsHostTestCases"
- },
- {
"name": "CtsAppSecurityHostTestCases",
"options": [
{
@@ -188,34 +179,47 @@
]
},
{
- "name": "FrameworksServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.pm.PackageParserTest"
- }
- ]
- },
- {
- "name": "CtsRollbackManagerHostTestCases"
- },
- {
"name": "CtsContentTestCases",
"options": [
{
"include-filter": "android.content.cts.IntentFilterTest"
}
]
- },
- {
- "name": "CtsAppEnumerationTestCases"
- },
- {
- "name": "PackageManagerServiceUnitTests",
- "options": [
- {
- "include-filter": "com.android.server.pm.test.verify.domain"
- }
- ]
}
+ ],
+ "platinum-postsubmit": [
+ {
+ "name": "CtsIncrementalInstallHostTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsAppSecurityHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.appsecurity.cts.SplitTests"
+ },
+ {
+ "include-filter": "android.appsecurity.cts.EphemeralTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsContentTestCases",
+ "options":[
+ {
+ "include-filter": "android.content.cts.IntentFilterTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
]
}
diff --git a/core/java/android/content/pm/verify/domain/TEST_MAPPING b/core/java/android/content/pm/verify/domain/TEST_MAPPING
index ba4a62cdbbf1..8a1982a339ea 100644
--- a/core/java/android/content/pm/verify/domain/TEST_MAPPING
+++ b/core/java/android/content/pm/verify/domain/TEST_MAPPING
@@ -12,9 +12,6 @@
"name": "CtsDomainVerificationDeviceStandaloneTestCases"
},
{
- "name": "CtsDomainVerificationDeviceMultiUserTestCases"
- },
- {
"name": "CtsDomainVerificationHostTestCases"
}
]
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index dc38db2134f4..69105016e0ea 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -152,6 +152,7 @@ final class NavigationBarController {
private boolean mDrawLegacyNavigationBarBackground;
private final Rect mTempRect = new Rect();
+ private final int[] mTempPos = new int[2];
Impl(@NonNull InputMethodService inputMethodService) {
mService = inputMethodService;
@@ -259,21 +260,28 @@ final class NavigationBarController {
switch (originalInsets.touchableInsets) {
case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
if (inputFrame.getVisibility() == View.VISIBLE) {
- inputFrame.getBoundsOnScreen(mTempRect);
+ inputFrame.getLocationInWindow(mTempPos);
+ mTempRect.set(mTempPos[0], mTempPos[1],
+ mTempPos[0] + inputFrame.getWidth(),
+ mTempPos[1] + inputFrame.getHeight());
touchableRegion = new Region(mTempRect);
}
break;
case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT:
if (inputFrame.getVisibility() == View.VISIBLE) {
- inputFrame.getBoundsOnScreen(mTempRect);
- mTempRect.top = originalInsets.contentTopInsets;
+ inputFrame.getLocationInWindow(mTempPos);
+ mTempRect.set(mTempPos[0], originalInsets.contentTopInsets,
+ mTempPos[0] + inputFrame.getWidth() ,
+ mTempPos[1] + inputFrame.getHeight());
touchableRegion = new Region(mTempRect);
}
break;
case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE:
if (inputFrame.getVisibility() == View.VISIBLE) {
- inputFrame.getBoundsOnScreen(mTempRect);
- mTempRect.top = originalInsets.visibleTopInsets;
+ inputFrame.getLocationInWindow(mTempPos);
+ mTempRect.set(mTempPos[0], originalInsets.visibleTopInsets,
+ mTempPos[0] + inputFrame.getWidth(),
+ mTempPos[1] + inputFrame.getHeight());
touchableRegion = new Region(mTempRect);
}
break;
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 815e4f0c9071..d71faee4cc8d 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1205,13 +1205,16 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
static Uri readFrom(Parcel parcel) {
- return new HierarchicalUri(
- parcel.readString8(),
- Part.readFrom(parcel),
- PathPart.readFrom(parcel),
- Part.readFrom(parcel),
- Part.readFrom(parcel)
- );
+ final String scheme = parcel.readString8();
+ final Part authority = Part.readFrom(parcel);
+ // In RFC3986 the path should be determined based on whether there is a scheme or
+ // authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3).
+ final boolean hasSchemeOrAuthority =
+ (scheme != null && scheme.length() > 0) || !authority.isEmpty();
+ final PathPart path = PathPart.readFrom(hasSchemeOrAuthority, parcel);
+ final Part query = Part.readFrom(parcel);
+ final Part fragment = Part.readFrom(parcel);
+ return new HierarchicalUri(scheme, authority, path, query, fragment);
}
public int describeContents() {
@@ -2270,6 +2273,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
}
+ static PathPart readFrom(boolean hasSchemeOrAuthority, Parcel parcel) {
+ final PathPart path = readFrom(parcel);
+ return hasSchemeOrAuthority ? makeAbsolute(path) : path;
+ }
+
/**
* Creates a path from the encoded string.
*
diff --git a/core/java/android/permission/ILegacyPermissionManager.aidl b/core/java/android/permission/ILegacyPermissionManager.aidl
index f1f083668711..78e12de04e89 100644
--- a/core/java/android/permission/ILegacyPermissionManager.aidl
+++ b/core/java/android/permission/ILegacyPermissionManager.aidl
@@ -49,4 +49,6 @@ interface ILegacyPermissionManager {
void grantDefaultPermissionsToActiveLuiApp(in String packageName, int userId);
void revokeDefaultPermissionsFromLuiApps(in String[] packageNames, int userId);
+
+ void grantDefaultPermissionsToCarrierServiceApp(in String packageName, int userId);
}
diff --git a/core/java/android/permission/LegacyPermissionManager.java b/core/java/android/permission/LegacyPermissionManager.java
index a4fa11b5121b..57776857864e 100644
--- a/core/java/android/permission/LegacyPermissionManager.java
+++ b/core/java/android/permission/LegacyPermissionManager.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.RemoteException;
@@ -244,4 +245,20 @@ public final class LegacyPermissionManager {
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Grant permissions to a newly set Carrier Services app.
+ * @param packageName The newly set Carrier Services app
+ * @param userId The user for which to grant the permissions.
+ * @hide
+ */
+ public void grantDefaultPermissionsToCarrierServiceApp(@NonNull String packageName,
+ @UserIdInt int userId) {
+ try {
+ mLegacyPermissionManager.grantDefaultPermissionsToCarrierServiceApp(packageName,
+ userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index d25e456270ae..37f44e98c165 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -731,6 +731,13 @@ public final class DeviceConfig {
public static final String NAMESPACE_AMBIENT_CONTEXT_MANAGER_SERVICE =
"ambient_context_manager_service";
+ /**
+ * Namespace for Vendor System Native related features.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_VENDOR_SYSTEM_NATIVE = "vendor_system_native";
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 34647b144be1..20a2bdf3b109 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7679,20 +7679,6 @@ public final class Settings {
"zen_settings_suggestion_viewed";
/**
- * State of whether review notification permissions notification needs to
- * be shown the user, and whether the user has interacted.
- *
- * Valid values:
- * -1 = UNKNOWN
- * 0 = SHOULD_SHOW
- * 1 = USER_INTERACTED
- * 2 = DISMISSED
- * @hide
- */
- public static final String REVIEW_PERMISSIONS_NOTIFICATION_STATE =
- "review_permissions_notification_state";
-
- /**
* Whether the in call notification is enabled to play sound during calls. The value is
* boolean (1 or 0).
* @hide
@@ -9696,6 +9682,26 @@ public final class Settings {
public static final String BIOMETRIC_APP_ENABLED = "biometric_app_enabled";
/**
+ * Whether or not active unlock triggers on wake.
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_ON_WAKE = "active_unlock_on_wake";
+
+ /**
+ * Whether or not active unlock triggers on unlock intent.
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_ON_UNLOCK_INTENT =
+ "active_unlock_on_unlock_intent";
+
+ /**
+ * Whether or not active unlock triggers on biometric failure.
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL =
+ "active_unlock_on_biometric_fail";
+
+ /**
* Whether the assist gesture should be enabled.
*
* @hide
@@ -16966,6 +16972,21 @@ public final class Settings {
"managed_provisioning_defer_provisioning_to_role_holder";
/**
+ * State of whether review notification permissions notification needs to
+ * be shown the user, and whether the user has interacted.
+ *
+ * Valid values:
+ * -1 = UNKNOWN
+ * 0 = SHOULD_SHOW
+ * 1 = USER_INTERACTED
+ * 2 = DISMISSED
+ * 3 = RESHOWN
+ * @hide
+ */
+ public static final String REVIEW_PERMISSIONS_NOTIFICATION_STATE =
+ "review_permissions_notification_state";
+
+ /**
* Settings migrated from Wear OS settings provider.
* @hide
*/
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 6a9afdb84e18..47fc120c9d4f 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -999,6 +999,14 @@ public class DreamService extends Service implements Window.Callback {
return mDreamServiceWrapper;
}
+ @Override
+ public boolean onUnbind(Intent intent) {
+ // We must unbind from any overlay connection if we are unbound before finishing.
+ mOverlayConnection.unbind(this);
+
+ return super.onUnbind(intent);
+ }
+
/**
* Stops the dream and detaches from the window.
* <p>
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index 01152943efe3..e8d53d351795 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -25,7 +25,6 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.ActivityTaskManager;
import android.app.Instrumentation;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -511,14 +510,11 @@ public abstract class GameSession {
callback.onActivityResult(result.getResultCode(), result.getData());
}, executor);
- final Intent trampolineIntent = new Intent();
- trampolineIntent.setComponent(
- new ComponentName(
- "android", "android.service.games.GameSessionTrampolineActivity"));
- trampolineIntent.putExtra(GameSessionTrampolineActivity.INTENT_KEY, intent);
- trampolineIntent.putExtra(GameSessionTrampolineActivity.OPTIONS_KEY, options);
- trampolineIntent.putExtra(
- GameSessionTrampolineActivity.FUTURE_KEY, future);
+ final Intent trampolineIntent =
+ GameSessionTrampolineActivity.createIntent(
+ intent,
+ options,
+ future);
try {
int result = ActivityTaskManager.getService().startActivityFromGameSession(
diff --git a/core/java/android/service/games/GameSessionActivityResult.java b/core/java/android/service/games/GameSessionActivityResult.java
index a2ec6ada010c..c8099e6e5eff 100644
--- a/core/java/android/service/games/GameSessionActivityResult.java
+++ b/core/java/android/service/games/GameSessionActivityResult.java
@@ -22,8 +22,12 @@ import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.annotations.VisibleForTesting;
-final class GameSessionActivityResult implements Parcelable {
+
+/** @hide */
+@VisibleForTesting
+public final class GameSessionActivityResult implements Parcelable {
public static final Creator<GameSessionActivityResult> CREATOR =
new Creator<GameSessionActivityResult>() {
@@ -44,17 +48,17 @@ final class GameSessionActivityResult implements Parcelable {
@Nullable
private final Intent mData;
- GameSessionActivityResult(int resultCode, @Nullable Intent data) {
+ public GameSessionActivityResult(int resultCode, @Nullable Intent data) {
mResultCode = resultCode;
mData = data;
}
- int getResultCode() {
+ public int getResultCode() {
return mResultCode;
}
@Nullable
- Intent getData() {
+ public Intent getData() {
return mData;
}
diff --git a/core/java/android/service/games/GameSessionService.java b/core/java/android/service/games/GameSessionService.java
index df5bad5c53b2..52c8ec3d4018 100644
--- a/core/java/android/service/games/GameSessionService.java
+++ b/core/java/android/service/games/GameSessionService.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.app.Service;
+import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.os.Binder;
@@ -28,6 +29,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.view.Display;
import android.view.SurfaceControlViewHost;
+import android.view.WindowManager;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -117,13 +119,18 @@ public abstract class GameSessionService extends Service {
}
IBinder hostToken = new Binder();
+
+ // Use a WindowContext so that views attached to the SurfaceControlViewHost will receive
+ // configuration changes (rather than always perceiving the global configuration).
+ final Context windowContext = createWindowContext(display,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, /*options=*/ null);
SurfaceControlViewHost surfaceControlViewHost =
- new SurfaceControlViewHost(this, display, hostToken);
+ new SurfaceControlViewHost(windowContext, display, hostToken);
gameSession.attach(
gameSessionController,
createGameSessionRequest.getTaskId(),
- this,
+ windowContext,
surfaceControlViewHost,
gameSessionViewHostConfiguration.mWidthPx,
gameSessionViewHostConfiguration.mHeightPx);
diff --git a/core/java/android/service/games/GameSessionTrampolineActivity.java b/core/java/android/service/games/GameSessionTrampolineActivity.java
index 3d97d0f59b33..b23791842284 100644
--- a/core/java/android/service/games/GameSessionTrampolineActivity.java
+++ b/core/java/android/service/games/GameSessionTrampolineActivity.java
@@ -16,12 +16,15 @@
package android.service.games;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
+import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AndroidFuture;
import java.util.concurrent.Executor;
@@ -35,6 +38,7 @@ import java.util.concurrent.Executor;
*
* @hide
*/
+@VisibleForTesting
public final class GameSessionTrampolineActivity extends Activity {
private static final String TAG = "GameSessionTrampoline";
private static final int REQUEST_CODE = 1;
@@ -42,11 +46,52 @@ public final class GameSessionTrampolineActivity extends Activity {
static final String FUTURE_KEY = "GameSessionTrampolineActivity.future";
static final String INTENT_KEY = "GameSessionTrampolineActivity.intent";
static final String OPTIONS_KEY = "GameSessionTrampolineActivity.options";
+ private static final String HAS_LAUNCHED_INTENT_KEY =
+ "GameSessionTrampolineActivity.hasLaunchedIntent";
+ private boolean mHasLaunchedIntent = false;
+
+ /**
+ * Create an {@link Intent} for the {@link GameSessionTrampolineActivity} with the given
+ * parameters.
+ *
+ * @param targetIntent the forwarded {@link Intent} that is associated with the Activity that
+ * will be launched by the {@link GameSessionTrampolineActivity}.
+ * @param options Activity options. See {@link #startActivity(Intent, Bundle)}.
+ * @param resultFuture the {@link AndroidFuture} that will complete with the activity results of
+ * {@code targetIntent} launched.
+ * @return the Intent that will launch the {@link GameSessionTrampolineActivity} with the given
+ * parameters.
+ * @hide
+ */
+ @VisibleForTesting
+ public static Intent createIntent(
+ @NonNull Intent targetIntent,
+ @Nullable Bundle options,
+ @NonNull AndroidFuture<GameSessionActivityResult> resultFuture) {
+ final Intent trampolineIntent = new Intent();
+ trampolineIntent.setComponent(
+ new ComponentName(
+ "android", "android.service.games.GameSessionTrampolineActivity"));
+ trampolineIntent.putExtra(INTENT_KEY, targetIntent);
+ trampolineIntent.putExtra(OPTIONS_KEY, options);
+ trampolineIntent.putExtra(FUTURE_KEY, resultFuture);
+
+ return trampolineIntent;
+ }
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ mHasLaunchedIntent = savedInstanceState.getBoolean(HAS_LAUNCHED_INTENT_KEY);
+ }
+
+ if (mHasLaunchedIntent) {
+ return;
+ }
+ mHasLaunchedIntent = true;
+
try {
startActivityAsCaller(
getIntent().getParcelableExtra(INTENT_KEY),
@@ -60,10 +105,17 @@ public final class GameSessionTrampolineActivity extends Activity {
FUTURE_KEY);
future.completeExceptionally(e);
finish();
+ overridePendingTransition(0, 0);
}
}
@Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(HAS_LAUNCHED_INTENT_KEY, mHasLaunchedIntent);
+ }
+
+ @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != REQUEST_CODE) {
// Something went very wrong if we hit this code path, and we should bail.
@@ -74,5 +126,6 @@ public final class GameSessionTrampolineActivity extends Activity {
FUTURE_KEY);
future.complete(new GameSessionActivityResult(resultCode, data));
finish();
+ overridePendingTransition(0, 0);
}
}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 4bbfbc2e717d..b783f6b8fd51 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1095,7 +1095,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
if (!mWindowVisible) {
mWindowVisible = true;
if (mUiEnabled) {
- mWindow.show();
+ showWindow();
}
}
if (showCallback != null) {
@@ -1284,9 +1284,25 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
}
}
+ void showWindow() {
+ if (mWindow != null) {
+ mWindow.show();
+ try {
+ mSystemService.setSessionWindowVisible(mToken, true);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to notify session window shown", e);
+ }
+ }
+ }
+
void ensureWindowHidden() {
if (mWindow != null) {
mWindow.hide();
+ try {
+ mSystemService.setSessionWindowVisible(mToken, false);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to notify session window hidden", e);
+ }
}
}
@@ -1377,7 +1393,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
if (mWindowVisible) {
if (enabled) {
ensureWindowAdded();
- mWindow.show();
+ showWindow();
} else {
ensureWindowHidden();
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 77591a7efb5e..ebbe64c396e7 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -785,9 +785,7 @@ public final class Choreographer {
}
}
frameTimeNanos = startNanos - lastFrameOffset;
- DisplayEventReceiver.VsyncEventData latestVsyncEventData =
- mDisplayEventReceiver.getLatestVsyncEventData();
- frameData.updateFrameData(frameTimeNanos, latestVsyncEventData);
+ frameData.updateFrameData(frameTimeNanos);
}
if (frameTimeNanos < mLastFrameTimeNanos) {
@@ -885,9 +883,7 @@ public final class Choreographer {
}
frameTimeNanos = now - lastFrameOffset;
mLastFrameTimeNanos = frameTimeNanos;
- DisplayEventReceiver.VsyncEventData latestVsyncEventData =
- mDisplayEventReceiver.getLatestVsyncEventData();
- frameData.updateFrameData(frameTimeNanos, latestVsyncEventData);
+ frameData.updateFrameData(frameTimeNanos);
}
}
}
@@ -1022,6 +1018,11 @@ public final class Choreographer {
return mVsyncId;
}
+ /** Reset the vsync ID to invalid. */
+ void resetVsyncId() {
+ mVsyncId = FrameInfo.INVALID_VSYNC_ID;
+ }
+
/**
* The time in {@link System#nanoTime()} timebase which this frame is expected to be
* presented.
@@ -1069,12 +1070,14 @@ public final class Choreographer {
private FrameTimeline[] mFrameTimelines;
private FrameTimeline mPreferredFrameTimeline;
- void updateFrameData(long frameTimeNanos,
- DisplayEventReceiver.VsyncEventData latestVsyncEventData) {
+ void updateFrameData(long frameTimeNanos) {
mFrameTimeNanos = frameTimeNanos;
- mFrameTimelines = convertFrameTimelines(latestVsyncEventData);
- mPreferredFrameTimeline =
- mFrameTimelines[latestVsyncEventData.preferredFrameTimelineIndex];
+ for (FrameTimeline ft : mFrameTimelines) {
+ // The ID is no longer valid because the frame time that was registered with the ID
+ // no longer matches.
+ // TODO(b/205721584): Ask SF for valid vsync information.
+ ft.resetVsyncId();
+ }
}
/** The time in nanoseconds when the frame started being rendered. */
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 4fdea3b006dc..332e97c8bcf5 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -65,6 +65,9 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
public void onWindowFocusGained(boolean hasViewFocus) {
super.onWindowFocusGained(hasViewFocus);
getImm().registerImeConsumer(this);
+ if (isRequestedVisible() && getControl() == null) {
+ mIsRequestedVisibleAwaitingControl = true;
+ }
}
@Override
@@ -149,14 +152,11 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
}
@Override
- public void setControl(@Nullable InsetsSourceControl control, int[] showTypes,
+ public boolean setControl(@Nullable InsetsSourceControl control, int[] showTypes,
int[] hideTypes) {
- super.setControl(control, showTypes, hideTypes);
- // TODO(b/204524304): clean-up how to deal with the timing issues of hiding IME:
- // 1) Already requested show IME, in the meantime of WM callback the control but got null
- // control when relayout comes first
- // 2) Make sure no regression on some implicit request IME visibility calls (e.g.
- // toggleSoftInput)
+ if (!super.setControl(control, showTypes, hideTypes)) {
+ return false;
+ }
if (control == null && !mIsRequestedVisibleAwaitingControl) {
hide();
removeSurface();
@@ -164,6 +164,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
if (control != null) {
mIsRequestedVisibleAwaitingControl = false;
}
+ return true;
}
@Override
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index e6cf68367ae6..583252756b92 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -47,6 +47,7 @@ public class InsetsSource implements Parcelable {
private final Rect mFrame;
private @Nullable Rect mVisibleFrame;
private boolean mVisible;
+ private boolean mInsetsRoundedCornerFrame;
private final Rect mTmpFrame = new Rect();
@@ -63,6 +64,7 @@ public class InsetsSource implements Parcelable {
mVisibleFrame = other.mVisibleFrame != null
? new Rect(other.mVisibleFrame)
: null;
+ mInsetsRoundedCornerFrame = other.mInsetsRoundedCornerFrame;
}
public void set(InsetsSource other) {
@@ -71,6 +73,7 @@ public class InsetsSource implements Parcelable {
mVisibleFrame = other.mVisibleFrame != null
? new Rect(other.mVisibleFrame)
: null;
+ mInsetsRoundedCornerFrame = other.mInsetsRoundedCornerFrame;
}
public void setFrame(int left, int top, int right, int bottom) {
@@ -110,6 +113,14 @@ public class InsetsSource implements Parcelable {
return mVisibleFrame == null || !mVisibleFrame.isEmpty();
}
+ public boolean getInsetsRoundedCornerFrame() {
+ return mInsetsRoundedCornerFrame;
+ }
+
+ public void setInsetsRoundedCornerFrame(boolean insetsRoundedCornerFrame) {
+ mInsetsRoundedCornerFrame = insetsRoundedCornerFrame;
+ }
+
/**
* Calculates the insets this source will cause to a client window.
*
@@ -225,6 +236,7 @@ public class InsetsSource implements Parcelable {
pw.print(" visibleFrame="); pw.print(mVisibleFrame.toShortString());
}
pw.print(" visible="); pw.print(mVisible);
+ pw.print(" insetsRoundedCornerFrame="); pw.print(mInsetsRoundedCornerFrame);
pw.println();
}
@@ -247,6 +259,7 @@ public class InsetsSource implements Parcelable {
if (mVisible != that.mVisible) return false;
if (excludeInvisibleImeFrames && !mVisible && mType == ITYPE_IME) return true;
if (!Objects.equals(mVisibleFrame, that.mVisibleFrame)) return false;
+ if (mInsetsRoundedCornerFrame != that.mInsetsRoundedCornerFrame) return false;
return mFrame.equals(that.mFrame);
}
@@ -256,6 +269,7 @@ public class InsetsSource implements Parcelable {
result = 31 * result + mFrame.hashCode();
result = 31 * result + (mVisibleFrame != null ? mVisibleFrame.hashCode() : 0);
result = 31 * result + (mVisible ? 1 : 0);
+ result = 31 * result + (mInsetsRoundedCornerFrame ? 1 : 0);
return result;
}
@@ -268,6 +282,7 @@ public class InsetsSource implements Parcelable {
mVisibleFrame = null;
}
mVisible = in.readBoolean();
+ mInsetsRoundedCornerFrame = in.readBoolean();
}
@Override
@@ -286,6 +301,7 @@ public class InsetsSource implements Parcelable {
dest.writeInt(0);
}
dest.writeBoolean(mVisible);
+ dest.writeBoolean(mInsetsRoundedCornerFrame);
}
@Override
@@ -294,6 +310,7 @@ public class InsetsSource implements Parcelable {
+ "mType=" + InsetsState.typeToString(mType)
+ ", mFrame=" + mFrame.toShortString()
+ ", mVisible=" + mVisible
+ + ", mInsetsRoundedCornerFrame=" + mInsetsRoundedCornerFrame
+ "}";
}
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 4d9033df89e1..d6b75b94b19a 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -122,8 +122,9 @@ public class InsetsSourceConsumer {
* animation should be run after setting the control.
* @param hideTypes An integer array with a single entry that determines which types a hide
* animation should be run after setting the control.
+ * @return Whether the control has changed from the server
*/
- public void setControl(@Nullable InsetsSourceControl control,
+ public boolean setControl(@Nullable InsetsSourceControl control,
@InsetsType int[] showTypes, @InsetsType int[] hideTypes) {
if (mType == ITYPE_IME) {
ImeTracing.getInstance().triggerClientDump("InsetsSourceConsumer#setControl",
@@ -134,7 +135,7 @@ public class InsetsSourceConsumer {
mSourceControl.release(SurfaceControl::release);
mSourceControl = control;
}
- return;
+ return false;
}
SurfaceControl oldLeash = mSourceControl != null ? mSourceControl.getLeash() : null;
@@ -201,6 +202,7 @@ public class InsetsSourceConsumer {
if (lastControl != null) {
lastControl.release(SurfaceControl::release);
}
+ return true;
}
@VisibleForTesting
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index eb746080de15..9d6b982c3571 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -294,9 +294,16 @@ public class InsetsState implements Parcelable {
return RoundedCorners.NO_ROUNDED_CORNERS;
}
// If mRoundedCornerFrame is set, we should calculate the new RoundedCorners based on this
- // frame. It's used for split-screen mode and devices with a task bar.
- if (!mRoundedCornerFrame.isEmpty() && !mRoundedCornerFrame.equals(mDisplayFrame)) {
- return mRoundedCorners.insetWithFrame(frame, mRoundedCornerFrame);
+ // frame.
+ final Rect roundedCornerFrame = new Rect(mRoundedCornerFrame);
+ for (InsetsSource source : mSources) {
+ if (source != null && source.getInsetsRoundedCornerFrame()) {
+ final Insets insets = source.calculateInsets(roundedCornerFrame, false);
+ roundedCornerFrame.inset(insets);
+ }
+ }
+ if (!roundedCornerFrame.isEmpty() && !roundedCornerFrame.equals(mDisplayFrame)) {
+ return mRoundedCorners.insetWithFrame(frame, roundedCornerFrame);
}
if (mDisplayFrame.equals(frame)) {
return mRoundedCorners;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b5bbc7537391..6c4933e07b90 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -785,12 +785,14 @@ public final class SurfaceControl implements Parcelable {
private final HardwareBuffer mHardwareBuffer;
private final ColorSpace mColorSpace;
private final boolean mContainsSecureLayers;
+ private final boolean mContainsHdrLayers;
public ScreenshotHardwareBuffer(HardwareBuffer hardwareBuffer, ColorSpace colorSpace,
- boolean containsSecureLayers) {
+ boolean containsSecureLayers, boolean containsHdrLayers) {
mHardwareBuffer = hardwareBuffer;
mColorSpace = colorSpace;
mContainsSecureLayers = containsSecureLayers;
+ mContainsHdrLayers = containsHdrLayers;
}
/**
@@ -798,13 +800,15 @@ public final class SurfaceControl implements Parcelable {
* @param hardwareBuffer The existing HardwareBuffer object
* @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
* @param containsSecureLayers Indicates whether this graphic buffer contains captured
- * contents
- * of secure layers, in which case the screenshot should not be persisted.
+ * contents of secure layers, in which case the screenshot
+ * should not be persisted.
+ * @param containsHdrLayers Indicates whether this graphic buffer contains HDR content.
*/
private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
- int namedColorSpace, boolean containsSecureLayers) {
+ int namedColorSpace, boolean containsSecureLayers, boolean containsHdrLayers) {
ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
- return new ScreenshotHardwareBuffer(hardwareBuffer, colorSpace, containsSecureLayers);
+ return new ScreenshotHardwareBuffer(
+ hardwareBuffer, colorSpace, containsSecureLayers, containsHdrLayers);
}
public ColorSpace getColorSpace() {
@@ -818,6 +822,14 @@ public final class SurfaceControl implements Parcelable {
public boolean containsSecureLayers() {
return mContainsSecureLayers;
}
+ /**
+ * Returns whether the screenshot contains at least one HDR layer.
+ * This information may be useful for informing the display whether this screenshot
+ * is allowed to be dimmed to SDR white.
+ */
+ public boolean containsHdrLayers() {
+ return mContainsHdrLayers;
+ }
/**
* Copy content of ScreenshotHardwareBuffer into a hardware bitmap and return it.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cf5727ea1342..62d0d37da84d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12066,8 +12066,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* <p>In multiple-screen scenarios, if the surface spans multiple screens,
* the coordinate space of the surface also spans multiple screens.
*
- * <p>After the method returns, the argument array contains the x- and
- * y-coordinates of the view relative to the view's left and top edges,
+ * <p>After the method returns, the argument array contains the x and y
+ * coordinates of the view relative to the view's left and top edges,
* respectively.
*
* @param location A two-element integer array in which the view coordinates
@@ -18743,18 +18743,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * If some part of this view is not clipped by any of its parents, then
- * return that area in r in global (root) coordinates. To convert r to local
- * coordinates (without taking possible View rotations into account), offset
- * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)).
- * If the view is completely clipped or translated out, return false.
+ * Sets {@code r} to the coordinates of the non-clipped area of this view in
+ * the coordinate space of the view's root view. Sets {@code globalOffset}
+ * to the offset of the view's x and y coordinates from the coordinate space
+ * origin, which is the top left corner of the root view irrespective of
+ * screen decorations and system UI elements.
*
- * @param r If true is returned, r holds the global coordinates of the
- * visible portion of this view.
- * @param globalOffset If true is returned, globalOffset holds the dx,dy
- * between this view and its root. globalOffet may be null.
- * @return true if r is non-empty (i.e. part of the view is visible at the
- * root level.
+ * <p>To convert {@code r} to coordinates relative to the top left corner of
+ * this view (without taking view rotations into account), offset {@code r}
+ * by the inverse values of
+ * {@code globalOffset}&mdash;{@code r.offset(-globalOffset.x,
+ * -globalOffset.y)}&mdash;which is equivalent to calling
+ * {@link #getLocalVisibleRect(Rect) getLocalVisibleRect(Rect)}.
+ *
+ * <p><b>Note:</b> Do not use this method to determine the size of a window
+ * in multi-window mode; use
+ * {@link WindowManager#getCurrentWindowMetrics()}.
+ *
+ * @param r If the method returns true, contains the coordinates of the
+ * visible portion of this view in the coordinate space of the view's
+ * root view. If the method returns false, the contents of {@code r}
+ * are undefined.
+ * @param globalOffset If the method returns true, contains the offset of
+ * the x and y coordinates of this view from the top left corner of the
+ * view's root view. If the method returns false, the contents of
+ * {@code globalOffset} are undefined. The argument can be null (see
+ * {@link #getGlobalVisibleRect(Rect) getGlobalVisibleRect(Rect)}.
+ * @return true if at least part of the view is visible within the root
+ * view; false if the view is completely clipped or translated out of
+ * the visible area of the root view.
+ *
+ * @see #getLocalVisibleRect(Rect)
*/
public boolean getGlobalVisibleRect(Rect r, Point globalOffset) {
int width = mRight - mLeft;
@@ -18769,10 +18788,48 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return false;
}
+ /**
+ * Sets {@code r} to the coordinates of the non-clipped area of this view in
+ * the coordinate space of the view's root view.
+ *
+ * <p>See {@link #getGlobalVisibleRect(Rect, Point)
+ * getGlobalVisibleRect(Rect, Point)} for more information.
+ *
+ * @param r If the method returns true, contains the coordinates of the
+ * visible portion of this view in the coordinate space of the view's
+ * root view. If the method returns false, the contents of {@code r}
+ * are undefined.
+ * @return true if at least part of the view is visible within the root
+ * view; otherwise false.
+ */
public final boolean getGlobalVisibleRect(Rect r) {
return getGlobalVisibleRect(r, null);
}
+ /**
+ * Sets {@code r} to the coordinates of the non-clipped area of this view
+ * relative to the top left corner of the view.
+ *
+ * <p>If the view is clipped on the left or top, the left and top
+ * coordinates are offset from 0 by the clipped amount. For example, if the
+ * view is off screen 50px on the left and 30px at the top, the left and top
+ * coordinates are 50 and 30 respectively.
+ *
+ * <p>If the view is clipped on the right or bottom, the right and bottom
+ * coordinates are reduced by the clipped amount. For example, if the view
+ * is off screen 40px on the right and 20px at the bottom, the right
+ * coordinate is the view width - 40, and the bottom coordinate is the view
+ * height - 20.
+ *
+ * @param r If the method returns true, contains the coordinates of the
+ * visible portion of this view relative to the top left corner of the
+ * view. If the method returns false, the contents of {@code r} are
+ * undefined.
+ * @return true if at least part of the view is visible; false if the view
+ * is completely clipped or translated out of the visible area.
+ *
+ * @see #getGlobalVisibleRect(Rect, Point)
+ */
public final boolean getLocalVisibleRect(Rect r) {
final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point();
if (getGlobalVisibleRect(r, offset)) {
@@ -25606,8 +25663,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* multiple-screen environment, the coordinate space includes only the
* screen on which the app is running.
*
- * <p>After the method returns, the argument array contains the x- and
- * y-coordinates of the view relative to the view's left and top edges,
+ * <p>After the method returns, the argument array contains the x and y
+ * coordinates of the view relative to the view's left and top edges,
* respectively.
*
* @param outLocation A two-element integer array in which the view
@@ -25637,8 +25694,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* restricted to a single screen, the coordinate space includes only the
* screen on which the app is running.
*
- * <p>After the method returns, the argument array contains the x- and
- * y-coordinates of the view relative to the view's left and top edges,
+ * <p>After the method returns, the argument array contains the x and y
+ * coordinates of the view relative to the view's left and top edges,
* respectively.
*
* @param outLocation A two-element integer array in which the view
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fbb86ff3a55a..b7a2aa0b0174 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5035,9 +5035,6 @@ public final class ViewRootImpl implements ViewParent,
}
void requestPointerCapture(boolean enabled) {
- if (mPointerCapture == enabled) {
- return;
- }
final IBinder inputToken = getInputToken();
if (inputToken == null) {
Log.e(mTag, "No input channel to request Pointer Capture.");
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index cfe44bbbf3c6..5bc340b76f56 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -488,6 +488,13 @@ public interface WindowManager extends ViewManager {
int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION = 0x8;
/**
+ * Transition flag: Keyguard is going away to the launcher, and it needs us to clear the task
+ * snapshot of the launcher because it has changed something in the Launcher window.
+ * @hide
+ */
+ int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT = 0x16;
+
+ /**
* Transition flag: App is crashed.
* @hide
*/
@@ -527,6 +534,7 @@ public interface WindowManager extends ViewManager {
TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION,
TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER,
TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION,
+ TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT,
TRANSIT_FLAG_APP_CRASHED,
TRANSIT_FLAG_OPEN_BEHIND,
TRANSIT_FLAG_KEYGUARD_LOCKED,
@@ -717,8 +725,8 @@ public interface WindowManager extends ViewManager {
/**
* Returns a set of {@link WindowMetrics} for the given display. Each WindowMetrics instance
- * is the maximum WindowMetrics for a device state, including rotations. This is not guaranteed
- * to include all possible device states.
+ * is the maximum WindowMetrics for a device state. This is not guaranteed to include all
+ * possible device states.
*
* This API can only be used by Launcher.
*
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index 94f633314b4e..4d07171d3086 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -48,6 +48,7 @@ public interface WindowManagerPolicyConstants {
int KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS = 1 << 1;
int KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER = 1 << 2;
int KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS = 1 << 3;
+ int KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT = 1 << 4;
// Flags used for indicating whether the internal and/or external input devices
// of some type are available.
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 79dac19d0927..7dc039d44f95 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -650,6 +650,26 @@ public final class WindowContainerTransaction implements Parcelable {
}
/**
+ * Requests focus on the top running Activity in the given TaskFragment. This will only take
+ * effect if there is no focus, or if the current focus is in the same Task as the requested
+ * TaskFragment.
+ * @param fragmentToken client assigned unique token to create TaskFragment with specified in
+ * {@link TaskFragmentCreationParams#getFragmentToken()}.
+ * @hide
+ */
+ @NonNull
+ public WindowContainerTransaction requestFocusOnTaskFragment(@NonNull IBinder fragmentToken) {
+ final HierarchyOp hierarchyOp =
+ new HierarchyOp.Builder(
+ HierarchyOp.HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT)
+ .setContainer(fragmentToken)
+ .build();
+ mHierarchyOps.add(hierarchyOp);
+ return this;
+
+ }
+
+ /**
* When this {@link WindowContainerTransaction} failed to finish on the server side, it will
* trigger callback with this {@param errorCallbackToken}.
* @param errorCallbackToken client provided token that will be passed back as parameter in
@@ -1057,6 +1077,7 @@ public final class WindowContainerTransaction implements Parcelable {
public static final int HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER = 15;
public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 16;
public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 17;
+ public static final int HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 18;
// The following key(s) are for use with mLaunchOptions:
// When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1368,6 +1389,8 @@ public final class WindowContainerTransaction implements Parcelable {
case HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER:
return "{removeLocalInsetsProvider: container=" + mContainer
+ " insetsType=" + Arrays.toString(mInsetsTypes) + "}";
+ case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT:
+ return "{requestFocusOnTaskFragment: container=" + mContainer + "}";
default:
return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
+ " mToTop=" + mToTop
diff --git a/core/java/com/android/internal/app/AppLocaleStore.java b/core/java/com/android/internal/app/AppLocaleStore.java
index f95838516927..599e6d24600c 100644
--- a/core/java/com/android/internal/app/AppLocaleStore.java
+++ b/core/java/com/android/internal/app/AppLocaleStore.java
@@ -51,13 +51,17 @@ class AppLocaleStore {
appSupportedLocales.add(packageLocaleList.get(i));
}
} else {
- localeStatus = LocaleStatus.NO_SUPPORTED_LANGUAGE;
+ localeStatus = LocaleStatus.NO_SUPPORTED_LANGUAGE_IN_APP;
}
} else if (localeConfig.getStatus() == LocaleConfig.STATUS_NOT_SPECIFIED) {
- localeStatus = LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_ASSET;
String[] languages = getAssetLocales(context, packageName);
- for (String language : languages) {
- appSupportedLocales.add(Locale.forLanguageTag(language));
+ if (languages.length > 0) {
+ localeStatus = LocaleStatus.GET_SUPPORTED_LANGUAGE_FROM_ASSET;
+ for (String language : languages) {
+ appSupportedLocales.add(Locale.forLanguageTag(language));
+ }
+ } else {
+ localeStatus = LocaleStatus.ASSET_LOCALE_IS_EMPTY;
}
}
}
@@ -89,7 +93,8 @@ class AppLocaleStore {
static class AppLocaleResult {
enum LocaleStatus {
UNKNOWN_FAILURE,
- NO_SUPPORTED_LANGUAGE,
+ NO_SUPPORTED_LANGUAGE_IN_APP,
+ ASSET_LOCALE_IS_EMPTY,
GET_SUPPORTED_LANGUAGE_FROM_LOCAL_CONFIG,
GET_SUPPORTED_LANGUAGE_FROM_ASSET,
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 52d54cd1f717..681693b1dbad 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -284,4 +284,9 @@ interface IVoiceInteractionManagerService {
* Stops to listen the status of visible activity.
*/
void stopListeningVisibleActivityChanged(in IBinder token);
+
+ /**
+ * Notifies when the session window is shown or hidden.
+ */
+ void setSessionWindowVisible(in IBinder token, boolean visible);
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl b/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl
index bc757e24c852..6e409885fa13 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl
@@ -30,6 +30,11 @@
void onVoiceSessionHidden();
/**
+ * Called when a voice session window is shown/hidden.
+ */
+ void onVoiceSessionWindowVisibilityChanged(boolean visible);
+
+ /**
* Called when UI hints were received.
*/
void onSetUiHints(in Bundle args);
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
index 314b0a0c81db..a06ba9be4689 100644
--- a/core/java/com/android/internal/app/LocalePickerWithRegion.java
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -247,6 +247,7 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
// In order to make the list view work with CollapsingToolbarLayout,
// we have to enable the nested scrolling feature of the list view.
getListView().setNestedScrollingEnabled(true);
+ getListView().setDivider(null);
}
@Override
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 351ac4587def..0a07e0a04a40 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -233,8 +233,14 @@ public class ResolverListAdapter extends BaseAdapter {
// copied the original unfiltered items to a separate List instance and can now filter
// the remainder in-place without any further bookkeeping.
boolean needsCopyOfUnfiltered = (mUnfilteredResolveList == currentResolveList);
- mUnfilteredResolveList = performSecondaryResolveListFiltering(
+ List<ResolvedComponentInfo> originalList = performSecondaryResolveListFiltering(
currentResolveList, needsCopyOfUnfiltered);
+ if (originalList != null) {
+ // Only need the originalList value if there was a modification (otherwise it's null
+ // and shouldn't overwrite mUnfilteredResolveList).
+ mUnfilteredResolveList = originalList;
+ }
+
return finishRebuildingListWithFilteredResults(currentResolveList, doPostProcessing);
}
@@ -293,7 +299,7 @@ public class ResolverListAdapter extends BaseAdapter {
* appearing in the rebuilt-list results, while still considering those items for the "other
* profile" special-treatment described in {@code rebuildList()}.
*
- * @return the same (possibly null) List reference as {@code currentResolveList}, if the list is
+ * @return the same (possibly null) List reference as {@code currentResolveList} if the list is
* unmodified as a result of filtering; or, if some item(s) were removed, then either a copy of
* the original {@code currentResolveList} (if {@code returnCopyOfOriginalListIfModified} is
* true), or null (otherwise).
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index 18fde4794969..5fe111148c91 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -27,7 +27,6 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
-import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.internal.R;
@@ -222,6 +221,7 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
convertView = mInflater.inflate(
R.layout.app_language_picker_current_locale_item, parent, false);
title = convertView.findViewById(R.id.language_picker_item);
+ addStateDescriptionIntoCurrentLocaleItem(convertView);
} else {
convertView = mInflater.inflate(
R.layout.language_picker_item, parent, false);
@@ -234,6 +234,7 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
if (!(convertView instanceof ViewGroup)) {
convertView = mInflater.inflate(
R.layout.app_language_picker_current_locale_item, parent, false);
+ addStateDescriptionIntoCurrentLocaleItem(convertView);
}
updateTextView(
convertView, convertView.findViewById(R.id.language_picker_item), position);
@@ -369,4 +370,9 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
: View.TEXT_DIRECTION_LTR);
}
}
+
+ private void addStateDescriptionIntoCurrentLocaleItem(View root) {
+ String description = root.getContext().getResources().getString(R.string.checked);
+ root.setStateDescription(description);
+ }
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 6424989c6b4f..1b52aa93a51d 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -28,6 +28,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_WIDGET;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_LAUNCH_CAMERA;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_APPEAR;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_DISAPPEAR;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PATTERN_APPEAR;
@@ -189,7 +190,8 @@ public class InteractionJankMonitor {
public static final int CUJ_SUW_LOADING_SCREEN_FOR_STATUS = 48;
public static final int CUJ_SPLIT_SCREEN_ENTER = 49;
public static final int CUJ_SPLIT_SCREEN_EXIT = 50;
- public static final int CUJ_SPLIT_SCREEN_RESIZE = 51;
+ public static final int CUJ_LOCKSCREEN_LAUNCH_CAMERA = 51; // reserved.
+ public static final int CUJ_SPLIT_SCREEN_RESIZE = 52;
private static final int NO_STATSD_LOGGING = -1;
@@ -249,6 +251,7 @@ public class InteractionJankMonitor {
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_SCREEN_FOR_STATUS,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_ENTER,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_EXIT,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_LAUNCH_CAMERA,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_RESIZE,
};
@@ -321,6 +324,7 @@ public class InteractionJankMonitor {
CUJ_SUW_LOADING_SCREEN_FOR_STATUS,
CUJ_SPLIT_SCREEN_ENTER,
CUJ_SPLIT_SCREEN_EXIT,
+ CUJ_LOCKSCREEN_LAUNCH_CAMERA,
CUJ_SPLIT_SCREEN_RESIZE
})
@Retention(RetentionPolicy.SOURCE)
@@ -742,6 +746,8 @@ public class InteractionJankMonitor {
return "SPLIT_SCREEN_ENTER";
case CUJ_SPLIT_SCREEN_EXIT:
return "SPLIT_SCREEN_EXIT";
+ case CUJ_LOCKSCREEN_LAUNCH_CAMERA:
+ return "CUJ_LOCKSCREEN_LAUNCH_CAMERA";
case CUJ_SPLIT_SCREEN_RESIZE:
return "CUJ_SPLIT_SCREEN_RESIZE";
}
diff --git a/core/java/com/android/internal/policy/ForceShowNavBarSettingsObserver.java b/core/java/com/android/internal/policy/ForceShowNavBarSettingsObserver.java
new file mode 100644
index 000000000000..fc064ea1ff10
--- /dev/null
+++ b/core/java/com/android/internal/policy/ForceShowNavBarSettingsObserver.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+/**
+ * A ContentObserver for listening {@link Settings.Secure#NAV_BAR_FORCE_VISIBLE} setting key.
+ *
+ * @hide
+ */
+public class ForceShowNavBarSettingsObserver extends ContentObserver {
+ private Context mContext;
+ private Runnable mOnChangeRunnable;
+
+ public ForceShowNavBarSettingsObserver(Handler handler, Context context) {
+ super(handler);
+ mContext = context;
+ }
+
+ public void setOnChangeRunnable(Runnable r) {
+ mOnChangeRunnable = r;
+ }
+
+ /**
+ * Registers the observer.
+ */
+ public void register() {
+ final ContentResolver r = mContext.getContentResolver();
+ r.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_FORCE_VISIBLE),
+ false, this, UserHandle.USER_ALL);
+ }
+
+ /**
+ * Unregisters the observer.
+ */
+ public void unregister() {
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ if (mOnChangeRunnable != null) {
+ mOnChangeRunnable.run();
+ }
+ }
+
+ /**
+ * Returns true only when it's in orce show navigation bar mode. Otherwise, return false.
+ */
+ public boolean isEnabled() {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.NAV_BAR_FORCE_VISIBLE, 0, UserHandle.USER_CURRENT) == 1;
+ }
+}
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
index 94a8ae5a8a67..f2c27a494fc9 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
@@ -76,6 +76,7 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
ContentResolver contentResolver = context.getContentResolver();
mPostScrollDelayMillis = Settings.Global.getLong(contentResolver,
SETTING_CAPTURE_DELAY, SETTING_CAPTURE_DELAY_DEFAULT);
+ Log.d(TAG, "screenshot.scroll_capture_delay = " + mPostScrollDelayMillis);
}
/** Based on ViewRootImpl#updateColorModeIfNeeded */
@@ -271,6 +272,13 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
Rect viewCaptureArea = new Rect(scrollResult.availableArea);
viewCaptureArea.offset(0, -scrollResult.scrollDelta);
+ view.postOnAnimationDelayed(
+ () -> doCapture(scrollResult, view, viewCaptureArea, onComplete),
+ mPostScrollDelayMillis);
+ }
+
+ private void doCapture(ScrollResult scrollResult, V view, Rect viewCaptureArea,
+ Consumer<Rect> onComplete) {
int result = mRenderer.renderView(view, viewCaptureArea);
if (result == HardwareRenderer.SYNC_OK
|| result == HardwareRenderer.SYNC_REDRAW_REQUESTED) {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 51a708b76801..c769da57eecc 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -322,7 +322,8 @@ public:
env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
gScreenshotHardwareBufferClassInfo.builder,
jhardwareBuffer, namedColorSpace,
- captureResults.capturedSecureLayers);
+ captureResults.capturedSecureLayers,
+ captureResults.capturedHdrLayers);
env->CallVoidMethod(screenCaptureListenerObject,
gScreenCaptureListenerClassInfo.onScreenCaptureComplete,
screenshotHardwareBuffer);
@@ -2399,7 +2400,7 @@ int register_android_view_SurfaceControl(JNIEnv* env)
MakeGlobalRefOrDie(env, screenshotGraphicsBufferClazz);
gScreenshotHardwareBufferClassInfo.builder =
GetStaticMethodIDOrDie(env, screenshotGraphicsBufferClazz, "createFromNative",
- "(Landroid/hardware/HardwareBuffer;IZ)Landroid/view/"
+ "(Landroid/hardware/HardwareBuffer;IZZ)Landroid/view/"
"SurfaceControl$ScreenshotHardwareBuffer;");
jclass displayedContentSampleClazz = FindClassOrDie(env,
diff --git a/core/proto/android/os/appbackgroundrestrictioninfo.proto b/core/proto/android/os/appbackgroundrestrictioninfo.proto
index 502fd64f97e4..5bf8ea79a8ea 100644
--- a/core/proto/android/os/appbackgroundrestrictioninfo.proto
+++ b/core/proto/android/os/appbackgroundrestrictioninfo.proto
@@ -73,12 +73,17 @@ message AppBackgroundRestrictionsInfo {
optional FgsTrackerInfo fgs_tracker_info = 5;
message BatteryTrackerInfo {
- // total battery usage within last 24h (percentage)
+ // total battery usage within last 24h (1/10000th)
optional int32 battery_24h = 1;
- // background battery usage (percentage)
+ // background battery usage (1/10000th)
optional int32 battery_usage_background = 2;
- // FGS battery usage (percentage)
+ // FGS battery usage (1/10000th)
optional int32 battery_usage_fgs = 3;
+ // Foreground battery usage (1/10000th)
+ optional int32 battery_usage_foreground = 4;
+ // Cached battery usage (1/10000th)
+ optional int32 battery_usage_cached = 5;
+
}
optional BatteryTrackerInfo battery_tracker_info = 6;
@@ -197,5 +202,8 @@ message AppBackgroundRestrictionsInfo {
// indicates if the current device is a low ram device.
optional bool low_mem_device = 12;
+
+ // indicates previous background restriction level.
+ optional RestrictionLevel previous_restriction_level = 13;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4075c5f4d8ae..217166c6810b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -377,6 +377,8 @@
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
<protected-broadcast android:name="com.android.internal.action.EUICC_FACTORY_RESET" />
+ <protected-broadcast
+ android:name="com.android.internal.action.EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS" />
<protected-broadcast android:name="com.android.server.usb.ACTION_OPEN_IN_APPS" />
<protected-broadcast android:name="com.android.server.am.DELETE_DUMPHEAP" />
<protected-broadcast android:name="com.android.server.net.action.SNOOZE_WARNING" />
@@ -6790,7 +6792,7 @@
android:excludeFromRecents="true"
android:exported="true"
android:permission="android.permission.MANAGE_GAME_ACTIVITY"
- android:theme="@style/Theme.Translucent.NoTitleBar">
+ android:theme="@style/Theme.GameSessionTrampoline">
</activity>
<receiver android:name="com.android.server.BootReceiver"
diff --git a/core/res/res/layout/app_language_picker_current_locale_item.xml b/core/res/res/layout/app_language_picker_current_locale_item.xml
index bf6d9639791a..990e26c8f6be 100644
--- a/core/res/res/layout/app_language_picker_current_locale_item.xml
+++ b/core/res/res/layout/app_language_picker_current_locale_item.xml
@@ -39,6 +39,6 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_check_24dp"
- app:tint="#0F9D58"/>
+ app:tint="?attr/colorAccentPrimaryVariant"/>
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/app_language_picker_system_current.xml b/core/res/res/layout/app_language_picker_system_current.xml
index 341ee2528671..300da25ea445 100644
--- a/core/res/res/layout/app_language_picker_system_current.xml
+++ b/core/res/res/layout/app_language_picker_system_current.xml
@@ -40,6 +40,6 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_check_24dp"
- app:tint="#0F9D58"/>
+ app:tint="?attr/colorAccentPrimaryVariant"/>
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 19b72bfbe6c0..edaf8cf279e3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2415,8 +2415,12 @@
<!-- Is the system user the only user allowed to dream. -->
<bool name="config_dreamsOnlyEnabledForSystemUser">false</bool>
+ <!-- Whether to dismiss the active dream when an activity is started. Doesn't apply to
+ assistant activities (ACTIVITY_TYPE_ASSISTANT) -->
+ <bool name="config_dismissDreamOnActivityStart">true</bool>
+
<!-- The prefix of dream component names that are loggable. If empty, logs "other" for all. -->
- <string name ="config_loggable_dream_prefix" translatable="false"></string>
+ <string name="config_loggable_dream_prefix" translatable="false"></string>
<!-- ComponentName of a dream to show whenever the system would otherwise have
gone to sleep. When the PowerManager is asked to go to sleep, it will instead
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 77500c42c6bf..d9ac5164f705 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -109,4 +109,12 @@
<!-- Telephony qualified networks service class name to bind to by default. -->
<string name="config_qualified_networks_service_class" translatable="false"></string>
<java-symbol type="string" name="config_qualified_networks_service_class" />
+
+ <!-- Whether enhanced IWLAN handover check is enabled. If enabled, telephony frameworks
+ will not perform handover if the target transport is out of service, or VoPS not
+ supported. The network will be torn down on the source transport, and will be
+ re-established on the target transport when condition is allowed for bringing up a
+ new network. -->
+ <bool name="config_enhanced_iwlan_handover_check">true</bool>
+ <java-symbol type="bool" name="config_enhanced_iwlan_handover_check" />
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 012030e9b393..8226ec435533 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2221,6 +2221,7 @@
<java-symbol type="array" name="config_supportedDreamComplications" />
<java-symbol type="array" name="config_dreamComplicationsEnabledByDefault" />
<java-symbol type="array" name="config_disabledDreamComponents" />
+ <java-symbol type="bool" name="config_dismissDreamOnActivityStart" />
<java-symbol type="string" name="config_loggable_dream_prefix" />
<java-symbol type="string" name="config_dozeComponent" />
<java-symbol type="string" name="enable_explore_by_touch_warning_title" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index bf42da080390..a60862b74e15 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -894,6 +894,22 @@ please see themes_device_defaults.xml.
<!-- @hide Special theme for the default system Activity-based Alert dialogs. -->
<style name="Theme.Dialog.Confirmation" parent="Theme.DeviceDefault.Dialog.Alert.DayNight" />
+ <!-- @hide Theme for GameSessionTrampolineActivity that prevents showing UI and activity
+ transitions. -->
+ <style name="Theme.GameSessionTrampoline">
+ <item name="backgroundDimEnabled">false</item>
+ <item name="colorBackgroundCacheHint">@null</item>
+ <item name="navigationBarColor">@color/transparent</item>
+ <item name="statusBarColor">@color/transparent</item>
+ <item name="windowAnimationStyle">@null</item>
+ <item name="windowBackground">@null</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowDrawsSystemBarBackgrounds">true</item>
+ <item name="windowIsFloating">true</item>
+ <item name="windowIsTranslucent">true</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
<!-- Theme for a window that looks like a toast. -->
<style name="Theme.Toast" parent="Theme.DeviceDefault.Dialog">
<item name="windowBackground">?attr/toastFrameBackground</item>
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index e083b0d460a2..3733bfa586d1 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -48,6 +48,7 @@ public class UriTest extends TestCase {
public void testParcelling() {
parcelAndUnparcel(Uri.parse("foo:bob%20lee"));
parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment"));
+ parcelAndUnparcel(Uri.fromParts("https", "www.google.com", null));
parcelAndUnparcel(new Uri.Builder()
.scheme("http")
.authority("crazybob.org")
@@ -890,9 +891,62 @@ public class UriTest extends TestCase {
Throwable targetException = expected.getTargetException();
// Check that the exception was thrown for the correct reason.
assertEquals("Unknown representation: 0", targetException.getMessage());
+ } finally {
+ parcel.recycle();
}
}
+ private Uri buildUriFromRawParcel(boolean argumentsEncoded,
+ String scheme,
+ String authority,
+ String path,
+ String query,
+ String fragment) {
+ // Representation value (from AbstractPart.REPRESENTATION_{ENCODED,DECODED}).
+ final int representation = argumentsEncoded ? 1 : 2;
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.writeInt(3); // hierarchical
+ parcel.writeString8(scheme);
+ parcel.writeInt(representation);
+ parcel.writeString8(authority);
+ parcel.writeInt(representation);
+ parcel.writeString8(path);
+ parcel.writeInt(representation);
+ parcel.writeString8(query);
+ parcel.writeInt(representation);
+ parcel.writeString8(fragment);
+ parcel.setDataPosition(0);
+ return Uri.CREATOR.createFromParcel(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ public void testUnparcelMalformedPath() {
+ // Regression tests for b/171966843.
+
+ // Test cases with arguments encoded (covering testing `scheme` * `authority` options).
+ Uri uri0 = buildUriFromRawParcel(true, "https", "google.com", "@evil.com", null, null);
+ assertEquals("https://google.com/@evil.com", uri0.toString());
+ Uri uri1 = buildUriFromRawParcel(true, null, "google.com", "@evil.com", "name=spark", "x");
+ assertEquals("//google.com/@evil.com?name=spark#x", uri1.toString());
+ Uri uri2 = buildUriFromRawParcel(true, "http:", null, "@evil.com", null, null);
+ assertEquals("http::/@evil.com", uri2.toString());
+ Uri uri3 = buildUriFromRawParcel(true, null, null, "@evil.com", null, null);
+ assertEquals("@evil.com", uri3.toString());
+
+ // Test cases with arguments not encoded (covering testing `scheme` * `authority` options).
+ Uri uriA = buildUriFromRawParcel(false, "https", "google.com", "@evil.com", null, null);
+ assertEquals("https://google.com/%40evil.com", uriA.toString());
+ Uri uriB = buildUriFromRawParcel(false, null, "google.com", "@evil.com", null, null);
+ assertEquals("//google.com/%40evil.com", uriB.toString());
+ Uri uriC = buildUriFromRawParcel(false, "http:", null, "@evil.com", null, null);
+ assertEquals("http::/%40evil.com", uriC.toString());
+ Uri uriD = buildUriFromRawParcel(false, null, null, "@evil.com", "name=spark", "y");
+ assertEquals("%40evil.com?name%3Dspark#y", uriD.toString());
+ }
+
public void testToSafeString() {
checkToSafeString("tel:xxxxxx", "tel:Google");
checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index b04b82629b92..a76d74edc0f4 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -128,6 +128,7 @@ public final class Icon implements Parcelable {
// TYPE_RESOURCE: Resources
// TYPE_DATA: DataBytes
private Object mObj1;
+ private boolean mCachedAshmem = false;
// TYPE_RESOURCE: package name
// TYPE_URI: uri string
@@ -156,6 +157,8 @@ public final class Icon implements Parcelable {
/**
* @return The {@link android.graphics.Bitmap} held by this {@link #TYPE_BITMAP} or
* {@link #TYPE_ADAPTIVE_BITMAP} Icon.
+ *
+ * Note that this will always return an immutable Bitmap.
* @hide
*/
@UnsupportedAppUsage
@@ -166,8 +169,20 @@ public final class Icon implements Parcelable {
return (Bitmap) mObj1;
}
+ /**
+ * Sets the Icon's contents to a particular Bitmap. Note that this may make a copy of the Bitmap
+ * if the supplied Bitmap is mutable. In that case, the value returned by getBitmap() may not
+ * equal the Bitmap passed to setBitmap().
+ *
+ * @hide
+ */
private void setBitmap(Bitmap b) {
- mObj1 = b;
+ if (b.isMutable()) {
+ mObj1 = b.copy(b.getConfig(), false);
+ } else {
+ mObj1 = b;
+ }
+ mCachedAshmem = false;
}
/**
@@ -488,6 +503,7 @@ public final class Icon implements Parcelable {
getBitmap().getAllocationByteCount() >= MIN_ASHMEM_ICON_SIZE) {
setBitmap(getBitmap().asShared());
}
+ mCachedAshmem = true;
}
/**
@@ -913,7 +929,10 @@ public final class Icon implements Parcelable {
switch (mType) {
case TYPE_BITMAP:
case TYPE_ADAPTIVE_BITMAP:
- final Bitmap bits = getBitmap();
+ if (!mCachedAshmem) {
+ mObj1 = ((Bitmap) mObj1).asShared();
+ mCachedAshmem = true;
+ }
getBitmap().writeToParcel(dest, flags);
break;
case TYPE_RESOURCE:
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 9f33cbcbcbd5..2328f76a7130 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -112,9 +112,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
*/
public void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent,
@Nullable Bundle options, @NonNull SplitRule sideRule,
- @Nullable Consumer<Exception> failureCallback) {
+ @Nullable Consumer<Exception> failureCallback, boolean isPlaceholder) {
try {
- mPresenter.startActivityToSide(launchingActivity, intent, options, sideRule);
+ mPresenter.startActivityToSide(launchingActivity, intent, options, sideRule,
+ isPlaceholder);
} catch (Exception e) {
if (failureCallback != null) {
failureCallback.accept(e);
@@ -710,8 +711,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
// TODO(b/190433398): Handle failed request
- startActivityToSide(activity, placeholderRule.getPlaceholderIntent(), null,
- placeholderRule, null);
+ startActivityToSide(activity, placeholderRule.getPlaceholderIntent(), null /* options */,
+ placeholderRule, null /* failureCallback */, true /* isPlaceholder */);
return true;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 716a087203d3..ee5a322eed4f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -217,12 +217,13 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
* @param launchingActivity An activity that should be in the primary container. If it is not
* currently in an existing container, a new one will be created and
* the activity will be re-parented to it.
- * @param activityIntent The intent to start the new activity.
- * @param activityOptions The options to apply to new activity start.
- * @param rule The split rule to be applied to the container.
+ * @param activityIntent The intent to start the new activity.
+ * @param activityOptions The options to apply to new activity start.
+ * @param rule The split rule to be applied to the container.
+ * @param isPlaceholder Whether the launch is a placeholder.
*/
void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent activityIntent,
- @Nullable Bundle activityOptions, @NonNull SplitRule rule) {
+ @Nullable Bundle activityOptions, @NonNull SplitRule rule, boolean isPlaceholder) {
final Rect parentBounds = getParentContainerBounds(launchingActivity);
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
isLtr(launchingActivity, rule));
@@ -244,6 +245,10 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
startActivityToSide(wct, primaryContainer.getTaskFragmentToken(), primaryRectBounds,
launchingActivity, secondaryContainer.getTaskFragmentToken(), secondaryRectBounds,
activityIntent, activityOptions, rule);
+ if (isPlaceholder) {
+ // When placeholder is launched in split, we should keep the focus on the primary.
+ wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken());
+ }
applyTransaction(wct);
primaryContainer.setLastRequestedBounds(primaryRectBounds);
@@ -272,14 +277,21 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
isLtr);
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds, rule,
isLtr);
+ final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
+ // Whether the placeholder is becoming side-by-side with the primary from fullscreen.
+ final boolean isPlaceholderBecomingSplit = splitContainer.isPlaceholderContainer()
+ && secondaryContainer.areLastRequestedBoundsEqual(null /* bounds */)
+ && !secondaryRectBounds.isEmpty();
// If the task fragments are not registered yet, the positions will be updated after they
// are created again.
resizeTaskFragmentIfRegistered(wct, primaryContainer, primaryRectBounds);
- final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
resizeTaskFragmentIfRegistered(wct, secondaryContainer, secondaryRectBounds);
-
setAdjacentTaskFragments(wct, primaryContainer, secondaryContainer, rule);
+ if (isPlaceholderBecomingSplit) {
+ // When placeholder is shown in split, we should keep the focus on the primary.
+ wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken());
+ }
}
private void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
diff --git a/libs/WindowManager/Shell/res/layout/split_decor.xml b/libs/WindowManager/Shell/res/layout/split_decor.xml
index dfb90affe7f6..443ecb2ed3f3 100644
--- a/libs/WindowManager/Shell/res/layout/split_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/split_decor.xml
@@ -20,8 +20,8 @@
android:layout_width="match_parent">
<ImageView android:id="@+id/split_resizing_icon"
- android:layout_height="@*android:dimen/starting_surface_icon_size"
- android:layout_width="@*android:dimen/starting_surface_icon_size"
+ android:layout_height="@dimen/split_icon_size"
+ android:layout_width="@dimen/split_icon_size"
android:layout_gravity="center"
android:scaleType="fitCenter"
android:padding="0dp"
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index c21381d1486a..1dac9caba01e 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -87,6 +87,8 @@
<!-- How high we lift the divider when touching -->
<dimen name="docked_stack_divider_lift_elevation">4dp</dimen>
+ <!-- Icon size for split screen -->
+ <dimen name="split_icon_size">72dp</dimen>
<!-- Divider handle size for legacy split screen -->
<dimen name="docked_divider_handle_width">16dp</dimen>
<dimen name="docked_divider_handle_height">2dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index a2b35fc9211a..a089585a5a00 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -454,8 +454,11 @@ public class BubbleExpandedView extends LinearLayout {
p.beginRecording(mOverflowView.getWidth(), mOverflowView.getHeight()));
p.endRecording();
Bitmap snapshot = Bitmap.createBitmap(p);
- return new SurfaceControl.ScreenshotHardwareBuffer(snapshot.getHardwareBuffer(),
- snapshot.getColorSpace(), false /* containsSecureLayers */);
+ return new SurfaceControl.ScreenshotHardwareBuffer(
+ snapshot.getHardwareBuffer(),
+ snapshot.getColorSpace(),
+ false /* containsSecureLayers */,
+ false /* containsHdrLayers */);
}
if (mTaskView == null || mTaskView.getSurfaceControl() == null) {
return null;
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 5dc6bd19853a..de30dbbe7e46 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
@@ -73,6 +73,8 @@ public class SplitDecorManager extends WindowlessWindowManager {
private Rect mBounds = new Rect();
private ValueAnimator mFadeAnimator;
+ private int mIconSize;
+
public SplitDecorManager(Configuration configuration, IconProvider iconProvider,
SurfaceSession surfaceSession) {
super(configuration, null /* rootSurface */, null /* hostInputToken */);
@@ -104,6 +106,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
mHostLeash = rootLeash;
mViewHost = new SurfaceControlViewHost(context, context.getDisplay(), this);
+ mIconSize = context.getResources().getDimensionPixelSize(R.dimen.split_icon_size);
final FrameLayout rootLayout = (FrameLayout) LayoutInflater.from(context)
.inflate(R.layout.split_decor, null);
mResizingIconView = rootLayout.findViewById(R.id.split_resizing_icon);
@@ -171,14 +174,14 @@ public class SplitDecorManager extends WindowlessWindowManager {
WindowManager.LayoutParams lp =
(WindowManager.LayoutParams) mViewHost.getView().getLayoutParams();
- lp.width = mIcon.getIntrinsicWidth();
- lp.height = mIcon.getIntrinsicHeight();
+ lp.width = mIconSize;
+ lp.height = mIconSize;
mViewHost.relayout(lp);
t.setLayer(mIconLeash, Integer.MAX_VALUE);
}
t.setPosition(mIconLeash,
- newBounds.width() / 2 - mIcon.getIntrinsicWidth() / 2,
- newBounds.height() / 2 - mIcon.getIntrinsicWidth() / 2);
+ newBounds.width() / 2 - mIconSize / 2,
+ newBounds.height() / 2 - mIconSize / 2);
boolean show = newBounds.width() > mBounds.width() || newBounds.height() > mBounds.height();
if (show != mShown) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index 0cea36ed48c8..28f59b53b5b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -111,8 +111,7 @@ public class DropZoneView extends FrameLayout {
mColorDrawable = new ColorDrawable();
setBackgroundDrawable(mColorDrawable);
- final int iconSize = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.starting_surface_icon_size);
+ final int iconSize = context.getResources().getDimensionPixelSize(R.dimen.split_icon_size);
mSplashScreenView = new ImageView(context);
mSplashScreenView.setScaleType(ImageView.ScaleType.FIT_CENTER);
addView(mSplashScreenView,
diff --git a/core/java/com/android/internal/policy/KidsModeSettingsObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
index 8a1d407382bc..f8f9d6b8f8a0 100644
--- a/core/java/com/android/internal/policy/KidsModeSettingsObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeSettingsObserver.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy;
+package com.android.wm.shell.kidsmode;
import android.content.ContentResolver;
import android.content.Context;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
index 28681526b4f2..dc703583a449 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
@@ -40,7 +40,6 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.KidsModeSettingsObserver;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayInsetsController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 9d6e34ddd9d7..91f9d2522397 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -1786,15 +1786,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override
public void onNoLongerSupportMultiWindow() {
if (mMainStage.isActive()) {
+ final boolean isMainStage = mMainStageListener == this;
if (!ENABLE_SHELL_TRANSITIONS) {
- StageCoordinator.this.exitSplitScreen(null /* childrenToTop */,
+ StageCoordinator.this.exitSplitScreen(isMainStage ? mMainStage : mSideStage,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
+ return;
}
+ final int stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
- prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
+ prepareExitSplitScreen(stageType, wct);
mSplitTransitions.startDismissTransition(null /* transition */, wct,
- StageCoordinator.this, STAGE_TYPE_UNDEFINED,
+ StageCoordinator.this, stageType,
EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index b7c80df03ce2..c9cab39b7d8b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -16,8 +16,6 @@
package com.android.wm.shell.flicker.apppairs
-import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -31,6 +29,7 @@ import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSuppo
import org.junit.After
import org.junit.Before
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -76,23 +75,23 @@ class AppPairsTestCannotPairNonResizeableApps(
resetMultiWindowConfig(instrumentation)
}
- @FlakyTest
+ @Ignore
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
- @FlakyTest(bugId = 206753786)
+ @Ignore
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
- @Presubmit
+ @Ignore
@Test
override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
- @Presubmit
+ @Ignore
@Test
fun appPairsDividerIsInvisibleAtEnd() = testSpec.appPairsDividerIsInvisibleAtEnd()
- @Presubmit
+ @Ignore
@Test
fun onlyResizeableAppWindowVisible() {
val nonResizeableApp = nonResizeableApp
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index 1ac664eb1f62..60c32c99d1ff 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -16,8 +16,6 @@
package com.android.wm.shell.flicker.apppairs
-import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -29,6 +27,7 @@ import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -57,23 +56,23 @@ class AppPairsTestPairPrimaryAndSecondaryApps(
}
}
- @Presubmit
+ @Ignore
@Test
override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
- @FlakyTest
+ @Ignore
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
- @FlakyTest(bugId = 206753786)
+ @Ignore
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
- @Presubmit
+ @Ignore
@Test
fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
- @Presubmit
+ @Ignore
@Test
fun bothAppWindowsVisible() {
testSpec.assertWmEnd {
@@ -82,7 +81,7 @@ class AppPairsTestPairPrimaryAndSecondaryApps(
}
}
- @FlakyTest
+ @Ignore
@Test
fun appsEndingBounds() {
testSpec.assertLayersEnd {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
index 57bcbc093a62..24869a802167 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
@@ -16,9 +16,7 @@
package com.android.wm.shell.flicker.apppairs
-import android.platform.test.annotations.Presubmit
import android.view.Display
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -33,6 +31,7 @@ import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.setSuppo
import org.junit.After
import org.junit.Before
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -89,23 +88,23 @@ class AppPairsTestSupportPairNonResizeableApps(
resetMultiWindowConfig(instrumentation)
}
- @Presubmit
+ @Ignore
@Test
override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
- @FlakyTest
+ @Ignore
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
- @FlakyTest(bugId = 206753786)
+ @Ignore
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
- @Presubmit
+ @Ignore
@Test
fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
- @Presubmit
+ @Ignore
@Test
fun bothAppWindowVisible() {
val nonResizeableApp = nonResizeableApp
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index 12910dd74271..007415d19860 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -17,8 +17,6 @@
package com.android.wm.shell.flicker.apppairs
import android.os.SystemClock
-import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -30,6 +28,7 @@ import com.android.wm.shell.flicker.appPairsDividerIsInvisibleAtEnd
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -65,19 +64,19 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
}
}
- @FlakyTest
+ @Ignore
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
- @FlakyTest(bugId = 206753786)
+ @Ignore
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
- @Presubmit
+ @Ignore
@Test
fun appPairsDividerIsInvisibleAtEnd() = testSpec.appPairsDividerIsInvisibleAtEnd()
- @Presubmit
+ @Ignore
@Test
fun bothAppWindowsInvisible() {
testSpec.assertWmEnd {
@@ -86,7 +85,7 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
}
}
- @FlakyTest
+ @Ignore
@Test
fun appsStartingBounds() {
testSpec.assertLayersStart {
@@ -98,7 +97,7 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
}
}
- @FlakyTest
+ @Ignore
@Test
fun appsEndingBounds() {
testSpec.assertLayersEnd {
@@ -107,7 +106,7 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
}
}
- @Presubmit
+ @Ignore
@Test
override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
index 863c3aff63a2..3e17948b4a84 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTransition.kt
@@ -18,9 +18,7 @@ package com.android.wm.shell.flicker.apppairs
import android.app.Instrumentation
import android.content.Context
-import android.platform.test.annotations.Presubmit
import android.system.helpers.ActivityHelper
-import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
@@ -42,6 +40,7 @@ import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import com.android.wm.shell.flicker.testapp.Components
import org.junit.After
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter) {
@@ -145,35 +144,35 @@ abstract class AppPairsTransition(protected val testSpec: FlickerTestParameter)
append("$primaryApp $secondaryApp")
}
- @FlakyTest(bugId = 186510496)
+ @Ignore
@Test
open fun navBarLayerIsVisible() {
testSpec.navBarLayerIsVisible()
}
- @Presubmit
+ @Ignore
@Test
open fun statusBarLayerIsVisible() {
testSpec.statusBarLayerIsVisible()
}
- @Presubmit
+ @Ignore
@Test
open fun navBarWindowIsVisible() {
testSpec.navBarWindowIsVisible()
}
- @Presubmit
+ @Ignore
@Test
open fun statusBarWindowIsVisible() {
testSpec.statusBarWindowIsVisible()
}
- @Presubmit
+ @Ignore
@Test
open fun navBarLayerRotatesAndScales() = testSpec.navBarLayerRotatesAndScales()
- @Presubmit
+ @Ignore
@Test
open fun statusBarLayerRotatesScales() = testSpec.statusBarLayerRotatesScales()
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index f2f4877a44c4..b0c3ba20d948 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -16,9 +16,7 @@
package com.android.wm.shell.flicker.apppairs
-import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -32,6 +30,7 @@ import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -60,15 +59,15 @@ class RotateTwoLaunchedAppsInAppPairsMode(
}
}
- @Presubmit
+ @Ignore
@Test
override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
- @Presubmit
+ @Ignore
@Test
override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
- @Presubmit
+ @Ignore
@Test
fun bothAppWindowsVisible() {
testSpec.assertWmEnd {
@@ -77,23 +76,23 @@ class RotateTwoLaunchedAppsInAppPairsMode(
}
}
- @Presubmit
+ @Ignore
@Test
fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
- @Presubmit
+ @Ignore
@Test
fun appPairsPrimaryBoundsIsVisibleAtEnd() =
testSpec.appPairsPrimaryBoundsIsVisibleAtEnd(testSpec.endRotation,
primaryApp.component)
- @Presubmit
+ @Ignore
@Test
fun appPairsSecondaryBoundsIsVisibleAtEnd() =
testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.endRotation,
secondaryApp.component)
- @FlakyTest(bugId = 206753786)
+ @Ignore
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index 2a173d16004f..ae56c7732a4d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -16,9 +16,7 @@
package com.android.wm.shell.flicker.apppairs
-import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -32,6 +30,7 @@ import com.android.wm.shell.flicker.appPairsSecondaryBoundsIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.waitAppsShown
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.FixMethodOrder
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -60,31 +59,31 @@ class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
}
}
- @Presubmit
+ @Ignore
@Test
fun appPairsDividerIsVisibleAtEnd() = testSpec.appPairsDividerIsVisibleAtEnd()
- @Presubmit
+ @Ignore
@Test
override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
- @Presubmit
+ @Ignore
@Test
override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
- @Presubmit
+ @Ignore
@Test
override fun statusBarWindowIsVisible() = super.statusBarWindowIsVisible()
- @Presubmit
+ @Ignore
@Test
override fun statusBarLayerIsVisible() = super.statusBarLayerIsVisible()
- @FlakyTest(bugId = 206753786)
+ @Ignore
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
- @Presubmit
+ @Ignore
@Test
fun bothAppWindowsVisible() {
testSpec.assertWmEnd {
@@ -93,13 +92,13 @@ class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
}
}
- @Presubmit
+ @Ignore
@Test
fun appPairsPrimaryBoundsIsVisibleAtEnd() =
testSpec.appPairsPrimaryBoundsIsVisibleAtEnd(testSpec.endRotation,
primaryApp.component)
- @Presubmit
+ @Ignore
@Test
fun appPairsSecondaryBoundsIsVisibleAtEnd() =
testSpec.appPairsSecondaryBoundsIsVisibleAtEnd(testSpec.endRotation,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
index 670fbd810907..b1f1c9e539df 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsTransition.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.apppairs
import android.view.Surface
-import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.setRotation
@@ -26,6 +25,7 @@ import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTrans
import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import org.junit.Assume.assumeFalse
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
abstract class RotateTwoLaunchedAppsTransition(
@@ -62,13 +62,13 @@ abstract class RotateTwoLaunchedAppsTransition(
super.setup()
}
- @FlakyTest
+ @Ignore
@Test
override fun navBarLayerIsVisible() {
super.navBarLayerIsVisible()
}
- @FlakyTest
+ @Ignore
@Test
override fun navBarLayerRotatesAndScales() {
super.navBarLayerRotatesAndScales()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
index 5526d5be7594..440a6f8fb59a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
@@ -44,7 +44,6 @@ import android.window.WindowContainerTransaction;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import com.android.internal.policy.KidsModeSettingsObserver;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
diff --git a/packages/SettingsLib/ActionButtonsPreference/res/layout-v31/settingslib_action_buttons.xml b/packages/SettingsLib/ActionButtonsPreference/res/layout-v31/settingslib_action_buttons.xml
index 7c3f5a566bdb..a596a9a59ee8 100644
--- a/packages/SettingsLib/ActionButtonsPreference/res/layout-v31/settingslib_action_buttons.xml
+++ b/packages/SettingsLib/ActionButtonsPreference/res/layout-v31/settingslib_action_buttons.xml
@@ -28,7 +28,8 @@
style="@style/SettingsLibActionButton"
android:layout_width="0dp"
android:layout_height="match_parent"
- android:layout_weight="1"/>
+ android:layout_weight="1"
+ android:hyphenationFrequency="normalFast"/>
<View
android:id="@+id/divider1"
@@ -43,7 +44,8 @@
style="@style/SettingsLibActionButton"
android:layout_width="0dp"
android:layout_height="match_parent"
- android:layout_weight="1"/>
+ android:layout_weight="1"
+ android:hyphenationFrequency="normalFast"/>
<View
android:id="@+id/divider2"
@@ -58,7 +60,8 @@
style="@style/SettingsLibActionButton"
android:layout_width="0dp"
android:layout_height="match_parent"
- android:layout_weight="1"/>
+ android:layout_weight="1"
+ android:hyphenationFrequency="normalFast"/>
<View
android:id="@+id/divider3"
@@ -73,5 +76,6 @@
style="@style/SettingsLibActionButton"
android:layout_width="0dp"
android:layout_height="match_parent"
- android:layout_weight="1"/>
+ android:layout_weight="1"
+ android:hyphenationFrequency="normalFast"/>
</LinearLayout>
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
index 7c9a045f4a42..fc0e05f7fb46 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
@@ -122,9 +122,10 @@ public class MainSwitchPreference extends TwoStatePreference implements OnMainSw
* Adds a listener for switch changes
*/
public void addOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
- if (mMainSwitchBar == null) {
+ if (!mSwitchChangeListeners.contains(listener)) {
mSwitchChangeListeners.add(listener);
- } else {
+ }
+ if (mMainSwitchBar != null) {
mMainSwitchBar.addOnSwitchChangeListener(listener);
}
}
@@ -133,9 +134,8 @@ public class MainSwitchPreference extends TwoStatePreference implements OnMainSw
* Remove a listener for switch changes
*/
public void removeOnSwitchChangeListener(OnMainSwitchChangeListener listener) {
- if (mMainSwitchBar == null) {
- mSwitchChangeListeners.remove(listener);
- } else {
+ mSwitchChangeListeners.remove(listener);
+ if (mMainSwitchBar != null) {
mMainSwitchBar.removeOnSwitchChangeListener(listener);
}
}
diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java
index b038d59e9fe4..5693c2f22d1e 100644
--- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java
+++ b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java
@@ -42,15 +42,13 @@ public class WorkPolicyUtils {
private static final int USER_NULL = -10000;
public WorkPolicyUtils(
- Context applicationContext,
- PackageManager mPm,
- UserManager mUm,
- DevicePolicyManager mDpm
+ Context context
) {
- mContext = applicationContext;
- mPackageManager = mPm;
- mUserManager = mUm;
- mDevicePolicyManager = mDpm;
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ mDevicePolicyManager =
+ (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 440a54435fc3..affcf585904a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -332,6 +332,9 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
*/
@Override
public int compareTo(MediaDevice another) {
+ if (another == null) {
+ return -1;
+ }
// Check Bluetooth device is have same connection state
if (isConnected() ^ another.isConnected()) {
if (isConnected()) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java
index 552fa11a42b7..3514932d4e8d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputConstants.java
@@ -48,6 +48,12 @@ public class MediaOutputConstants {
"com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG";
/**
+ * An intent action to launch media output broadcast dialog.
+ */
+ public static final String ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG =
+ "com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG";
+
+ /**
* Settings package name.
*/
public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiPermissionChecker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiPermissionChecker.java
new file mode 100644
index 000000000000..2fe6e4695b3c
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiPermissionChecker.java
@@ -0,0 +1,98 @@
+/*
+ * 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.wifi;
+
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.ACCESS_WIFI_STATE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Helper class to check Wi-Fi permissions.
+ */
+public class WifiPermissionChecker {
+
+ private static final String TAG = "WifiPermChecker";
+
+ private IActivityManager mActivityManager;
+ private PackageManager mPackageManager;
+ private String mLaunchedPackage;
+
+ public WifiPermissionChecker(Activity activity) {
+ this(activity, ActivityManager.getService());
+ }
+
+ public WifiPermissionChecker(Activity activity, IActivityManager activityManager) {
+ mActivityManager = activityManager;
+ mPackageManager = activity.getPackageManager();
+ mLaunchedPackage = getLaunchedFromPackage(activity);
+ }
+
+ /**
+ * Returns the launched package name
+ */
+ public String getLaunchedPackage() {
+ return mLaunchedPackage;
+ }
+
+ /**
+ * Returns whether the launched package can access Wi-Fi information
+ */
+ public boolean canAccessWifiState() {
+ return checkPermission(ACCESS_WIFI_STATE);
+ }
+
+ /**
+ * Returns whether the launched package can access precise location
+ */
+ public boolean canAccessFineLocation() {
+ return checkPermission(ACCESS_FINE_LOCATION);
+ }
+
+ private boolean checkPermission(String permission) {
+ if (mPackageManager == null || TextUtils.isEmpty(mLaunchedPackage)) {
+ Log.e(TAG, "Failed to check package permission!"
+ + " {PackageManager:" + mPackageManager
+ + ", LaunchedPackage:" + mLaunchedPackage + "}");
+ return false;
+ }
+
+ if (mPackageManager.checkPermission(permission, mLaunchedPackage) == PERMISSION_GRANTED) {
+ return true;
+ }
+
+ Log.w(TAG, "The launched package does not have the required permission!"
+ + " {LaunchedPackage:" + mLaunchedPackage + ", Permission:" + permission + "}");
+ return false;
+ }
+
+ private String getLaunchedFromPackage(Activity activity) {
+ try {
+ return mActivityManager.getLaunchedFromPackage(activity.getActivityToken());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can not get the launched package from activity manager!");
+ return null;
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiPermissionCheckerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiPermissionCheckerTest.java
new file mode 100644
index 000000000000..ec84141360e4
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiPermissionCheckerTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.wifi;
+
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.ACCESS_WIFI_STATE;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.app.IActivityManager;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+
+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;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiPermissionCheckerTest {
+
+ static final String LAUNCHED_PACKAGE = "TestPackage";
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Mock
+ PackageManager mPackageManager;
+ @Mock
+ IActivityManager mActivityManager;
+ @Mock
+ Activity mActivity;
+
+ WifiPermissionChecker mWifiPermissionChecker;
+
+ @Before
+ public void setUp() {
+ when(mActivity.getPackageManager()).thenReturn(mPackageManager);
+ fakeGetLaunchedFromPackage(LAUNCHED_PACKAGE);
+
+ mWifiPermissionChecker = new WifiPermissionChecker(mActivity, mActivityManager);
+ }
+
+ @Test
+ public void getLaunchedPackage_returnLaunchedFromPackage() {
+ assertThat(mWifiPermissionChecker.getLaunchedPackage()).isEqualTo(LAUNCHED_PACKAGE);
+ }
+
+ @Test
+ public void canAccessWifiState_noPermission_returnFalse() {
+ when(mPackageManager.checkPermission(ACCESS_WIFI_STATE, LAUNCHED_PACKAGE))
+ .thenReturn(PERMISSION_DENIED);
+
+ assertThat(mWifiPermissionChecker.canAccessWifiState()).isFalse();
+ }
+
+ @Test
+ public void canAccessWifiState_hasPermission_returnTrue() {
+ when(mPackageManager.checkPermission(ACCESS_WIFI_STATE, LAUNCHED_PACKAGE))
+ .thenReturn(PERMISSION_GRANTED);
+
+ assertThat(mWifiPermissionChecker.canAccessWifiState()).isTrue();
+ }
+
+ @Test
+ public void canAccessFineLocation_noPermission_returnFalse() {
+ when(mPackageManager.checkPermission(ACCESS_FINE_LOCATION, LAUNCHED_PACKAGE))
+ .thenReturn(PERMISSION_DENIED);
+
+ assertThat(mWifiPermissionChecker.canAccessFineLocation()).isFalse();
+ }
+
+ @Test
+ public void canAccessFineLocation_hasPermission_returnTrue() {
+ when(mPackageManager.checkPermission(ACCESS_FINE_LOCATION, LAUNCHED_PACKAGE))
+ .thenReturn(PERMISSION_GRANTED);
+
+ assertThat(mWifiPermissionChecker.canAccessFineLocation()).isTrue();
+ }
+
+ void fakeGetLaunchedFromPackage(String packageName) {
+ try {
+ when(mActivityManager.getLaunchedFromPackage(any())).thenReturn(packageName);
+ } catch (RemoteException e) {
+ // Do nothing
+ }
+ }
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index f949f99673d9..3029781f3e99 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -117,6 +117,9 @@ public class SecureSettings {
Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
Settings.Secure.FACE_UNLOCK_APP_ENABLED,
Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
+ Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
+ Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
Settings.Secure.VR_DISPLAY_MODE,
Settings.Secure.NOTIFICATION_BADGING,
Settings.Secure.NOTIFICATION_DISMISS_RTL,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 2bdf81912709..a4da49713f87 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -173,6 +173,9 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.SHOW_MEDIA_WHEN_BYPASSING, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.FACE_UNLOCK_APP_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_WAKE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_WAKE_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index f1b23d5733af..4b7d0d2a3c74 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -597,6 +597,7 @@ public class SettingsBackupTest {
Settings.Global.CLOCKWORK_HOME_READY,
Settings.Global.WATCHDOG_TIMEOUT_MILLIS,
Settings.Global.MANAGED_PROVISIONING_DEFER_PROVISIONING_TO_ROLE_HOLDER,
+ Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE,
Settings.Global.Wearable.BATTERY_SAVER_MODE,
Settings.Global.Wearable.COMBINED_LOCATION_ENABLED,
Settings.Global.Wearable.HAS_PAY_TOKENS,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6887d037c6f4..290ce345694e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -931,6 +931,7 @@
android:exported="true">
<intent-filter>
<action android:name="com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG" />
+ <action android:name="com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG" />
<action android:name="com.android.systemui.action.DISMISS_MEDIA_OUTPUT_DIALOG" />
</intent-filter>
</receiver>
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
index ca557796462f..093589f8c636 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -20,6 +20,7 @@ import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.animation.PropertyValuesHolder
+import android.animation.ValueAnimator
import android.util.IntProperty
import android.view.View
import android.view.ViewGroup
@@ -37,6 +38,7 @@ class ViewHierarchyAnimator {
private const val DEFAULT_DURATION = 500L
private val DEFAULT_INTERPOLATOR = Interpolators.STANDARD
private val DEFAULT_ADDITION_INTERPOLATOR = Interpolators.STANDARD_DECELERATE
+ private val DEFAULT_REMOVAL_INTERPOLATOR = Interpolators.STANDARD_ACCELERATE
/** The properties used to animate the view bounds. */
private val PROPERTIES = mapOf(
@@ -113,7 +115,7 @@ class ViewHierarchyAnimator {
}
val listener = createUpdateListener(interpolator, duration, ephemeral)
- recursivelyAddListener(rootView, listener)
+ addListener(rootView, listener, recursive = true)
return true
}
@@ -183,7 +185,7 @@ class ViewHierarchyAnimator {
val listener = createAdditionListener(
origin, interpolator, duration, ignorePreviousValues = !includeMargins
)
- recursivelyAddListener(rootView, listener)
+ addListener(rootView, listener, recursive = true)
return true
}
@@ -298,6 +300,183 @@ class ViewHierarchyAnimator {
}
/**
+ * Animates the removal of [rootView] and its children from the hierarchy. It uses the given
+ * [interpolator] and [duration].
+ *
+ * The end state of the animation is controlled by [destination]. This value can be any of
+ * the four corners, any of the four edges, or the center of the view.
+ */
+ @JvmOverloads
+ fun animateRemoval(
+ rootView: View,
+ destination: Hotspot = Hotspot.CENTER,
+ interpolator: Interpolator = DEFAULT_REMOVAL_INTERPOLATOR,
+ duration: Long = DEFAULT_DURATION
+ ): Boolean {
+ if (!isVisible(
+ rootView.visibility,
+ rootView.left,
+ rootView.top,
+ rootView.right,
+ rootView.bottom
+ )
+ ) {
+ return false
+ }
+
+ val parent = rootView.parent as ViewGroup
+
+ // Ensure that rootView's siblings animate nicely around the removal.
+ val listener = createUpdateListener(
+ interpolator,
+ duration,
+ ephemeral = true
+ )
+ for (i in 0 until parent.childCount) {
+ val child = parent.getChildAt(i)
+ if (child == rootView) continue
+ addListener(child, listener, recursive = false)
+ }
+
+ // Remove the view so that a layout update is triggered for the siblings and they
+ // animate to their next position while the view's removal is also animating.
+ parent.removeView(rootView)
+ // By adding the view to the overlay, we can animate it while it isn't part of the view
+ // hierarchy. It is correctly positioned because we have its previous bounds, and we set
+ // them manually during the animation.
+ parent.overlay.add(rootView)
+
+ val startValues = mapOf(
+ Bound.LEFT to rootView.left,
+ Bound.TOP to rootView.top,
+ Bound.RIGHT to rootView.right,
+ Bound.BOTTOM to rootView.bottom
+ )
+ val endValues = processEndValuesForRemoval(
+ destination,
+ rootView.left,
+ rootView.top,
+ rootView.right,
+ rootView.bottom
+ )
+
+ val boundsToAnimate = mutableSetOf<Bound>()
+ if (rootView.left != endValues.getValue(Bound.LEFT)) boundsToAnimate.add(Bound.LEFT)
+ if (rootView.top != endValues.getValue(Bound.TOP)) boundsToAnimate.add(Bound.TOP)
+ if (rootView.right != endValues.getValue(Bound.RIGHT)) boundsToAnimate.add(Bound.RIGHT)
+ if (rootView.bottom != endValues.getValue(Bound.BOTTOM)) {
+ boundsToAnimate.add(Bound.BOTTOM)
+ }
+
+ startAnimation(
+ rootView,
+ boundsToAnimate,
+ startValues,
+ endValues,
+ interpolator,
+ duration,
+ ephemeral = true
+ )
+
+ if (rootView is ViewGroup) {
+ // Shift the children so they maintain a consistent position within the shrinking
+ // view.
+ shiftChildrenForRemoval(rootView, destination, endValues, interpolator, duration)
+
+ // Fade out the children during the first half of the removal, so they don't clutter
+ // too much once the view becomes very small. Then we fade out the view itself, in
+ // case it has its own content and/or background.
+ val startAlphas = FloatArray(rootView.childCount)
+ for (i in 0 until rootView.childCount) {
+ startAlphas[i] = rootView.getChildAt(i).alpha
+ }
+
+ val animator = ValueAnimator.ofFloat(1f, 0f)
+ animator.interpolator = Interpolators.ALPHA_OUT
+ animator.duration = duration / 2
+ animator.addUpdateListener { animation ->
+ for (i in 0 until rootView.childCount) {
+ rootView.getChildAt(i).alpha =
+ (animation.animatedValue as Float) * startAlphas[i]
+ }
+ }
+ animator.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ rootView.animate()
+ .alpha(0f)
+ .setInterpolator(Interpolators.ALPHA_OUT)
+ .setDuration(duration / 2)
+ .withEndAction { parent.overlay.remove(rootView) }
+ .start()
+ }
+ })
+ animator.start()
+ } else {
+ // Fade out the view during the second half of the removal.
+ rootView.animate()
+ .alpha(0f)
+ .setInterpolator(Interpolators.ALPHA_OUT)
+ .setDuration(duration / 2)
+ .setStartDelay(duration / 2)
+ .withEndAction { parent.overlay.remove(rootView) }
+ .start()
+ }
+
+ return true
+ }
+
+ /**
+ * Animates the children of [rootView] so that its layout remains internally consistent as
+ * it shrinks towards [destination] and changes its bounds to [endValues].
+ *
+ * Uses [interpolator] and [duration], which should match those of the removal animation.
+ */
+ private fun shiftChildrenForRemoval(
+ rootView: ViewGroup,
+ destination: Hotspot,
+ endValues: Map<Bound, Int>,
+ interpolator: Interpolator,
+ duration: Long
+ ) {
+ for (i in 0 until rootView.childCount) {
+ val child = rootView.getChildAt(i)
+ val childStartValues = mapOf(
+ Bound.LEFT to child.left,
+ Bound.TOP to child.top,
+ Bound.RIGHT to child.right,
+ Bound.BOTTOM to child.bottom
+ )
+ val childEndValues = processChildEndValuesForRemoval(
+ destination,
+ child.left,
+ child.top,
+ child.right,
+ child.bottom,
+ endValues.getValue(Bound.RIGHT) - endValues.getValue(Bound.LEFT),
+ endValues.getValue(Bound.BOTTOM) - endValues.getValue(Bound.TOP)
+ )
+
+ val boundsToAnimate = mutableSetOf<Bound>()
+ if (child.left != endValues.getValue(Bound.LEFT)) boundsToAnimate.add(Bound.LEFT)
+ if (child.top != endValues.getValue(Bound.TOP)) boundsToAnimate.add(Bound.TOP)
+ if (child.right != endValues.getValue(Bound.RIGHT)) boundsToAnimate.add(Bound.RIGHT)
+ if (child.bottom != endValues.getValue(Bound.BOTTOM)) {
+ boundsToAnimate.add(Bound.BOTTOM)
+ }
+
+ startAnimation(
+ child,
+ boundsToAnimate,
+ childStartValues,
+ childEndValues,
+ interpolator,
+ duration,
+ ephemeral = true
+ )
+ }
+ }
+
+ /**
* Returns whether the given [visibility] and bounds are consistent with a view being
* currently visible on screen.
*/
@@ -312,7 +491,7 @@ class ViewHierarchyAnimator {
}
/**
- * Compute the actual starting values based on the requested [origin] and on
+ * Computes the actual starting values based on the requested [origin] and on
* [ignorePreviousValues].
*
* If [origin] is null, the resolved start values will be the same as those passed in, or
@@ -422,7 +601,140 @@ class ViewHierarchyAnimator {
)
}
- private fun recursivelyAddListener(view: View, listener: View.OnLayoutChangeListener) {
+ /**
+ * Computes a removal animation's end values based on the requested [destination] and the
+ * view's starting bounds.
+ *
+ * Examples:
+ * 1) destination=TOP
+ * x---------x x---------x x---------x x---------x x---------x
+ * | | | | | | x---------x
+ * | | -> | | -> x---------x -> ->
+ * | | x---------x
+ * x---------x
+ * 2) destination=BOTTOM_LEFT
+ * x---------x
+ * | | x-------x
+ * | | -> | | -> x----x -> ->
+ * | | | | | | x--x
+ * x---------x x-------x x----x x--x x
+ * 3) destination=CENTER
+ * x---------x
+ * | | x-------x x-----x
+ * | | -> | | -> | | -> x---x -> x
+ * | | x-------x x-----x
+ * x---------x
+ */
+ private fun processEndValuesForRemoval(
+ destination: Hotspot,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int
+ ): Map<Bound, Int> {
+ val endLeft = when (destination) {
+ Hotspot.CENTER -> (left + right) / 2
+ Hotspot.BOTTOM, Hotspot.BOTTOM_LEFT, Hotspot.LEFT, Hotspot.TOP_LEFT, Hotspot.TOP ->
+ left
+ Hotspot.TOP_RIGHT, Hotspot.RIGHT, Hotspot.BOTTOM_RIGHT -> right
+ }
+ val endTop = when (destination) {
+ Hotspot.CENTER -> (top + bottom) / 2
+ Hotspot.LEFT, Hotspot.TOP_LEFT, Hotspot.TOP, Hotspot.TOP_RIGHT, Hotspot.RIGHT ->
+ top
+ Hotspot.BOTTOM_RIGHT, Hotspot.BOTTOM, Hotspot.BOTTOM_LEFT -> bottom
+ }
+ val endRight = when (destination) {
+ Hotspot.CENTER -> (left + right) / 2
+ Hotspot.TOP, Hotspot.TOP_RIGHT, Hotspot.RIGHT,
+ Hotspot.BOTTOM_RIGHT, Hotspot.BOTTOM ->
+ right
+ Hotspot.BOTTOM_LEFT, Hotspot.LEFT, Hotspot.TOP_LEFT -> left
+ }
+ val endBottom = when (destination) {
+ Hotspot.CENTER -> (top + bottom) / 2
+ Hotspot.RIGHT, Hotspot.BOTTOM_RIGHT, Hotspot.BOTTOM,
+ Hotspot.BOTTOM_LEFT, Hotspot.LEFT ->
+ bottom
+ Hotspot.TOP_LEFT, Hotspot.TOP, Hotspot.TOP_RIGHT -> top
+ }
+
+ return mapOf(
+ Bound.LEFT to endLeft,
+ Bound.TOP to endTop,
+ Bound.RIGHT to endRight,
+ Bound.BOTTOM to endBottom
+ )
+ }
+
+ /**
+ * Computes the end values for the child of a view being removed, based on the child's
+ * starting bounds, the removal's [destination], and the [parentWidth] and [parentHeight].
+ *
+ * The end values always represent the child's position after it has been translated so that
+ * its center is at the [destination].
+ *
+ * Examples:
+ * 1) destination=TOP
+ * The child maintains its left and right positions, but is shifted up so that its
+ * center is on the parent's end top edge.
+ * 2) destination=BOTTOM_LEFT
+ * The child shifts so that its center is on the parent's end bottom left corner.
+ * 3) destination=CENTER
+ * The child shifts so that its own center is on the parent's end center.
+ */
+ private fun processChildEndValuesForRemoval(
+ destination: Hotspot,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ parentWidth: Int,
+ parentHeight: Int
+ ): Map<Bound, Int> {
+ val halfWidth = (right - left) / 2
+ val halfHeight = (bottom - top) / 2
+
+ val endLeft = when (destination) {
+ Hotspot.CENTER -> (parentWidth / 2) - halfWidth
+ Hotspot.BOTTOM_LEFT, Hotspot.LEFT, Hotspot.TOP_LEFT -> -halfWidth
+ Hotspot.TOP_RIGHT, Hotspot.RIGHT, Hotspot.BOTTOM_RIGHT -> parentWidth - halfWidth
+ Hotspot.TOP, Hotspot.BOTTOM -> left
+ }
+ val endTop = when (destination) {
+ Hotspot.CENTER -> (parentHeight / 2) - halfHeight
+ Hotspot.TOP_LEFT, Hotspot.TOP, Hotspot.TOP_RIGHT -> -halfHeight
+ Hotspot.BOTTOM_RIGHT, Hotspot.BOTTOM, Hotspot.BOTTOM_LEFT ->
+ parentHeight - halfHeight
+ Hotspot.LEFT, Hotspot.RIGHT -> top
+ }
+ val endRight = when (destination) {
+ Hotspot.CENTER -> (parentWidth / 2) + halfWidth
+ Hotspot.TOP_RIGHT, Hotspot.RIGHT, Hotspot.BOTTOM_RIGHT -> parentWidth + halfWidth
+ Hotspot.BOTTOM_LEFT, Hotspot.LEFT, Hotspot.TOP_LEFT -> halfWidth
+ Hotspot.TOP, Hotspot.BOTTOM -> right
+ }
+ val endBottom = when (destination) {
+ Hotspot.CENTER -> (parentHeight / 2) + halfHeight
+ Hotspot.BOTTOM_RIGHT, Hotspot.BOTTOM, Hotspot.BOTTOM_LEFT ->
+ parentHeight + halfHeight
+ Hotspot.TOP_LEFT, Hotspot.TOP, Hotspot.TOP_RIGHT -> halfHeight
+ Hotspot.LEFT, Hotspot.RIGHT -> bottom
+ }
+
+ return mapOf(
+ Bound.LEFT to endLeft,
+ Bound.TOP to endTop,
+ Bound.RIGHT to endRight,
+ Bound.BOTTOM to endBottom
+ )
+ }
+
+ private fun addListener(
+ view: View,
+ listener: View.OnLayoutChangeListener,
+ recursive: Boolean = false
+ ) {
// Make sure that only one listener is active at a time.
val previousListener = view.getTag(R.id.tag_layout_listener)
if (previousListener != null && previousListener is View.OnLayoutChangeListener) {
@@ -431,9 +743,9 @@ class ViewHierarchyAnimator {
view.addOnLayoutChangeListener(listener)
view.setTag(R.id.tag_layout_listener, listener)
- if (view is ViewGroup) {
+ if (view is ViewGroup && recursive) {
for (i in 0 until view.childCount) {
- recursivelyAddListener(view.getChildAt(i), listener)
+ addListener(view.getChildAt(i), listener, recursive = true)
}
}
}
@@ -490,6 +802,8 @@ class ViewHierarchyAnimator {
}
}.toTypedArray()
+ (view.getTag(R.id.tag_animator) as? ObjectAnimator)?.cancel()
+
val animator = ObjectAnimator.ofPropertyValuesHolder(view, *propertyValuesHolders)
animator.interpolator = interpolator
animator.duration = duration
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 46dad02ddb45..dd45b6f39bdd 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -23,6 +23,7 @@ import com.android.internal.graphics.ColorUtils
import com.android.internal.graphics.cam.Cam
import com.android.internal.graphics.cam.CamUtils.lstarFromInt
import kotlin.math.absoluteValue
+import kotlin.math.max
import kotlin.math.roundToInt
const val TAG = "ColorScheme"
@@ -78,36 +79,32 @@ internal class HueSubtract(val amountDegrees: Double) : Hue {
}
internal class HueVibrantSecondary() : Hue {
- val hueToRotations = listOf(Pair(24, 15), Pair(53, 15), Pair(91, 15), Pair(123, 15),
- Pair(141, 15), Pair(172, 15), Pair(198, 15), Pair(234, 18), Pair(272, 18),
- Pair(302, 18), Pair(329, 30), Pair(354, 15))
+ val hueToRotations = listOf(Pair(0, 18), Pair(41, 15), Pair(61, 10), Pair(101, 12),
+ Pair(131, 15), Pair(181, 18), Pair(251, 15), Pair(301, 12))
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
}
internal class HueVibrantTertiary() : Hue {
- val hueToRotations = listOf(Pair(24, 30), Pair(53, 30), Pair(91, 15), Pair(123, 30),
- Pair(141, 27), Pair(172, 27), Pair(198, 30), Pair(234, 35), Pair(272, 30),
- Pair(302, 30), Pair(329, 60), Pair(354, 30))
+ val hueToRotations = listOf(Pair(0, 35), Pair(41, 30), Pair(61, 20), Pair(101, 25),
+ Pair(131, 30), Pair(181, 35), Pair(251, 30), Pair(301, 25))
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
}
internal class HueExpressiveSecondary() : Hue {
- val hueToRotations = listOf(Pair(24, 95), Pair(53, 45), Pair(91, 45), Pair(123, 20),
- Pair(141, 45), Pair(172, 45), Pair(198, 15), Pair(234, 15),
- Pair(272, 45), Pair(302, 45), Pair(329, 45), Pair(354, 45))
+ val hueToRotations = listOf(Pair(0, 45), Pair(21, 95), Pair(51, 45), Pair(121, 20),
+ Pair(141, 45), Pair(191, 90), Pair(271, 45), Pair(321, 45))
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
}
internal class HueExpressiveTertiary() : Hue {
- val hueToRotations = listOf(Pair(24, 20), Pair(53, 20), Pair(91, 20), Pair(123, 45),
- Pair(141, 20), Pair(172, 20), Pair(198, 90), Pair(234, 90), Pair(272, 20),
- Pair(302, 20), Pair(329, 120), Pair(354, 120))
+ val hueToRotations = listOf(Pair(0, 120), Pair(21, 120), Pair(51, 20), Pair(121, 45),
+ Pair(141, 20), Pair(191, 15), Pair(271, 20), Pair(321, 120))
override fun get(sourceColor: Cam): Double {
return getHueRotation(sourceColor.hue, hueToRotations)
}
@@ -140,18 +137,15 @@ internal interface Chroma {
}
}
-internal class ChromaConstant(val chroma: Double) : Chroma {
+internal class ChromaMinimum(val chroma: Double) : Chroma {
override fun get(sourceColor: Cam): Double {
- return chroma
+ return max(sourceColor.chroma.toDouble(), chroma)
}
}
-internal class ChromaExpressiveNeutral() : Chroma {
- val hueToChromas = listOf(Pair(24, 8), Pair(53, 8), Pair(91, 8), Pair(123, 8),
- Pair(141, 6), Pair(172, 6), Pair(198, 8), Pair(234, 8), Pair(272, 8),
- Pair(302, 8), Pair(329, 8), Pair(354, 8))
+internal class ChromaConstant(val chroma: Double) : Chroma {
override fun get(sourceColor: Cam): Double {
- return getSpecifiedChroma(sourceColor.hue, hueToChromas)
+ return chroma
}
}
@@ -187,17 +181,17 @@ enum class Style(internal val coreSpec: CoreSpec) {
n2 = TonalSpec(HueSource(), ChromaConstant(8.0))
)),
VIBRANT(CoreSpec(
- a1 = TonalSpec(HueSource(), ChromaConstant(48.0)),
+ a1 = TonalSpec(HueSource(), ChromaMinimum(48.0)),
a2 = TonalSpec(HueVibrantSecondary(), ChromaConstant(24.0)),
a3 = TonalSpec(HueVibrantTertiary(), ChromaConstant(32.0)),
- n1 = TonalSpec(HueSource(), ChromaConstant(6.0)),
+ n1 = TonalSpec(HueSource(), ChromaConstant(10.0)),
n2 = TonalSpec(HueSource(), ChromaConstant(12.0))
)),
EXPRESSIVE(CoreSpec(
a1 = TonalSpec(HueAdd(240.0), ChromaConstant(40.0)),
a2 = TonalSpec(HueExpressiveSecondary(), ChromaConstant(24.0)),
- a3 = TonalSpec(HueExpressiveTertiary(), ChromaConstant(40.0)),
- n1 = TonalSpec(HueAdd(15.0), ChromaExpressiveNeutral()),
+ a3 = TonalSpec(HueExpressiveTertiary(), ChromaConstant(32.0)),
+ n1 = TonalSpec(HueAdd(15.0), ChromaConstant(8.0)),
n2 = TonalSpec(HueAdd(15.0), ChromaConstant(12.0))
)),
RAINBOW(CoreSpec(
@@ -231,8 +225,13 @@ class ColorScheme(
constructor(@ColorInt seed: Int, darkTheme: Boolean):
this(seed, darkTheme, Style.TONAL_SPOT)
- constructor(wallpaperColors: WallpaperColors, darkTheme: Boolean):
- this(getSeedColor(wallpaperColors), darkTheme)
+ @JvmOverloads
+ constructor(
+ wallpaperColors: WallpaperColors,
+ darkTheme: Boolean,
+ style: Style = Style.TONAL_SPOT
+ ):
+ this(getSeedColor(wallpaperColors), darkTheme, style)
val allAccentColors: List<Int>
get() {
diff --git a/packages/SystemUI/res-keyguard/layout/fgs_footer.xml b/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
index 9ffafbc8cc09..6757acf7014a 100644
--- a/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
+++ b/packages/SystemUI/res-keyguard/layout/fgs_footer.xml
@@ -55,6 +55,15 @@
android:textColor="?android:attr/textColorSecondary"/>
<ImageView
+ android:id="@+id/fgs_new"
+ android:layout_width="12dp"
+ android:layout_height="12dp"
+ android:scaleType="fitCenter"
+ android:src="@drawable/fgs_dot"
+ android:contentDescription="@string/fgs_dot_content_description"
+ />
+
+ <ImageView
android:id="@+id/footer_icon"
android:layout_width="@dimen/qs_footer_icon_size"
android:layout_height="@dimen/qs_footer_icon_size"
@@ -82,7 +91,7 @@
android:textColor="?android:attr/textColorPrimary"
android:textSize="18sp"/>
<ImageView
- android:id="@+id/fgs_new"
+ android:id="@+id/fgs_collapsed_new"
android:layout_width="12dp"
android:layout_height="12dp"
android:scaleType="fitCenter"
diff --git a/packages/SystemUI/res/drawable/keyguard_framed_avatar_background.xml b/packages/SystemUI/res/drawable/keyguard_framed_avatar_background.xml
new file mode 100644
index 000000000000..a461bf836d61
--- /dev/null
+++ b/packages/SystemUI/res/drawable/keyguard_framed_avatar_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners android:radius="@dimen/kg_framed_avatar_size"/>
+ <solid android:color="@color/kg_user_avatar_frame"/>
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml b/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml
index 9cf09ff328c4..6f3362308484 100644
--- a/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml
+++ b/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml
@@ -22,18 +22,25 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="end">
- <com.android.systemui.statusbar.phone.UserAvatarView
- android:id="@+id/kg_multi_user_avatar"
- android:layout_width="@dimen/kg_framed_avatar_size"
- android:layout_height="@dimen/kg_framed_avatar_size"
- android:layout_centerHorizontal="true"
+ <!-- We add a background behind the UserAvatarView with the same color and with a circular shape
+ so that this view can be expanded into a Dialog or an Activity. -->
+ <FrameLayout
+ android:id="@+id/kg_multi_user_avatar_with_background"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_marginEnd="16dp"
- systemui:avatarPadding="0dp"
- systemui:badgeDiameter="18dp"
- systemui:badgeMargin="1dp"
- systemui:frameColor="@color/kg_user_avatar_frame"
- systemui:framePadding="0dp"
- systemui:frameWidth="0dp">
- </com.android.systemui.statusbar.phone.UserAvatarView>
+ android:background="@drawable/keyguard_framed_avatar_background">
+ <com.android.systemui.statusbar.phone.UserAvatarView
+ android:id="@+id/kg_multi_user_avatar"
+ android:layout_width="@dimen/kg_framed_avatar_size"
+ android:layout_height="@dimen/kg_framed_avatar_size"
+ systemui:avatarPadding="0dp"
+ systemui:badgeDiameter="18dp"
+ systemui:badgeMargin="1dp"
+ systemui:frameColor="@color/kg_user_avatar_frame"
+ systemui:framePadding="0dp"
+ systemui:frameWidth="0dp">
+ </com.android.systemui.statusbar.phone.UserAvatarView>
+ </FrameLayout>
</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml b/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml
index 8b7a019b791b..89dcbcc5929f 100644
--- a/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_broadcast_update_dialog.xml
@@ -19,11 +19,19 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="?android:attr/dialogPreferredPadding"
- android:paddingRight="?android:attr/dialogPreferredPadding">
+ android:paddingRight="?android:attr/dialogPreferredPadding"
+ android:orientation="vertical">
<EditText
android:id="@+id/broadcast_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:textAlignment="viewStart"/>
+ <TextView
+ android:id="@+id/broadcast_error_message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="6dp"
+ style="@style/TextAppearance.ErrorText"
+ android:visibility="invisible"/>
</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 2264671e5067..008299bd9b1c 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -60,11 +60,15 @@
<dimen name="global_actions_grid_item_layout_height">80dp</dimen>
+ <dimen name="qs_brightness_margin_bottom">16dp</dimen>
+
<!-- For large screens the security footer appears below the footer,
same as phones in portrait -->
<dimen name="qs_security_footer_single_line_height">48dp</dimen>
<dimen name="qs_security_footer_background_inset">0dp</dimen>
+ <dimen name="qs_panel_padding_top">8dp</dimen>
+
<!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) -->
<dimen name="large_dialog_width">472dp</dimen>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 83b1b52fff3d..c8fff39cc8e5 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -711,4 +711,10 @@
<item>@*android:string/status_bar_alarm_clock</item>
<item>@*android:string/status_bar_call_strength</item>
</string-array>
+
+ <!-- Packages of SystemUI -->
+ <string-array name="system_ui_packages" translatable="false">
+ <item>com.android.keyguard</item>
+ <item>com.android.systemui</item>
+ </string-array>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4a8fd1b00dde..0a858af31964 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1179,6 +1179,10 @@
<!-- Maximum over scroll amount for the shade when transition to the full shade. -->
<dimen name="lockscreen_shade_max_over_scroll_amount">24dp</dimen>
+ <!-- Maximum over scroll amount for the shade when transition to the full shade.
+ Only used for split-shade. -->
+ <dimen name="shade_max_over_scroll_amount">@dimen/lockscreen_shade_max_over_scroll_amount</dimen>
+
<!-- Maximum overshoot for the pulse expansion -->
<dimen name="pulse_expansion_max_top_overshoot">32dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f92d6238e863..6cc61b4706f6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -213,6 +213,8 @@
<!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] -->
<string name="screenshot_failed_to_capture_text">Taking screenshots isn\'t allowed by the app or
your organization</string>
+ <!-- Notification text displayed when screenshots are blocked by an IT admin. [CHAR LIMIT=100] -->
+ <string name="screenshot_blocked_by_admin">Taking screenshots is blocked by your IT admin</string>
<!-- Label for UI element which allows editing the screenshot [CHAR LIMIT=30] -->
<string name="screenshot_edit_label">Edit</string>
<!-- Content description indicating that tapping the element will allow editing the screenshot [CHAR LIMIT=NONE] -->
@@ -1994,7 +1996,8 @@
app for debugging. Will not be seen by users. [CHAR LIMIT=20] -->
<string name="heap_dump_tile_name">Dump SysUI Heap</string>
- <!-- Content description for ongoing privacy chip. Use with a single app [CHAR LIMIT=NONE]-->
+ <!-- Title for the privacy indicators dialog, only appears as part of a11y descriptions [CHAR LIMIT=NONE] -->
+ <string name="ongoing_privacy_dialog_a11y_title">In use</string>
<!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]-->
<string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string>
@@ -2290,6 +2293,11 @@
<string name="media_output_broadcast_starting">Starting&#8230;</string>
<!-- The button text when Broadcast start failed [CHAR LIMIT=60] -->
<string name="media_output_broadcast_start_failed">Can\u2019t broadcast</string>
+ <!-- The error message when Broadcast name/code update failed [CHAR LIMIT=60] -->
+ <string name="media_output_broadcast_update_error">Can\u2019t save. Try again.</string>
+ <!-- The error message when Broadcast name/code update failed and can't change again[CHAR LIMIT=60] -->
+ <string name="media_output_broadcast_last_update_error">Can\u2019t save.</string>
+
<!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]-->
<string name="build_number_clip_data_label">Build number</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ILauncherUnlockAnimationController.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ILauncherUnlockAnimationController.aidl
index b2295b94127b..5a30901f1a8b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ILauncherUnlockAnimationController.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ILauncherUnlockAnimationController.aidl
@@ -16,17 +16,20 @@
package com.android.systemui.shared.system.smartspace;
+import android.graphics.Rect;
import com.android.systemui.shared.system.smartspace.SmartspaceState;
// Methods for System UI to interface with Launcher to perform the unlock animation.
interface ILauncherUnlockAnimationController {
// Prepares Launcher for the unlock animation by setting scale/alpha/etc. to their starting
// values.
- void prepareForUnlock(boolean willAnimateSmartspace, int selectedPage);
+ void prepareForUnlock(boolean animateSmartspace, in Rect lockscreenSmartspaceBounds,
+ int selectedPage);
// Set the unlock percentage. This is used when System UI is controlling each frame of the
- // unlock animation, such as during a swipe to unlock touch gesture.
- oneway void setUnlockAmount(float amount);
+ // unlock animation, such as during a swipe to unlock touch gesture. Will not apply this change
+ // if the unlock amount is animating unless forceIfAnimating is true.
+ oneway void setUnlockAmount(float amount, boolean forceIfAnimating);
// Play a full unlock animation from 0f to 1f. This is used when System UI is unlocking from a
// single action, such as biometric auth, and doesn't need to control individual frames.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 04c9a45af065..ea14b64b8b18 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -58,9 +58,7 @@ import com.android.systemui.util.ViewController;
import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter;
-import java.util.HashSet;
import java.util.Locale;
-import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.Executor;
@@ -134,14 +132,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mKeyguardUnlockAnimationListener =
new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@Override
- public void onSmartspaceSharedElementTransitionStarted() {
- // The smartspace needs to be able to translate out of bounds in order to
- // end up where the launcher's smartspace is, while its container is being
- // swiped off the top of the screen.
- setClipChildrenForUnlock(false);
- }
-
- @Override
public void onUnlockAnimationFinished() {
// For performance reasons, reset this once the unlock animation ends.
setClipChildrenForUnlock(true);
@@ -390,41 +380,6 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
if (mStatusArea != null) {
PropertyAnimator.setProperty(mStatusArea, AnimatableProperty.TRANSLATION_X,
x, props, animate);
-
- // If we're unlocking with the SmartSpace shared element transition, let the controller
- // know that it should re-position our SmartSpace.
- if (mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
- mKeyguardUnlockAnimationController.updateLockscreenSmartSpacePosition();
- }
- }
- }
-
- /** Sets an alpha value on every child view except for the smartspace. */
- public void setChildrenAlphaExcludingSmartspace(float alpha) {
- final Set<View> excludedViews = new HashSet<>();
-
- if (mSmartspaceView != null) {
- excludedViews.add(mStatusArea);
- }
-
- // Don't change the alpha of the invisible clock.
- if (mCurrentClockSize == LARGE) {
- excludedViews.add(mClockFrame);
- } else {
- excludedViews.add(mLargeClockFrame);
- }
-
- setChildrenAlphaExcluding(alpha, excludedViews);
- }
-
- /** Sets an alpha value on every child view except for the views in the provided set. */
- public void setChildrenAlphaExcluding(float alpha, Set<View> excludedViews) {
- for (int i = 0; i < mView.getChildCount(); i++) {
- final View child = mView.getChildAt(i);
-
- if (!excludedViews.contains(child)) {
- child.setAlpha(alpha);
- }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 1ede76fb1fa4..02776a295359 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -16,7 +16,6 @@
package com.android.keyguard;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.DEFAULT_DISPLAY_GROUP;
import android.app.Presentation;
import android.content.Context;
@@ -119,10 +118,9 @@ public class KeyguardDisplayManager {
if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on a private display");
return false;
}
- if (mTmpDisplayInfo.displayGroupId != DEFAULT_DISPLAY_GROUP) {
+ if ((mTmpDisplayInfo.flags & Display.FLAG_ALWAYS_UNLOCKED) != 0) {
if (DEBUG) {
- Log.i(TAG,
- "Do not show KeyguardPresentation on a non-default group display");
+ Log.i(TAG, "Do not show KeyguardPresentation on an unlocked display");
}
return false;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 853d7402a1f8..cb3172dabdb1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -47,7 +47,6 @@ public class KeyguardStatusView extends GridLayout {
private float mDarkAmount = 0;
private int mTextColor;
- private float mChildrenAlphaExcludingSmartSpace = 1f;
public KeyguardStatusView(Context context) {
this(context, null, 0);
@@ -95,23 +94,6 @@ public class KeyguardStatusView extends GridLayout {
mClockView.setTextColor(blendedTextColor);
}
- public void setChildrenAlphaExcludingClockView(float alpha) {
- setChildrenAlphaExcluding(alpha, Set.of(mClockView));
- }
-
- /** Sets an alpha value on every view except for the views in the provided set. */
- public void setChildrenAlphaExcluding(float alpha, Set<View> excludedViews) {
- mChildrenAlphaExcludingSmartSpace = alpha;
-
- for (int i = 0; i < mStatusViewContainer.getChildCount(); i++) {
- final View child = mStatusViewContainer.getChildAt(i);
-
- if (!excludedViews.contains(child)) {
- child.setAlpha(alpha);
- }
- }
- }
-
/** Sets a translationY value on every child view except for the media view. */
public void setChildrenTranslationYExcludingMediaView(float translationY) {
setChildrenTranslationYExcluding(translationY, Set.of(mMediaHostContainer));
@@ -128,10 +110,6 @@ public class KeyguardStatusView extends GridLayout {
}
}
- public float getChildrenAlphaExcludingSmartSpace() {
- return mChildrenAlphaExcludingSmartSpace;
- }
-
public void dump(PrintWriter pw, String[] args) {
pw.println("KeyguardStatusView:");
pw.println(" mDarkAmount: " + mDarkAmount);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 14c9cb2022bc..083f2fe53d17 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -20,7 +20,6 @@ import android.graphics.Rect;
import android.util.Slog;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
-import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -49,10 +48,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
private final KeyguardClockSwitchController mKeyguardClockSwitchController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController;
- private final DozeParameters mDozeParameters;
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
- private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
- private final KeyguardStateController mKeyguardStateController;
private final Rect mClipBounds = new Rect();
@Inject
@@ -64,18 +60,14 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController,
DozeParameters dozeParameters,
- KeyguardUnlockAnimationController keyguardUnlockAnimationController,
ScreenOffAnimationController screenOffAnimationController) {
super(keyguardStatusView);
mKeyguardSliceViewController = keyguardSliceViewController;
mKeyguardClockSwitchController = keyguardClockSwitchController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mConfigurationController = configurationController;
- mDozeParameters = dozeParameters;
- mKeyguardStateController = keyguardStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
dozeParameters, screenOffAnimationController, /* animateYPos= */ true);
- mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
}
@Override
@@ -87,14 +79,12 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
protected void onViewAttached() {
mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
mConfigurationController.addCallback(mConfigurationListener);
- mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
}
@Override
protected void onViewDetached() {
mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
mConfigurationController.removeCallback(mConfigurationListener);
- mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback);
}
/**
@@ -148,24 +138,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
*/
public void setAlpha(float alpha) {
if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
- // If we're capable of performing the SmartSpace shared element transition, and we are
- // going to (we're swiping to dismiss vs. bringing up the PIN screen), then fade out
- // everything except for the SmartSpace.
- if (mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
- mView.setChildrenAlphaExcludingClockView(alpha);
- mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(alpha);
- } else if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
- // Otherwise, we can just set the alpha for the entire container.
- mView.setAlpha(alpha);
-
- // If we previously unlocked with the shared element transition, some child views
- // might still have alpha = 0f. Set them back to 1f since we're just using the
- // parent container's alpha.
- if (mView.getChildrenAlphaExcludingSmartSpace() < 1f) {
- mView.setChildrenAlphaExcludingClockView(1f);
- mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(1f);
- }
- }
+ mView.setAlpha(alpha);
}
}
@@ -289,19 +262,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
};
- private KeyguardStateController.Callback mKeyguardStateControllerCallback =
- new KeyguardStateController.Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- // If we explicitly re-show the keyguard, make sure that all the child views are
- // visible. They might have been animating out as part of the SmartSpace shared
- // element transition.
- if (mKeyguardStateController.isShowing()) {
- mView.setChildrenAlphaExcludingClockView(1f);
- }
- }
- };
-
/**
* Rect that specifies how KSV should be clipped, on its parent's coordinates.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 239730d18934..95cda8b9dfca 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -668,7 +668,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mVelocityTracker.recycle();
mVelocityTracker = null;
}
- mVibrator.cancel();
}
private boolean inLockIconArea(MotionEvent event) {
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index f925eaa0e40b..eb6705a2e979 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -15,6 +15,8 @@
*/
package com.android.keyguard;
+import static com.android.systemui.util.ColorUtilKt.getPrivateAttrColorIfUnset;
+
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
@@ -152,7 +154,7 @@ class NumPadAnimator {
ContextThemeWrapper ctw = new ContextThemeWrapper(context, mStyle);
TypedArray a = ctw.obtainStyledAttributes(customAttrs);
- mNormalColor = Utils.getPrivateAttrColorIfUnset(ctw, a, 0, 0,
+ mNormalColor = getPrivateAttrColorIfUnset(ctw, a, 0, 0,
com.android.internal.R.attr.colorSurface);
mHighlightColor = a.getColor(1, 0);
a.recycle();
diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
index ccb5b1146a1c..e51a63fbcd10 100644
--- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
+++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
@@ -228,14 +228,20 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
if (pendingRotationChange) {
return
}
+ val m = Matrix()
+ // Apply display ratio.
+ val physicalPixelDisplaySizeRatio = getPhysicalPixelDisplaySizeRatio()
+ m.postScale(physicalPixelDisplaySizeRatio, physicalPixelDisplaySizeRatio)
+
+ // Apply rotation.
val lw: Int = displayInfo.logicalWidth
val lh: Int = displayInfo.logicalHeight
val flipped = (displayInfo.rotation == Surface.ROTATION_90 ||
displayInfo.rotation == Surface.ROTATION_270)
val dw = if (flipped) lh else lw
val dh = if (flipped) lw else lh
- val m = Matrix()
transformPhysicalToLogicalCoordinates(displayInfo.rotation, dw, dh, m)
+
if (!protectionPathOrig.isEmpty) {
// Reset the protection path so we don't aggregate rotations
protectionPath.set(protectionPathOrig)
@@ -244,6 +250,14 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
}
}
+ @VisibleForTesting
+ open fun getPhysicalPixelDisplaySizeRatio(): Float {
+ displayInfo.displayCutout?.let {
+ return it.cutoutPathParserInfo.physicalPixelDisplaySizeRatio
+ }
+ return 1f
+ }
+
private fun displayModeChanged(oldMode: Display.Mode?, newMode: Display.Mode?): Boolean {
if (oldMode == null) {
return true
@@ -265,17 +279,17 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView {
out: Matrix
) {
when (rotation) {
- Surface.ROTATION_0 -> out.reset()
+ Surface.ROTATION_0 -> return
Surface.ROTATION_90 -> {
- out.setRotate(270f)
+ out.postRotate(270f)
out.postTranslate(0f, physicalWidth.toFloat())
}
Surface.ROTATION_180 -> {
- out.setRotate(180f)
+ out.postRotate(180f)
out.postTranslate(physicalWidth.toFloat(), physicalHeight.toFloat())
}
Surface.ROTATION_270 -> {
- out.setRotate(90f)
+ out.postRotate(90f)
out.postTranslate(physicalHeight.toFloat(), 0f)
}
else -> throw IllegalArgumentException("Unknown rotation: $rotation")
diff --git a/packages/SystemUI/src/com/android/systemui/FontSizeUtils.java b/packages/SystemUI/src/com/android/systemui/FontSizeUtils.java
index 35a70a5ed52b..0d1dc9d6a5dd 100644
--- a/packages/SystemUI/src/com/android/systemui/FontSizeUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/FontSizeUtils.java
@@ -16,6 +16,8 @@
package com.android.systemui;
+import android.annotation.StyleRes;
+import android.content.res.TypedArray;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
@@ -23,9 +25,9 @@ import android.widget.TextView;
/**
* Utility class to update the font size when the configuration has changed.
*/
-public class FontSizeUtils {
+public final class FontSizeUtils {
- public static final float LARGE_TEXT_SCALE = 1.3f;
+ private FontSizeUtils() {}
public static void updateFontSize(View parent, int viewId, int dimensId) {
updateFontSize((TextView) parent.findViewById(viewId), dimensId);
@@ -37,4 +39,20 @@ public class FontSizeUtils {
v.getResources().getDimensionPixelSize(dimensId));
}
}
+
+ /**
+ * Updates the font size according to the style given.
+ *
+ * @param v Text to update.
+ * @param resId Style applying to the text.
+ */
+ public static void updateFontSizeFromStyle(TextView v, @StyleRes int resId) {
+ int[] attrs = {android.R.attr.textSize};
+ int indexOfAttrTextSize = 0;
+ TypedArray ta = v.getContext().obtainStyledAttributes(resId, attrs);
+ int updatedTextPixelSize = ta.getDimensionPixelSize(indexOfAttrTextSize,
+ (int) v.getTextSize());
+ v.setTextSize(TypedValue.COMPLEX_UNIT_PX, updatedTextPixelSize);
+ ta.recycle();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
index 3641e1d52144..0df2730a48eb 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
@@ -380,7 +380,7 @@ class ScreenDecorHwcLayer(context: Context, displayDecorationSupport: DisplayDec
) {
if (hasTopRoundedCorner == hasTop &&
hasBottomRoundedCorner == hasBottom &&
- roundedCornerBottomSize == bottomSize &&
+ roundedCornerTopSize == topSize &&
roundedCornerBottomSize == bottomSize) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index b98fc03e3acd..8d6509874776 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -348,7 +348,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
@Override
public void onDisplayChanged(int displayId) {
final int newRotation = mContext.getDisplay().getRotation();
- if (mOverlays != null && mRotation != newRotation) {
+ if ((mOverlays != null || mScreenDecorHwcWindow != null)
+ && mRotation != newRotation) {
// We cannot immediately update the orientation. Otherwise
// WindowManager is still deferring layout until it has finished dispatching
// the config changes, which may cause divergence between what we draw
@@ -362,11 +363,13 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
+ mRotation);
}
- for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
- if (mOverlays[i] != null) {
- final ViewGroup overlayView = mOverlays[i].getRootView();
- overlayView.getViewTreeObserver().addOnPreDrawListener(
- new RestartingPreDrawListener(overlayView, i, newRotation));
+ if (mOverlays != null) {
+ for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
+ if (mOverlays[i] != null) {
+ final ViewGroup overlayView = mOverlays[i].getRootView();
+ overlayView.getViewTreeObserver().addOnPreDrawListener(
+ new RestartingPreDrawListener(overlayView, i, newRotation));
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 9d5b93c2b329..7c2673c31bf5 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -187,6 +187,14 @@ public class AssistManager {
}
@Override
+ public void onVoiceSessionWindowVisibilityChanged(boolean visible)
+ throws RemoteException {
+ if (VERBOSE) {
+ Log.v(TAG, "Window visibility changed: " + visible);
+ }
+ }
+
+ @Override
public void onSetUiHints(Bundle hints) {
if (VERBOSE) {
Log.v(TAG, "UI hints received");
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
index dbfce2ed2532..2f097924817e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
@@ -112,17 +112,16 @@ public class UdfpsDialogMeasureAdapter {
if (child.getId() == R.id.biometric_icon_frame) {
final FrameLayout iconFrame = (FrameLayout) child;
final View icon = iconFrame.getChildAt(0);
-
- // Ensure that the icon is never larger than the sensor.
- icon.measure(
- MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST));
-
// Create a frame that's exactly the height of the sensor circle.
iconFrame.measure(
MeasureSpec.makeMeasureSpec(
child.getLayoutParams().width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY));
+
+ // Ensure that the icon is never larger than the sensor.
+ icon.measure(
+ MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST));
} else if (child.getId() == R.id.space_above_icon) {
child.measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
@@ -208,16 +207,15 @@ public class UdfpsDialogMeasureAdapter {
if (child.getId() == R.id.biometric_icon_frame) {
final FrameLayout iconFrame = (FrameLayout) child;
final View icon = iconFrame.getChildAt(0);
+ // Create a frame that's exactly the height of the sensor circle.
+ iconFrame.measure(
+ MeasureSpec.makeMeasureSpec(remeasuredWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY));
// Ensure that the icon is never larger than the sensor.
icon.measure(
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST));
-
- // Create a frame that's exactly the height of the sensor circle.
- iconFrame.measure(
- MeasureSpec.makeMeasureSpec(remeasuredWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY));
} else if (child.getId() == R.id.space_above_icon) {
// Adjust the width and height of the top spacer if necessary.
final int newTopSpacerHeight = child.getLayoutParams().height
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index 842791f8ed93..937b81337cbb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -127,17 +127,19 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
mBurnInProgress = MathUtils.lerp(0f, getBurnInProgressOffset(), darkAmountForAnimation);
if (mAnimatingBetweenAodAndLockscreen && !mPauseAuth) {
+ mLockScreenFp.setTranslationX(mBurnInOffsetX);
+ mLockScreenFp.setTranslationY(mBurnInOffsetY);
mBgProtection.setAlpha(1f - mInterpolatedDarkAmount);
mLockScreenFp.setAlpha(1f - mInterpolatedDarkAmount);
} else if (mInterpolatedDarkAmount == 0f) {
+ mLockScreenFp.setTranslationX(0);
+ mLockScreenFp.setTranslationY(0);
mBgProtection.setAlpha(mAlpha / 255f);
mLockScreenFp.setAlpha(mAlpha / 255f);
} else {
mBgProtection.setAlpha(0f);
mLockScreenFp.setAlpha(0f);
}
- mLockScreenFp.setTranslationX(mBurnInOffsetX);
- mLockScreenFp.setTranslationY(mBurnInOffsetY);
mLockScreenFp.setProgress(1f - mInterpolatedDarkAmount);
mAodFp.setTranslationX(mBurnInOffsetX);
diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt
index 9dbeb77ebc00..e316722b64ea 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt
@@ -105,7 +105,7 @@ private fun Int.toLayoutGravity(@Surface.Rotation rotation: Int): Int = when (ro
DisplayCutout.BOUNDS_POSITION_LEFT -> Gravity.BOTTOM
DisplayCutout.BOUNDS_POSITION_TOP -> Gravity.LEFT
DisplayCutout.BOUNDS_POSITION_RIGHT -> Gravity.TOP
- else /* DisplayCutout.BOUNDS_POSITION_BOTTOM */ -> Gravity.LEFT
+ else /* DisplayCutout.BOUNDS_POSITION_BOTTOM */ -> Gravity.RIGHT
}
Surface.ROTATION_270 -> when (this) {
DisplayCutout.BOUNDS_POSITION_LEFT -> Gravity.TOP
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 3ae11ff28345..9c7411bf3649 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -54,7 +54,7 @@ public class FragmentHostManager {
private final View mRootView;
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
- | ActivityInfo.CONFIG_LAYOUT_DIRECTION | ActivityInfo.CONFIG_ASSETS_PATHS);
+ | ActivityInfo.CONFIG_ASSETS_PATHS);
private final FragmentService mManager;
private final ExtensionFragmentManager mPlugins = new ExtensionFragmentManager();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index a8c286241141..b21a886b037d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -23,7 +23,7 @@ import android.content.Context
import android.graphics.Matrix
import android.graphics.Rect
import android.os.Handler
-import android.provider.Settings
+import android.os.RemoteException
import android.util.Log
import android.view.RemoteAnimationTarget
import android.view.SyncRtSurfaceTransactionApplier
@@ -47,7 +47,6 @@ import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy
import javax.inject.Inject
-import kotlin.math.min
const val TAG = "KeyguardUnlock"
@@ -77,7 +76,7 @@ const val SURFACE_BEHIND_SCALE_PIVOT_Y = 0.66f
* The dismiss amount is the inverse of the notification panel expansion, which decreases as the
* lock screen is swiped away.
*/
-const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.25f
+const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.15f
/**
* Dismiss amount at which to complete the keyguard exit animation and hide the keyguard.
@@ -85,7 +84,7 @@ const val DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD = 0.25f
* The dismiss amount is the inverse of the notification panel expansion, which decreases as the
* lock screen is swiped away.
*/
-const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.4f
+const val DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD = 0.3f
/**
* How long the canned unlock animation takes. This is used if we are unlocking from biometric auth,
@@ -112,7 +111,7 @@ const val CANNED_UNLOCK_START_DELAY = 100L
* Duration for the alpha animation on the surface behind. This plays to fade in the surface during
* a swipe to unlock (and to fade it back out if the swipe is cancelled).
*/
-const val SURFACE_BEHIND_SWIPE_FADE_DURATION_MS = 150L
+const val SURFACE_BEHIND_SWIPE_FADE_DURATION_MS = 175L
/**
* Start delay for the surface behind animation, used so that the lockscreen can get out of the way
@@ -151,12 +150,21 @@ class KeyguardUnlockAnimationController @Inject constructor(
* [playingCannedAnimation] indicates whether we are playing a canned animation to show the
* app/launcher behind the keyguard, vs. this being a swipe to unlock where the dismiss
* amount drives the animation.
+ *
* [fromWakeAndUnlock] tells us whether we are unlocking directly from AOD - in this case,
* the lockscreen is dismissed instantly, so we shouldn't run any animations that rely on it
* being visible.
+ *
+ * [unlockAnimationStartDelay] and [unlockAnimationDuration] provide the timing parameters
+ * for the canned animation (if applicable) so interested parties can sync with it. If no
+ * canned animation is playing, these are both 0.
*/
@JvmDefault
- fun onUnlockAnimationStarted(playingCannedAnimation: Boolean, fromWakeAndUnlock: Boolean) {}
+ fun onUnlockAnimationStarted(
+ playingCannedAnimation: Boolean,
+ fromWakeAndUnlock: Boolean,
+ unlockAnimationStartDelay: Long,
+ unlockAnimationDuration: Long) {}
/**
* Called when the remote unlock animation ends, in all cases, canned or swipe-to-unlock.
@@ -165,19 +173,6 @@ class KeyguardUnlockAnimationController @Inject constructor(
*/
@JvmDefault
fun onUnlockAnimationFinished() {}
-
- /**
- * Called when we begin the smartspace shared element transition, either due to an unlock
- * action (biometric, etc.) or a swipe to unlock.
- *
- * This transition can begin BEFORE [onUnlockAnimationStarted] is called, if we are swiping
- * to unlock and the surface behind the keyguard has not yet been made visible. This is
- * because the lockscreen smartspace immediately begins moving towards the launcher
- * smartspace location when a swipe begins, even before we start the keyguard exit remote
- * animation and show the launcher itself.
- */
- @JvmDefault
- fun onSmartspaceSharedElementTransitionStarted() {}
}
/** The SmartSpace view on the lockscreen, provided by [KeyguardClockSwitchController]. */
@@ -259,8 +254,9 @@ class KeyguardUnlockAnimationController @Inject constructor(
* animation plays.
*/
private var surfaceBehindAlpha = 1f
- private var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
- private var smartspaceAnimator = ValueAnimator.ofFloat(0f, 1f)
+
+ @VisibleForTesting
+ var surfaceBehindAlphaAnimator = ValueAnimator.ofFloat(0f, 1f)
/**
* Matrix applied to [surfaceBehindRemoteAnimationTarget], which is the surface of the
@@ -281,59 +277,38 @@ class KeyguardUnlockAnimationController @Inject constructor(
private var roundedCornerRadius = 0f
/**
- * Whether we tried to start the SmartSpace shared element transition for this unlock swipe.
- * It's possible we were unable to do so (if the Launcher SmartSpace is not available), and we
- * need to keep track of that so that we don't start doing it halfway through the swipe if
- * Launcher becomes available suddenly.
- */
- private var attemptedSmartSpaceTransitionForThisSwipe = false
-
- /**
- * The original location of the lockscreen smartspace on the screen.
- */
- private val smartspaceOriginBounds = Rect()
-
- /**
- * The bounds to which the lockscreen smartspace is moving. This is set to the bounds of the
- * launcher's smartspace prior to the transition starting.
- */
- private val smartspaceDestBounds = Rect()
-
- /**
- * From 0f to 1f, the progress of the smartspace shared element animation. 0f means the
- * smartspace is at its normal position within the lock screen hierarchy, and 1f means it has
- * fully animated to the location of the Launcher's smartspace.
+ * Whether we decided in [prepareForInWindowLauncherAnimations] that we are able to and want to
+ * play the in-window launcher unlock animations rather than simply animating the Launcher
+ * window like any other app. This can be true while [willUnlockWithSmartspaceTransition] is
+ * false, if the smartspace is not available or was not ready in time.
*/
- private var smartspaceUnlockProgress = 0f
+ private var willUnlockWithInWindowLauncherAnimations: Boolean = false
/**
- * Whether we're currently unlocking, and we're talking to Launcher to perform in-window
- * animations rather than simply animating the Launcher window like any other app. This can be
- * true while [unlockingWithSmartspaceTransition] is false, if the smartspace is not available
- * or was not ready in time.
+ * Whether we decided in [prepareForInWindowLauncherAnimations] that we are able to and want to
+ * play the smartspace shared element animation. If true,
+ * [willUnlockWithInWindowLauncherAnimations] will also always be true since in-window
+ * animations are a prerequisite for the smartspace transition.
*/
- private var unlockingToLauncherWithInWindowAnimations: Boolean = false
-
- /**
- * Whether we are currently unlocking, and the smartspace shared element transition is in
- * progress. If true, we're also [unlockingToLauncherWithInWindowAnimations].
- */
- private var unlockingWithSmartspaceTransition: Boolean = false
+ private var willUnlockWithSmartspaceTransition: Boolean = false
private val handler = Handler()
init {
with(surfaceBehindAlphaAnimator) {
duration = SURFACE_BEHIND_SWIPE_FADE_DURATION_MS
- interpolator = Interpolators.TOUCH_RESPONSE
+ interpolator = Interpolators.LINEAR
addUpdateListener { valueAnimator: ValueAnimator ->
surfaceBehindAlpha = valueAnimator.animatedValue as Float
updateSurfaceBehindAppearAmount()
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
- // If the surface alpha is 0f, it's no longer visible so we can safely be done
- // with the animation even if other properties are still animating.
+ // If we animated the surface alpha to 0f, it means we cancelled a swipe to
+ // dismiss. In this case, we should ask the KeyguardViewMediator to end the
+ // remote animation to hide the surface behind the keyguard, but should *not*
+ // call onKeyguardExitRemoteAnimationFinished since that will hide the keyguard
+ // and unlock the device as well as hiding the surface.
if (surfaceBehindAlpha == 0f) {
keyguardViewMediator.get().finishSurfaceBehindRemoteAnimation(
false /* cancelled */)
@@ -360,21 +335,6 @@ class KeyguardUnlockAnimationController @Inject constructor(
})
}
- with(smartspaceAnimator) {
- duration = UNLOCK_ANIMATION_DURATION_MS
- interpolator = Interpolators.TOUCH_RESPONSE
- addUpdateListener {
- smartspaceUnlockProgress = it.animatedValue as Float
- }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- launcherUnlockController?.setSmartspaceVisibility(View.VISIBLE)
- keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
- false /* cancelled */)
- }
- })
- }
-
// Listen for changes in the dismiss amount.
keyguardStateController.addCallback(this)
@@ -394,6 +354,74 @@ class KeyguardUnlockAnimationController @Inject constructor(
}
/**
+ * Whether we should be able to do the in-window launcher animations given the current state of
+ * the device.
+ */
+ fun canPerformInWindowLauncherAnimations(): Boolean {
+ return isNexusLauncherUnderneath() &&
+ launcherUnlockController != null &&
+ !keyguardStateController.isDismissingFromSwipe &&
+ // Temporarily disable for foldables since foldable launcher has two first pages,
+ // which breaks the in-window animation.
+ !isFoldable(context)
+ }
+
+ /**
+ * Called from [KeyguardStateController] to let us know that the keyguard going away state has
+ * changed.
+ */
+ override fun onKeyguardGoingAwayChanged() {
+ if (keyguardStateController.isKeyguardGoingAway) {
+ prepareForInWindowLauncherAnimations()
+ }
+ }
+
+ /**
+ * Prepare for in-window Launcher unlock animations, if we're able to do so.
+ *
+ * The in-window animations consist of the staggered ring icon unlock animation, and optionally
+ * the shared element smartspace transition.
+ */
+ fun prepareForInWindowLauncherAnimations() {
+ willUnlockWithInWindowLauncherAnimations = canPerformInWindowLauncherAnimations()
+
+ if (!willUnlockWithInWindowLauncherAnimations) {
+ return
+ }
+
+ // There are additional conditions under which we should not perform the smartspace
+ // transition specifically, so check those.
+ willUnlockWithSmartspaceTransition = shouldPerformSmartspaceTransition()
+
+ var lockscreenSmartspaceBounds = Rect()
+
+ // Grab the bounds of our lockscreen smartspace and send them to launcher so they can
+ // position their smartspace there initially, then animate it to its resting position.
+ if (willUnlockWithSmartspaceTransition) {
+ lockscreenSmartspaceBounds = Rect().apply {
+ lockscreenSmartspace!!.getBoundsOnScreen(this)
+ offset(lockscreenSmartspace!!.paddingLeft, lockscreenSmartspace!!.paddingTop)
+ }
+ }
+
+ // Currently selected lockscreen smartspace page, or -1 if it's not available.
+ val selectedPage =
+ (lockscreenSmartspace as BcSmartspaceDataPlugin.SmartspaceView?)?.selectedPage ?: -1
+
+ try {
+
+ // Let the launcher know to prepare for this animation.
+ launcherUnlockController?.prepareForUnlock(
+ willUnlockWithSmartspaceTransition, /* willAnimateSmartspace */
+ lockscreenSmartspaceBounds, /* lockscreenSmartspaceBounds */
+ selectedPage, /* selectedPage */
+ )
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Remote exception in prepareForInWindowUnlockAnimations.", e)
+ }
+ }
+
+ /**
* Called from [KeyguardViewMediator] to tell us that the RemoteAnimation on the surface behind
* the keyguard has started successfully. We can use these parameters to directly manipulate the
* surface for the unlock gesture/animation.
@@ -404,7 +432,8 @@ class KeyguardUnlockAnimationController @Inject constructor(
*
* [requestedShowSurfaceBehindKeyguard] indicates whether the animation started because of a
* call to [KeyguardViewMediator.showSurfaceBehindKeyguard], as happens during a swipe gesture,
- * as opposed to being called because the device was unlocked and the keyguard is going away.
+ * as opposed to being called because the device was unlocked instantly by some other means
+ * (fingerprint, tap, etc.) and the keyguard is going away.
*/
fun notifyStartSurfaceBehindRemoteAnimation(
target: RemoteAnimationTarget,
@@ -422,19 +451,31 @@ class KeyguardUnlockAnimationController @Inject constructor(
surfaceBehindRemoteAnimationTarget = target
surfaceBehindRemoteAnimationStartTime = startTime
- // If we specifically requested that the surface behind be made visible, it means we are
- // swiping to unlock. In that case, the surface visibility is tied to the dismiss amount,
- // and we'll handle that in onKeyguardDismissAmountChanged(). If we didn't request that, the
- // keyguard is being dismissed for a different reason (biometric auth, etc.) and we should
- // play a canned animation to make the surface fully visible.
- if (!requestedShowSurfaceBehindKeyguard) {
+ // If we specifically requested that the surface behind be made visible (vs. it being made
+ // visible because we're unlocking), then we're in the middle of a swipe-to-unlock touch
+ // gesture and the surface behind the keyguard should be made visible.
+ if (requestedShowSurfaceBehindKeyguard) {
+ // Fade in the surface, as long as we're not now flinging. The touch gesture ending in
+ // a fling during the time it takes the keyguard exit animation to start is an edge
+ // case race condition, and we'll handle it by playing a canned animation on the
+ // now-visible surface to finish unlocking.
+ if (!keyguardStateController.isFlingingToDismissKeyguard) {
+ fadeInSurfaceBehind()
+ } else {
+ playCannedUnlockAnimation()
+ }
+ } else {
+ // The surface was made visible since we're unlocking not from a swipe (fingerprint,
+ // lock icon long-press, etc). Play the full unlock animation.
playCannedUnlockAnimation()
}
listeners.forEach {
it.onUnlockAnimationStarted(
playingCannedUnlockAnimation /* playingCannedAnimation */,
- biometricUnlockControllerLazy.get().isWakeAndUnlock /* isWakeAndUnlock */) }
+ biometricUnlockControllerLazy.get().isWakeAndUnlock /* isWakeAndUnlock */,
+ CANNED_UNLOCK_START_DELAY /* unlockStartDelay */,
+ LAUNCHER_ICONS_ANIMATION_DURATION_MS /* unlockAnimationDuration */) }
// Finish the keyguard remote animation if the dismiss amount has crossed the threshold.
// Check it here in case there is no more change to the dismiss amount after the last change
@@ -443,57 +484,32 @@ class KeyguardUnlockAnimationController @Inject constructor(
}
/**
- * Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and
- * we should clean up all of our state.
- */
- fun notifyFinishedKeyguardExitAnimation(cancelled: Boolean) {
- // Cancel any pending actions.
- handler.removeCallbacksAndMessages(null)
-
- // Make sure we made the surface behind fully visible, just in case. It should already be
- // fully visible.
- setSurfaceBehindAppearAmount(1f)
- launcherUnlockController?.setUnlockAmount(1f)
- smartspaceDestBounds.setEmpty()
-
- // That target is no longer valid since the animation finished, null it out.
- surfaceBehindRemoteAnimationTarget = null
- surfaceBehindParams = null
-
- playingCannedUnlockAnimation = false
- unlockingToLauncherWithInWindowAnimations = false
- unlockingWithSmartspaceTransition = false
- resetSmartspaceTransition()
-
- listeners.forEach { it.onUnlockAnimationFinished() }
- }
-
- /**
* Play a canned unlock animation to unlock the device. This is used when we were *not* swiping
* to unlock using a touch gesture. If we were swiping to unlock, the animation will be driven
* by the dismiss amount via [onKeyguardDismissAmountChanged].
*/
- fun playCannedUnlockAnimation() {
+ private fun playCannedUnlockAnimation() {
playingCannedUnlockAnimation = true
- if (canPerformInWindowLauncherAnimations()) {
- // If possible, use the neat in-window animations to unlock to the launcher.
- unlockToLauncherWithInWindowAnimations()
- } else if (!biometricUnlockControllerLazy.get().isWakeAndUnlock) {
- // If the launcher isn't behind the keyguard, or the launcher unlock controller is not
- // available, animate in the entire window.
- surfaceBehindEntryAnimator.start()
- } else {
- setSurfaceBehindAppearAmount(1f)
- keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(false)
- }
- // If this is a wake and unlock, hide the lockscreen immediately. In the future, we should
- // animate it out nicely instead, but to the current state of wake and unlock, not hiding it
- // causes a lot of issues.
- // TODO(b/210016643): Not this, it looks not-ideal!
- if (biometricUnlockControllerLazy.get().isWakeAndUnlock) {
- keyguardViewController.hide(surfaceBehindRemoteAnimationStartTime, 350)
+ when {
+ // If we're set up for in-window launcher animations, ask Launcher to play its in-window
+ // canned animation.
+ willUnlockWithInWindowLauncherAnimations -> unlockToLauncherWithInWindowAnimations()
+
+ // If we're waking and unlocking to a non-Launcher app surface (or Launcher in-window
+ // animations are not available), show it immediately and end the remote animation. The
+ // circular light reveal will show the app surface, and it looks weird if it's moving
+ // around behind that.
+ biometricUnlockControllerLazy.get().isWakeAndUnlock -> {
+ setSurfaceBehindAppearAmount(1f)
+ keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
+ false /* cancelled */)
+ }
+
+ // Otherwise, we're doing a normal full-window unlock. Start this animator, which will
+ // scale/translate the window underneath the lockscreen.
+ else -> surfaceBehindEntryAnimator.start()
}
}
@@ -502,205 +518,31 @@ class KeyguardUnlockAnimationController @Inject constructor(
* transition if possible.
*/
private fun unlockToLauncherWithInWindowAnimations() {
- // See if we can do the smartspace transition, and if so, do it!
- if (prepareForSmartspaceTransition()) {
- animateSmartspaceToDestination()
- listeners.forEach { it.onSmartspaceSharedElementTransitionStarted() }
- }
-
- val startDelay = Settings.Secure.getLong(
- context.contentResolver, "unlock_start_delay", CANNED_UNLOCK_START_DELAY)
- val duration = Settings.Secure.getLong(
- context.contentResolver, "unlock_duration", LAUNCHER_ICONS_ANIMATION_DURATION_MS)
-
- unlockingToLauncherWithInWindowAnimations = true
- prepareLauncherWorkspaceForUnlockAnimation()
+ setSurfaceBehindAppearAmount(1f)
// Begin the animation, waiting for the shade to animate out.
launcherUnlockController?.playUnlockAnimation(
true /* unlocked */,
- duration /* duration */,
- startDelay /* startDelay */)
-
- handler.postDelayed({
- applyParamsToSurface(
- SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
- surfaceBehindRemoteAnimationTarget!!.leash)
- .withAlpha(1f)
- .build())
- }, startDelay)
-
- if (!unlockingWithSmartspaceTransition) {
- // If we are not unlocking with the smartspace transition, wait for the unlock animation
- // to end and then finish the remote animation. If we are using the smartspace
- // transition, it will finish the remote animation once it ends.
- handler.postDelayed({
- keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
- false /* cancelled */)
- }, UNLOCK_ANIMATION_DURATION_MS)
- }
- }
-
- /**
- * Asks Launcher to prepare the workspace to be unlocked. This sets up the animation and makes
- * the page invisible.
- */
- private fun prepareLauncherWorkspaceForUnlockAnimation() {
- // Tell the launcher to prepare for the animation by setting its views invisible and
- // syncing the selected smartspace pages.
- launcherUnlockController?.prepareForUnlock(
- unlockingWithSmartspaceTransition /* willAnimateSmartspace */,
- (lockscreenSmartspace as BcSmartspaceDataPlugin.SmartspaceView?)?.selectedPage ?: -1)
- }
-
- /**
- * Animates the lockscreen smartspace all the way to the launcher's smartspace location, then
- * makes the launcher smartspace visible and ends the remote animation.
- */
- private fun animateSmartspaceToDestination() {
- smartspaceAnimator.start()
- }
-
- /**
- * Reset the lockscreen smartspace's position, and reset all state involving the smartspace
- * transition.
- */
- public fun resetSmartspaceTransition() {
- unlockingWithSmartspaceTransition = false
- smartspaceUnlockProgress = 0f
-
- lockscreenSmartspace?.post {
- lockscreenSmartspace!!.translationX = 0f
- lockscreenSmartspace!!.translationY = 0f
- }
- }
-
- /**
- * Moves the lockscreen smartspace towards the launcher smartspace's position.
- */
- private fun setSmartspaceProgressToDestinationBounds(progress: Float) {
- if (smartspaceDestBounds.isEmpty) {
- return
- }
-
- val progressClamped = min(1f, progress)
-
- // Calculate the distance (relative to the origin) that we need to be for the current
- // progress value.
- val progressX =
- (smartspaceDestBounds.left - smartspaceOriginBounds.left) * progressClamped
- val progressY =
- (smartspaceDestBounds.top - smartspaceOriginBounds.top) * progressClamped
-
- val lockscreenSmartspaceCurrentBounds = Rect().also {
- lockscreenSmartspace!!.getBoundsOnScreen(it)
- }
-
- // Figure out how far that is from our present location on the screen. This approach
- // compensates for the fact that our parent container is also translating to animate out.
- val dx = smartspaceOriginBounds.left + progressX -
- lockscreenSmartspaceCurrentBounds.left
- val dy = smartspaceOriginBounds.top + progressY -
- lockscreenSmartspaceCurrentBounds.top
-
- with(lockscreenSmartspace!!) {
- translationX += dx
- translationY += dy
- }
- }
-
- /**
- * Update the lockscreen SmartSpace to be positioned according to the current dismiss amount. As
- * the dismiss amount increases, we will increase our SmartSpace's progress to the destination
- * bounds (the location of the Launcher SmartSpace).
- *
- * This is used by [KeyguardClockSwitchController] to keep the smartspace position updated as
- * the clock is swiped away.
- */
- fun updateLockscreenSmartSpacePosition() {
- setSmartspaceProgressToDestinationBounds(smartspaceUnlockProgress)
- }
-
- /**
- * Asks the keyguard view to hide, using the start time from the beginning of the remote
- * animation.
- */
- fun hideKeyguardViewAfterRemoteAnimation() {
- if (keyguardViewController.isShowing) {
- // Hide the keyguard, with no fade out since we animated it away during the unlock.
- keyguardViewController.hide(
- surfaceBehindRemoteAnimationStartTime,
- 0 /* fadeOutDuration */
- )
- } else {
- Log.e(TAG, "#hideKeyguardViewAfterRemoteAnimation called when keyguard view is not " +
- "showing. Ignoring...")
- }
- }
+ LAUNCHER_ICONS_ANIMATION_DURATION_MS /* duration */,
+ CANNED_UNLOCK_START_DELAY /* startDelay */)
- private fun applyParamsToSurface(params: SyncRtSurfaceTransactionApplier.SurfaceParams) {
- surfaceTransactionApplier!!.scheduleApply(params)
- surfaceBehindParams = params
- }
+ // Now that the Launcher surface (with its smartspace positioned identically to ours) is
+ // visible, hide our smartspace.
+ lockscreenSmartspace!!.visibility = View.INVISIBLE
- /**
- * Scales in and translates up the surface behind the keyguard. This is used during unlock
- * animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
- * cancelled).
- */
- fun setSurfaceBehindAppearAmount(amount: Float) {
- if (surfaceBehindRemoteAnimationTarget == null) {
- return
- }
-
- if (unlockingToLauncherWithInWindowAnimations) {
- // If we aren't using the canned unlock animation (which would be setting the unlock
- // amount in its update listener), do it here.
- if (!isPlayingCannedUnlockAnimation()) {
- launcherUnlockController?.setUnlockAmount(amount)
-
- if (surfaceBehindParams?.alpha?.let { it < 1f } != false) {
- applyParamsToSurface(
- SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
- surfaceBehindRemoteAnimationTarget!!.leash)
- .withAlpha(1f)
- .build())
- }
+ // As soon as the shade has animated out of the way, finish the keyguard exit animation. The
+ // in-window animations in the Launcher window will end on their own.
+ handler.postDelayed({
+ if (keyguardViewMediator.get().isShowingAndNotOccluded &&
+ !keyguardStateController.isKeyguardGoingAway) {
+ Log.e(TAG, "Finish keyguard exit animation delayed Runnable ran, but we are " +
+ "showing and not going away.")
+ return@postDelayed
}
- } else {
- // Otherwise, animate in the surface's scale/transltion.
- val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.height()
- val scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR +
- (1f - SURFACE_BEHIND_START_SCALE_FACTOR) *
- MathUtils.clamp(amount, 0f, 1f))
-
- // Scale up from a point at the center-bottom of the surface.
- surfaceBehindMatrix.setScale(
- scaleFactor,
- scaleFactor,
- surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.width() / 2f,
- surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y
- )
- // Translate up from the bottom.
- surfaceBehindMatrix.postTranslate(
- 0f,
- surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount)
- )
-
- // If we're snapping the keyguard back, immediately begin fading it out.
- val animationAlpha =
- if (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount
- else surfaceBehindAlpha
-
- applyParamsToSurface(
- SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
- surfaceBehindRemoteAnimationTarget!!.leash)
- .withMatrix(surfaceBehindMatrix)
- .withCornerRadius(roundedCornerRadius)
- .withAlpha(animationAlpha)
- .build())
- }
+ keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished(
+ false /* cancelled */)
+ }, CANNED_UNLOCK_START_DELAY)
}
/**
@@ -738,7 +580,7 @@ class KeyguardUnlockAnimationController @Inject constructor(
return
}
- if (keyguardViewController.isShowing) {
+ if (keyguardViewController.isShowing && !playingCannedUnlockAnimation) {
showOrHideSurfaceIfDismissAmountThresholdsReached()
// If the surface is visible or it's about to be, start updating its appearance to
@@ -750,11 +592,6 @@ class KeyguardUnlockAnimationController @Inject constructor(
updateSurfaceBehindAppearAmount()
}
}
-
- // The end of the SmartSpace transition can occur after the keyguard is hidden (when we tell
- // Launcher's SmartSpace to become visible again), so update it even if the keyguard view is
- // no longer showing.
- applyDismissAmountToSmartspaceTransition()
}
/**
@@ -775,18 +612,16 @@ class KeyguardUnlockAnimationController @Inject constructor(
return
}
+ if (!keyguardStateController.isShowing) {
+ return
+ }
+
val dismissAmount = keyguardStateController.dismissAmount
+
if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
- !keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
- // We passed the threshold, and we're not yet showing the surface behind the
- // keyguard. Animate it in.
- if (!unlockingToLauncherWithInWindowAnimations &&
- canPerformInWindowLauncherAnimations()) {
- unlockingToLauncherWithInWindowAnimations = true
- prepareLauncherWorkspaceForUnlockAnimation()
- }
+ !keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
+
keyguardViewMediator.get().showSurfaceBehindKeyguard()
- fadeInSurfaceBehind()
} else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
// We're no longer past the threshold but we are showing the surface. Animate it
@@ -828,60 +663,103 @@ class KeyguardUnlockAnimationController @Inject constructor(
}
/**
- * Updates flags related to the SmartSpace transition in response to a change in keyguard
- * dismiss amount, and also updates the SmartSpaceTransitionController, which will let Launcher
- * know if it needs to do something as a result.
+ * Scales in and translates up the surface behind the keyguard. This is used during unlock
+ * animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
+ * cancelled).
*/
- private fun applyDismissAmountToSmartspaceTransition() {
- if (!featureFlags.isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED)) {
+ fun setSurfaceBehindAppearAmount(amount: Float) {
+ if (surfaceBehindRemoteAnimationTarget == null) {
return
}
- // If we are playing the canned animation, the smartspace is being animated directly between
- // its original location and the location of the launcher smartspace by smartspaceAnimator.
- // We can ignore the dismiss amount, which is caused by panel height changes as the panel is
- // flung away.
- if (playingCannedUnlockAnimation) {
- return
- }
+ // Otherwise, animate in the surface's scale/transltion.
+ val surfaceHeight: Int = surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.height()
+ val scaleFactor = (SURFACE_BEHIND_START_SCALE_FACTOR +
+ (1f - SURFACE_BEHIND_START_SCALE_FACTOR) *
+ MathUtils.clamp(amount, 0f, 1f))
+
+ // Scale up from a point at the center-bottom of the surface.
+ surfaceBehindMatrix.setScale(
+ scaleFactor,
+ scaleFactor,
+ surfaceBehindRemoteAnimationTarget!!.screenSpaceBounds.width() / 2f,
+ surfaceHeight * SURFACE_BEHIND_SCALE_PIVOT_Y
+ )
+
+ // Translate up from the bottom.
+ surfaceBehindMatrix.postTranslate(
+ 0f,
+ surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount)
+ )
+
+ // If we're snapping the keyguard back, immediately begin fading it out.
+ val animationAlpha =
+ if (keyguardStateController.isSnappingKeyguardBackAfterSwipe) amount
+ else surfaceBehindAlpha
+
+ applyParamsToSurface(
+ SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(
+ surfaceBehindRemoteAnimationTarget!!.leash)
+ .withMatrix(surfaceBehindMatrix)
+ .withCornerRadius(roundedCornerRadius)
+ .withAlpha(animationAlpha)
+ .build())
+ }
- val dismissAmount = keyguardStateController.dismissAmount
+ /**
+ * Called by [KeyguardViewMediator] to let us know that the remote animation has finished, and
+ * we should clean up all of our state.
+ *
+ * This is generally triggered by us, calling
+ * [KeyguardViewMediator.finishSurfaceBehindRemoteAnimation].
+ */
+ fun notifyFinishedKeyguardExitAnimation(cancelled: Boolean) {
+ // Cancel any pending actions.
+ handler.removeCallbacksAndMessages(null)
- // If we've begun a swipe, and haven't yet tried doing the SmartSpace transition, do that
- // now.
- if (!attemptedSmartSpaceTransitionForThisSwipe &&
- keyguardViewController.isShowing &&
- dismissAmount > 0f &&
- dismissAmount < 1f) {
- attemptedSmartSpaceTransitionForThisSwipe = true
+ // Make sure we made the surface behind fully visible, just in case. It should already be
+ // fully visible. If the launcher is doing its own animation, let it continue without
+ // forcing it to 1f.
+ setSurfaceBehindAppearAmount(1f)
+ launcherUnlockController?.setUnlockAmount(1f, false /* forceIfAnimating */)
- if (prepareForSmartspaceTransition()) {
- unlockingWithSmartspaceTransition = true
+ // That target is no longer valid since the animation finished, null it out.
+ surfaceBehindRemoteAnimationTarget = null
+ surfaceBehindParams = null
- // Ensure that the smartspace is invisible if we're doing the transition, and
- // visible if we aren't.
- launcherUnlockController?.setSmartspaceVisibility(
- if (unlockingWithSmartspaceTransition) View.INVISIBLE else View.VISIBLE)
+ playingCannedUnlockAnimation = false
+ willUnlockWithInWindowLauncherAnimations = false
+ willUnlockWithSmartspaceTransition = false
- if (unlockingWithSmartspaceTransition) {
- listeners.forEach { it.onSmartspaceSharedElementTransitionStarted() }
- }
- }
- } else if (attemptedSmartSpaceTransitionForThisSwipe &&
- (dismissAmount == 0f || dismissAmount == 1f)) {
- attemptedSmartSpaceTransitionForThisSwipe = false
- unlockingWithSmartspaceTransition = false
- launcherUnlockController?.setSmartspaceVisibility(View.VISIBLE)
- }
+ // The lockscreen surface is gone, so it is now safe to re-show the smartspace.
+ lockscreenSmartspace?.visibility = View.VISIBLE
+
+ listeners.forEach { it.onUnlockAnimationFinished() }
+ }
+
+ /**
+ * Asks the keyguard view to hide, using the start time from the beginning of the remote
+ * animation.
+ */
+ fun hideKeyguardViewAfterRemoteAnimation() {
+ if (keyguardViewController.isShowing) {
+ // Hide the keyguard, with no fade out since we animated it away during the unlock.
- if (unlockingWithSmartspaceTransition) {
- val swipedFraction: Float = keyguardStateController.dismissAmount
- val progress = swipedFraction / DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD
- smartspaceUnlockProgress = progress
- setSmartspaceProgressToDestinationBounds(smartspaceUnlockProgress)
+ keyguardViewController.hide(
+ surfaceBehindRemoteAnimationStartTime,
+ 0 /* fadeOutDuration */
+ )
+ } else {
+ Log.e(TAG, "#hideKeyguardViewAfterRemoteAnimation called when keyguard view is not " +
+ "showing. Ignoring...")
}
}
+ private fun applyParamsToSurface(params: SyncRtSurfaceTransactionApplier.SurfaceParams) {
+ surfaceTransactionApplier!!.scheduleApply(params)
+ surfaceBehindParams = params
+ }
+
private fun fadeInSurfaceBehind() {
surfaceBehindAlphaAnimator.cancel()
surfaceBehindAlphaAnimator.start()
@@ -892,14 +770,8 @@ class KeyguardUnlockAnimationController @Inject constructor(
surfaceBehindAlphaAnimator.reverse()
}
- /**
- * Prepare for the smartspace shared element transition, if possible, by figuring out where we
- * are animating from/to.
- *
- * Return true if we'll be able to do the smartspace transition, or false if conditions are not
- * right to do it right now.
- */
- private fun prepareForSmartspaceTransition(): Boolean {
+
+ private fun shouldPerformSmartspaceTransition(): Boolean {
// Feature is disabled, so we don't want to.
if (!featureFlags.isEnabled(Flags.SMARTSPACE_SHARED_ELEMENT_TRANSITION_ENABLED)) {
return false
@@ -940,45 +812,22 @@ class KeyguardUnlockAnimationController @Inject constructor(
return false
}
- unlockingWithSmartspaceTransition = true
- smartspaceDestBounds.setEmpty()
-
- // Assuming we were able to retrieve the launcher's state, start the lockscreen
- // smartspace at 0, 0, and save its starting bounds.
- with(lockscreenSmartspace!!) {
- translationX = 0f
- translationY = 0f
- getBoundsOnScreen(smartspaceOriginBounds)
- }
-
- // Set the destination bounds to the launcher smartspace's bounds, offset by any
- // padding on our smartspace.
- with(smartspaceDestBounds) {
- set(launcherSmartspaceState!!.boundsOnScreen)
- offset(-lockscreenSmartspace!!.paddingLeft, -lockscreenSmartspace!!.paddingTop)
+ // We started to swipe to dismiss, but now we're doing a fling animation to complete the
+ // dismiss. In this case, the smartspace swiped away with the rest of the keyguard, so don't
+ // do the shared element transition.
+ if (keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture) {
+ return false
}
return true
}
/**
- * Whether we should be able to do the in-window launcher animations given the current state of
- * the device.
- */
- fun canPerformInWindowLauncherAnimations(): Boolean {
- return isNexusLauncherUnderneath() &&
- launcherUnlockController != null &&
- // Temporarily disable for foldables since foldable launcher has two first pages,
- // which breaks the in-window animation.
- !isFoldable(context)
- }
-
- /**
* Whether we are currently in the process of unlocking the keyguard, and we are performing the
* shared element SmartSpace transition.
*/
fun isUnlockingWithSmartSpaceTransition(): Boolean {
- return unlockingWithSmartspaceTransition
+ return willUnlockWithSmartspaceTransition
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2e1373259975..10ea1e06c6d7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -17,6 +17,8 @@
package com.android.systemui.keyguard;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN;
@@ -119,7 +121,6 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -849,7 +850,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
@Override
public void onLaunchAnimationCancelled() {
- setOccluded(true /* occluded */, false /* animate */);
+ Log.d(TAG, "Occlude launch animation cancelled. "
+ + "Occluded state is now: " + mOccluded);
}
@NonNull
@@ -894,7 +896,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
};
private IRemoteAnimationRunner mOccludeAnimationRunner =
- new ActivityLaunchRemoteAnimationRunner(mOccludeAnimationController);
+ new OccludeActivityLaunchRemoteAnimationRunner(mOccludeAnimationController);
/**
* Animation controller for activities that unocclude the keyguard. This does not use the
@@ -919,13 +921,17 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
- final RemoteAnimationTarget primary = apps[0];
+ if (apps == null || apps.length == 0 || apps[0] == null) {
+ Log.d(TAG, "No apps provided to unocclude runner; "
+ + "skipping animation and unoccluding.");
- if (primary == null) {
finishedCallback.onAnimationFinished();
+ setOccluded(false /* isOccluded */, true /* animate */);
return;
}
+ final RemoteAnimationTarget primary = apps[0];
+
final SyncRtSurfaceTransactionApplier applier =
new SyncRtSurfaceTransactionApplier(
mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
@@ -965,6 +971,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
@Override
public void onAnimationEnd(Animator animation) {
try {
+ setOccluded(false /* isOccluded */, true /* animate */);
finishedCallback.onAnimationFinished();
mUnoccludeAnimator = null;
} catch (RemoteException e) {
@@ -2301,8 +2308,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
int flags = 0;
if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock()
|| mWakeAndUnlocking && !mWallpaperSupportsAmbientMode) {
- flags |= WindowManagerPolicyConstants
- .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
+ flags |= KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
}
if (mKeyguardViewControllerLazy.get().isGoingToNotificationShade()
|| mWakeAndUnlocking && mWallpaperSupportsAmbientMode) {
@@ -2318,6 +2324,15 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
.KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS;
}
+ // If we are unlocking to the launcher, clear the snapshot so that any changes as part
+ // of the in-window animations are reflected. This is needed even if we're not actually
+ // playing in-window animations for this particular unlock since a previous unlock might
+ // have changed the Launcher state.
+ if (mWakeAndUnlocking
+ && KeyguardUnlockAnimationController.Companion.isNexusLauncherUnderneath()) {
+ flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
+ }
+
mUpdateMonitor.setKeyguardGoingAway(true);
mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(true);
@@ -2622,9 +2637,18 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
mSurfaceBehindRemoteAnimationRequested = true;
try {
- ActivityTaskManager.getService().keyguardGoingAway(
- WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS
- | WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER);
+ int flags = KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS
+ | KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+
+ // If we are unlocking to the launcher, clear the snapshot so that any changes as part
+ // of the in-window animations are reflected. This is needed even if we're not actually
+ // playing in-window animations for this particular unlock since a previous unlock might
+ // have changed the Launcher state.
+ if (KeyguardUnlockAnimationController.Companion.isNexusLauncherUnderneath()) {
+ flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
+ }
+
+ ActivityTaskManager.getService().keyguardGoingAway(flags);
mKeyguardStateController.notifyKeyguardGoingAway(true);
} catch (RemoteException e) {
mSurfaceBehindRemoteAnimationRequested = false;
@@ -2654,7 +2678,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
}
/** If it's running, finishes the RemoteAnimation on the surface behind the keyguard. */
- public void finishSurfaceBehindRemoteAnimation(boolean cancelled) {
+ void finishSurfaceBehindRemoteAnimation(boolean cancelled) {
if (!mSurfaceBehindRemoteAnimationRunning) {
return;
}
@@ -2790,12 +2814,6 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
mWakeAndUnlocking = true;
- // We're going to animate in the Launcher, so ask WM to clear the task snapshot so we don't
- // initially display an old snapshot with all of the icons visible. We're System UI, so
- // we're allowed to pass in null to ask WM to find the home activity for us to prevent
- // needing to IPC to Launcher.
- ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(null /* homeActivity */);
-
keyguardDone();
Trace.endSection();
}
@@ -3125,4 +3143,36 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
mRunner.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback);
}
}
+
+ /**
+ * Subclass of {@link ActivityLaunchRemoteAnimationRunner} that calls {@link #setOccluded} when
+ * onAnimationStart is called.
+ */
+ private class OccludeActivityLaunchRemoteAnimationRunner
+ extends ActivityLaunchRemoteAnimationRunner {
+
+ OccludeActivityLaunchRemoteAnimationRunner(
+ ActivityLaunchAnimator.Controller controller) {
+ super(controller);
+ }
+
+ @Override
+ public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+ super.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback);
+
+ // This is the first signal we have from WM that we're going to be occluded. Set our
+ // internal state to reflect that immediately, vs. waiting for the launch animator to
+ // begin. Otherwise, calls to setShowingLocked, etc. will not know that we're about to
+ // be occluded and might re-show the keyguard.
+ setOccluded(true /* isOccluded */, false /* animate */);
+ }
+
+ @Override
+ public void onAnimationCancelled() throws RemoteException {
+ super.onAnimationCancelled();
+ Log.d(TAG, "Occlude launch animation cancelled. Occluded state is now: " + mOccluded);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
index 5a214d1cd5e0..a6b4f1d2a9d0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
@@ -21,24 +21,41 @@ import android.animation.ValueAnimator.AnimatorUpdateListener
import android.animation.ValueAnimator
import android.content.Context
import android.content.res.ColorStateList
+import android.graphics.drawable.GradientDrawable
import com.android.internal.R
import com.android.internal.annotations.VisibleForTesting
import com.android.settingslib.Utils
import com.android.systemui.monet.ColorScheme
+import com.android.systemui.util.getColorWithAlpha
/**
- * ColorTransition is responsible for managing the animation between two specific colors.
+ * A [ColorTransition] is an object that updates the colors of views each time [updateColorScheme]
+ * is triggered.
+ */
+interface ColorTransition {
+ fun updateColorScheme(scheme: ColorScheme?)
+}
+
+/** A generic implementation of [ColorTransition] so that we can define a factory method. */
+open class GenericColorTransition(
+ private val applyTheme: (ColorScheme?) -> Unit
+) : ColorTransition {
+ override fun updateColorScheme(scheme: ColorScheme?) = applyTheme(scheme)
+}
+
+/**
+ * A [ColorTransition] that animates between two specific colors.
* It uses a ValueAnimator to execute the animation and interpolate between the source color and
* the target color.
*
* Selection of the target color from the scheme, and application of the interpolated color
* are delegated to callbacks.
*/
-open class ColorTransition(
+open class AnimatingColorTransition(
private val defaultColor: Int,
private val extractColor: (ColorScheme) -> Int,
private val applyColor: (Int) -> Unit
-) : AnimatorUpdateListener {
+) : AnimatorUpdateListener, ColorTransition {
private val argbEvaluator = ArgbEvaluator()
private val valueAnimator = buildAnimator()
@@ -53,7 +70,7 @@ open class ColorTransition(
applyColor(currentColor)
}
- fun updateColorScheme(scheme: ColorScheme?) {
+ override fun updateColorScheme(scheme: ColorScheme?) {
val newTargetColor = if (scheme == null) defaultColor else extractColor(scheme)
if (newTargetColor != targetColor) {
sourceColor = currentColor
@@ -76,7 +93,9 @@ open class ColorTransition(
}
}
-typealias ColorTransitionFactory = (Int, (ColorScheme) -> Int, (Int) -> Unit) -> ColorTransition
+typealias AnimatingColorTransitionFactory =
+ (Int, (ColorScheme) -> Int, (Int) -> Unit) -> AnimatingColorTransition
+typealias GenericColorTransitionFactory = ((ColorScheme?) -> Unit) -> GenericColorTransition
/**
* ColorSchemeTransition constructs a ColorTransition for each color in the scheme
@@ -86,27 +105,26 @@ typealias ColorTransitionFactory = (Int, (ColorScheme) -> Int, (Int) -> Unit) ->
class ColorSchemeTransition internal constructor(
private val context: Context,
mediaViewHolder: MediaViewHolder,
- colorTransitionFactory: ColorTransitionFactory
+ animatingColorTransitionFactory: AnimatingColorTransitionFactory,
+ genericColorTransitionFactory: GenericColorTransitionFactory
) {
constructor(context: Context, mediaViewHolder: MediaViewHolder) :
- this(context, mediaViewHolder, ::ColorTransition)
+ this(context, mediaViewHolder, ::AnimatingColorTransition, ::GenericColorTransition)
val bgColor = context.getColor(com.android.systemui.R.color.material_dynamic_secondary95)
- val surfaceColor = colorTransitionFactory(
+ val surfaceColor = animatingColorTransitionFactory(
bgColor,
::surfaceFromScheme
) { surfaceColor ->
val colorList = ColorStateList.valueOf(surfaceColor)
mediaViewHolder.player.backgroundTintList = colorList
- mediaViewHolder.albumView.foregroundTintList = colorList
- mediaViewHolder.albumView.backgroundTintList = colorList
mediaViewHolder.seamlessIcon.imageTintList = colorList
mediaViewHolder.seamlessText.setTextColor(surfaceColor)
mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor)
}
- val accentPrimary = colorTransitionFactory(
+ val accentPrimary = animatingColorTransitionFactory(
loadDefaultColor(R.attr.textColorPrimary),
::accentPrimaryFromScheme
) { accentPrimary ->
@@ -116,7 +134,7 @@ class ColorSchemeTransition internal constructor(
mediaViewHolder.gutsViewHolder.setAccentPrimaryColor(accentPrimary)
}
- val textPrimary = colorTransitionFactory(
+ val textPrimary = animatingColorTransitionFactory(
loadDefaultColor(R.attr.textColorPrimary),
::textPrimaryFromScheme
) { textPrimary ->
@@ -132,28 +150,65 @@ class ColorSchemeTransition internal constructor(
mediaViewHolder.gutsViewHolder.setTextPrimaryColor(textPrimary)
}
- val textPrimaryInverse = colorTransitionFactory(
+ val textPrimaryInverse = animatingColorTransitionFactory(
loadDefaultColor(R.attr.textColorPrimaryInverse),
::textPrimaryInverseFromScheme
) { textPrimaryInverse ->
mediaViewHolder.actionPlayPause.imageTintList = ColorStateList.valueOf(textPrimaryInverse)
}
- val textSecondary = colorTransitionFactory(
+ val textSecondary = animatingColorTransitionFactory(
loadDefaultColor(R.attr.textColorSecondary),
::textSecondaryFromScheme
) { textSecondary -> mediaViewHolder.artistText.setTextColor(textSecondary) }
- val textTertiary = colorTransitionFactory(
+ val textTertiary = animatingColorTransitionFactory(
loadDefaultColor(R.attr.textColorTertiary),
::textTertiaryFromScheme
) { textTertiary ->
mediaViewHolder.seekBar.progressBackgroundTintList = ColorStateList.valueOf(textTertiary)
}
+ // Note: This background gradient currently doesn't animate between colors.
+ val backgroundGradient = genericColorTransitionFactory { scheme ->
+ val defaultTintColor = ColorStateList.valueOf(bgColor)
+ if (scheme == null) {
+ mediaViewHolder.albumView.foregroundTintList = defaultTintColor
+ mediaViewHolder.albumView.backgroundTintList = defaultTintColor
+ return@genericColorTransitionFactory
+ }
+
+ // If there's no album art, just hide the gradient so we show the solid background.
+ val showGradient = mediaViewHolder.albumView.drawable != null
+ val startColor = getColorWithAlpha(
+ backgroundStartFromScheme(scheme),
+ alpha = if (showGradient) .25f else 0f
+ )
+ val endColor = getColorWithAlpha(
+ backgroundEndFromScheme(scheme),
+ alpha = if (showGradient) .90f else 0f
+ )
+ val gradientColors = intArrayOf(startColor, endColor)
+
+ val foregroundGradient = mediaViewHolder.albumView.foreground?.mutate()
+ if (foregroundGradient is GradientDrawable) {
+ foregroundGradient.colors = gradientColors
+ }
+ val backgroundGradient = mediaViewHolder.albumView.background?.mutate()
+ if (backgroundGradient is GradientDrawable) {
+ backgroundGradient.colors = gradientColors
+ }
+ }
+
val colorTransitions = arrayOf(
- surfaceColor, accentPrimary, textPrimary,
- textPrimaryInverse, textSecondary, textTertiary)
+ surfaceColor,
+ accentPrimary,
+ textPrimary,
+ textPrimaryInverse,
+ textSecondary,
+ textTertiary,
+ backgroundGradient
+ )
private fun loadDefaultColor(id: Int): Int {
return Utils.getColorAttr(context, id).defaultColor
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaColorSchemes.kt b/packages/SystemUI/src/com/android/systemui/media/MediaColorSchemes.kt
index 97c6014c91bd..5e767b0458b9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaColorSchemes.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaColorSchemes.kt
@@ -35,3 +35,9 @@ internal fun textSecondaryFromScheme(scheme: ColorScheme) = scheme.neutral2[3] /
/** Returns the tertiary text color for media controls based on the scheme. */
internal fun textTertiaryFromScheme(scheme: ColorScheme) = scheme.neutral2[5] // N2-400
+
+/** Returns the color for the start of the background gradient based on the scheme. */
+internal fun backgroundStartFromScheme(scheme: ColorScheme) = scheme.accent2[8] // A2-700
+
+/** Returns the color for the end of the background gradient based on the scheme. */
+internal fun backgroundEndFromScheme(scheme: ColorScheme) = scheme.accent1[8] // A1-700
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index d2c35bd96d5a..d9ee8f3f06b4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -30,10 +30,12 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
+import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.graphics.drawable.TransitionDrawable;
@@ -159,6 +161,7 @@ public class MediaControlPanel {
private MetadataAnimationHandler mMetadataAnimationHandler;
private ColorSchemeTransition mColorSchemeTransition;
private Drawable mPrevArtwork = null;
+ private boolean mIsArtworkBound = false;
private int mArtworkBoundId = 0;
private int mArtworkNextBindRequestId = 0;
@@ -586,6 +589,9 @@ public class MediaControlPanel {
private void bindArtworkAndColors(MediaData data, boolean updateBackground) {
final int reqId = mArtworkNextBindRequestId++;
+ if (updateBackground) {
+ mIsArtworkBound = false;
+ }
// Capture width & height from views in foreground for artwork scaling in background
int width = mMediaViewHolder.getPlayer().getWidth();
@@ -597,15 +603,18 @@ public class MediaControlPanel {
// Album art
ColorScheme mutableColorScheme = null;
Drawable artwork;
+ boolean isArtworkBound;
Icon artworkIcon = data.getArtwork();
if (artworkIcon != null) {
WallpaperColors wallpaperColors = WallpaperColors
.fromBitmap(artworkIcon.getBitmap());
mutableColorScheme = new ColorScheme(wallpaperColors, true);
artwork = getScaledBackground(artworkIcon, width, height);
+ isArtworkBound = true;
} else {
// If there's no artwork, use colors from the app icon
- artwork = null;
+ artwork = new ColorDrawable(Color.TRANSPARENT);
+ isArtworkBound = false;
try {
Drawable icon = mContext.getPackageManager()
.getApplicationIcon(data.getPackageName());
@@ -625,16 +634,20 @@ public class MediaControlPanel {
ImageView albumView = mMediaViewHolder.getAlbumView();
albumView.setPadding(0, 0, 0, 0);
albumView.setClipToOutline(true);
- if (updateBackground) {
- if (mPrevArtwork == null || artwork == null) {
+ if (updateBackground || (!mIsArtworkBound && isArtworkBound)) {
+ if (mPrevArtwork == null) {
albumView.setImageDrawable(artwork);
} else {
+ // Since we throw away the last transition, this'll pop if you backgrounds
+ // are cycled too fast (or the correct background arrives very soon after
+ // the metadata changes).
TransitionDrawable transitionDrawable = new TransitionDrawable(
- new Drawable[] { mPrevArtwork, artwork });
+ new Drawable[]{mPrevArtwork, artwork});
albumView.setImageDrawable(transitionDrawable);
- transitionDrawable.startTransition(333);
+ transitionDrawable.startTransition(isArtworkBound ? 333 : 80);
}
mPrevArtwork = artwork;
+ mIsArtworkBound = isArtworkBound;
}
// Transition Colors to current color scheme
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index b2751cec5d9e..426b45a31550 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -261,6 +261,8 @@ class MediaDataManager(
// Set up links back into the pipeline for listeners that need to send events upstream.
mediaTimeoutListener.timeoutCallback = { key: String, timedOut: Boolean ->
setTimedOut(key, timedOut) }
+ mediaTimeoutListener.stateCallback = { key: String, state: PlaybackState ->
+ updateState(key, state) }
mediaResumeListener.setManager(this)
mediaDataFilter.mediaDataManager = this
@@ -502,6 +504,21 @@ class MediaDataManager(
}
}
+ /**
+ * Called when the player's [PlaybackState] has been updated with new actions and/or state
+ */
+ private fun updateState(key: String, state: PlaybackState) {
+ mediaEntries.get(key)?.let {
+ val actions = createActionsFromState(it.packageName,
+ mediaControllerFactory.create(it.token), UserHandle(it.userId))
+ val data = it.copy(
+ semanticActions = actions,
+ isPlaying = isPlayingState(state.state))
+ if (DEBUG) Log.d(TAG, "State updated outside of notification")
+ onMediaDataLoaded(key, key, data)
+ }
+ }
+
private fun removeEntry(key: String) {
mediaEntries.remove(key)?.let {
logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId)
@@ -673,11 +690,8 @@ class MediaDataManager(
// Otherwise, use the notification actions
var actionIcons: List<MediaAction> = emptyList()
var actionsToShowCollapsed: List<Int> = emptyList()
- var semanticActions: MediaButton? = null
- if (mediaFlags.areMediaSessionActionsEnabled(sbn.packageName, sbn.user) &&
- mediaController.playbackState != null) {
- semanticActions = createActionsFromState(sbn.packageName, mediaController)
- } else {
+ val semanticActions = createActionsFromState(sbn.packageName, mediaController, sbn.user)
+ if (semanticActions == null) {
val actions = createActionsFromNotification(sbn)
actionIcons = actions.first
actionsToShowCollapsed = actions.second
@@ -789,13 +803,17 @@ class MediaDataManager(
* @return a Pair consisting of a list of media actions, and a list of ints representing which
* of those actions should be shown in the compact player
*/
- private fun createActionsFromState(packageName: String, controller: MediaController):
- MediaButton? {
+ private fun createActionsFromState(
+ packageName: String,
+ controller: MediaController,
+ user: UserHandle
+ ): MediaButton? {
val state = controller.playbackState
- if (state == null) {
- return MediaButton()
+ if (state == null || !mediaFlags.areMediaSessionActionsEnabled(packageName, user)) {
+ return null
}
- // First, check for} standard actions
+
+ // First, check for standard actions
val playOrPause = if (isConnectingState(state.state)) {
// Spinner needs to be animating to render anything. Start it here.
val drawable = context.getDrawable(
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index 8c6710a6fd68..fc8d38d59d59 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -55,6 +55,13 @@ class MediaTimeoutListener @Inject constructor(
*/
lateinit var timeoutCallback: (String, Boolean) -> Unit
+ /**
+ * Callback representing that a media object [PlaybackState] has changed.
+ * @param key Media control unique identifier
+ * @param state The new [PlaybackState]
+ */
+ lateinit var stateCallback: (String, PlaybackState) -> Unit
+
override fun onMediaDataLoaded(
key: String,
oldKey: String?,
@@ -85,17 +92,17 @@ class MediaTimeoutListener @Inject constructor(
}
reusedListener?.let {
- val wasPlaying = it.playing ?: false
+ val wasPlaying = it.isPlaying()
logger.logUpdateListener(key, wasPlaying)
it.mediaData = data
it.key = key
mediaListeners[key] = it
- if (wasPlaying != it.playing) {
+ if (wasPlaying != it.isPlaying()) {
// If a player becomes active because of a migration, we'll need to broadcast
// its state. Doing it now would lead to reentrant callbacks, so let's wait
// until we're done.
mainExecutor.execute {
- if (mediaListeners[key]?.playing == true) {
+ if (mediaListeners[key]?.isPlaying() == true) {
logger.logDelayedUpdate(key)
timeoutCallback.invoke(key, false /* timedOut */)
}
@@ -121,7 +128,7 @@ class MediaTimeoutListener @Inject constructor(
) : MediaController.Callback() {
var timedOut = false
- var playing: Boolean? = null
+ var lastState: PlaybackState? = null
var resumption: Boolean? = null
var destroyed = false
@@ -145,6 +152,9 @@ class MediaTimeoutListener @Inject constructor(
private var mediaController: MediaController? = null
private var cancellation: Runnable? = null
+ fun Int.isPlaying() = isPlayingState(this)
+ fun isPlaying() = lastState?.state?.isPlaying() ?: false
+
init {
mediaData = data
}
@@ -175,16 +185,26 @@ class MediaTimeoutListener @Inject constructor(
private fun processState(state: PlaybackState?, dispatchEvents: Boolean) {
logger.logPlaybackState(key, state)
- val isPlaying = state != null && isPlayingState(state.state)
+ val playingStateSame = (state?.state?.isPlaying() == isPlaying())
+ val actionsSame = (lastState?.actions == state?.actions) &&
+ areCustomActionListsEqual(lastState?.customActions, state?.customActions)
val resumptionChanged = resumption != mediaData.resumption
- if (playing == isPlaying && playing != null && !resumptionChanged) {
+
+ lastState = state
+
+ if ((!actionsSame || !playingStateSame) && state != null && dispatchEvents) {
+ logger.logStateCallback(key)
+ stateCallback.invoke(key, state)
+ }
+
+ if (playingStateSame && !resumptionChanged) {
return
}
- playing = isPlaying
resumption = mediaData.resumption
- if (!isPlaying) {
- logger.logScheduleTimeout(key, isPlaying, resumption!!)
+ val playing = isPlaying()
+ if (!playing) {
+ logger.logScheduleTimeout(key, playing, resumption!!)
if (cancellation != null && !resumptionChanged) {
// if the media changed resume state, we'll need to adjust the timeout length
logger.logCancelIgnored(key)
@@ -220,4 +240,50 @@ class MediaTimeoutListener @Inject constructor(
cancellation = null
}
}
+
+ private fun areCustomActionListsEqual(
+ first: List<PlaybackState.CustomAction>?,
+ second: List<PlaybackState.CustomAction>?
+ ): Boolean {
+ // Same object, or both null
+ if (first === second) {
+ return true
+ }
+
+ // Only one null, or different number of actions
+ if ((first == null || second == null) || (first.size != second.size)) {
+ return false
+ }
+
+ // Compare individual actions
+ first.asSequence().zip(second.asSequence()).forEach { (firstAction, secondAction) ->
+ if (!areCustomActionsEqual(firstAction, secondAction)) {
+ return false
+ }
+ }
+ return true
+ }
+
+ private fun areCustomActionsEqual(
+ firstAction: PlaybackState.CustomAction,
+ secondAction: PlaybackState.CustomAction
+ ): Boolean {
+ if (firstAction.action != secondAction.action ||
+ firstAction.name != secondAction.name ||
+ firstAction.icon != secondAction.icon) {
+ return false
+ }
+
+ if ((firstAction.extras == null) != (secondAction.extras == null)) {
+ return false
+ }
+ if (firstAction.extras != null) {
+ firstAction.extras.keySet().forEach { key ->
+ if (firstAction.extras.get(key) != secondAction.extras.get(key)) {
+ return false
+ }
+ }
+ }
+ return true
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt
index a86515990fcb..d9c58c0d0d76 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt
@@ -102,6 +102,17 @@ class MediaTimeoutLogger @Inject constructor(
}
)
+ fun logStateCallback(key: String) = buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = key
+ },
+ {
+ "dispatching state update for $key"
+ }
+ )
+
fun logScheduleTimeout(key: String, playing: Boolean, resumption: Boolean) = buffer.log(
TAG,
LogLevel.DEBUG,
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index 9b3b3ce6109f..dd4f1d6c9015 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -59,11 +59,14 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
private ImageView mBroadcastCodeEye;
private Boolean mIsPasswordHide = true;
private ImageView mBroadcastCodeEdit;
- private Button mStopButton;
+ private AlertDialog mAlertDialog;
+ private TextView mBroadcastErrorMessage;
static final int METADATA_BROADCAST_NAME = 0;
static final int METADATA_BROADCAST_CODE = 1;
+ private static final int MAX_BROADCAST_INFO_UPDATE = 3;
+
MediaOutputBroadcastDialog(Context context, boolean aboveStatusbar,
BroadcastSender broadcastSender, MediaOutputController mediaOutputController) {
super(context, broadcastSender, mediaOutputController);
@@ -118,14 +121,18 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
return View.VISIBLE;
}
- // TODO(b/222674827): To get the information from BluetoothLeBroadcastMetadata(Broadcast code)
- // and BluetoothLeAudioContentMetadata(Program info) when start Broadcast is successful.
- private String getBroadcastMetaDataInfo(int metaData) {
- switch (metaData) {
+ @Override
+ public void onStopButtonClick() {
+ mMediaOutputController.stopBluetoothLeBroadcast();
+ dismiss();
+ }
+
+ private String getBroadcastMetadataInfo(int metadata) {
+ switch (metadata) {
case METADATA_BROADCAST_NAME:
- return "";
+ return mMediaOutputController.getBroadcastName();
case METADATA_BROADCAST_CODE:
- return "";
+ return mMediaOutputController.getBroadcastCode();
default:
return "";
}
@@ -164,13 +171,8 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
launchBroadcastUpdatedDialog(true, mBroadcastCode.getText().toString());
});
- mBroadcastName.setText(getBroadcastMetaDataInfo(METADATA_BROADCAST_NAME));
- mBroadcastCode.setText(getBroadcastMetaDataInfo(METADATA_BROADCAST_CODE));
-
- mStopButton = getDialogView().requireViewById(R.id.stop);
- mStopButton.setOnClickListener(v -> {
- stopBroadcast();
- });
+ mBroadcastName.setText(getBroadcastMetadataInfo(METADATA_BROADCAST_NAME));
+ mBroadcastCode.setText(getBroadcastMetadataInfo(METADATA_BROADCAST_CODE));
}
private void inflateBroadcastInfoArea() {
@@ -179,16 +181,16 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
}
private void setQrCodeView() {
- //get the MetaData, and convert to BT QR code format.
- String broadcastMetaData = getBroadcastMetaData();
- if (broadcastMetaData.isEmpty()) {
+ //get the Metadata, and convert to BT QR code format.
+ String broadcastMetadata = getBroadcastMetadata();
+ if (broadcastMetadata.isEmpty()) {
//TDOD(b/226708424) Error handling for unable to generate the QR code bitmap
return;
}
try {
final int qrcodeSize = getContext().getResources().getDimensionPixelSize(
R.dimen.media_output_qrcode_size);
- final Bitmap bmp = QrCodeGenerator.encodeQrCode(broadcastMetaData, qrcodeSize);
+ final Bitmap bmp = QrCodeGenerator.encodeQrCode(broadcastMetadata, qrcodeSize);
mBroadcastQrCodeView.setImageBitmap(bmp);
} catch (WriterException e) {
//TDOD(b/226708424) Error handling for unable to generate the QR code bitmap
@@ -203,50 +205,87 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog {
mIsPasswordHide = !mIsPasswordHide;
}
- private void launchBroadcastUpdatedDialog(boolean isPassword, String editString) {
+ private void launchBroadcastUpdatedDialog(boolean isBroadcastCode, String editString) {
final View layout = LayoutInflater.from(mContext).inflate(
R.layout.media_output_broadcast_update_dialog, null);
final EditText editText = layout.requireViewById(R.id.broadcast_edit_text);
editText.setText(editString);
- final AlertDialog alertDialog = new Builder(mContext)
- .setTitle(isPassword ? R.string.media_output_broadcast_code
+ mBroadcastErrorMessage = layout.requireViewById(R.id.broadcast_error_message);
+ mAlertDialog = new Builder(mContext)
+ .setTitle(isBroadcastCode ? R.string.media_output_broadcast_code
: R.string.media_output_broadcast_name)
.setView(layout)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.media_output_broadcast_dialog_save,
(d, w) -> {
- updateBroadcast(isPassword, editText.getText().toString());
+ updateBroadcastInfo(isBroadcastCode, editText.getText().toString());
})
.create();
- alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- SystemUIDialog.setShowForAllUsers(alertDialog, true);
- SystemUIDialog.registerDismissListener(alertDialog);
- alertDialog.show();
+ mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
+ SystemUIDialog.registerDismissListener(mAlertDialog);
+ mAlertDialog.show();
}
- /**
- * TODO(b/222674827): The method should be get the BluetoothLeBroadcastMetadata after
- * starting the Broadcast session successfully. Then we will follow the BT QR code format
- * that convert BluetoothLeBroadcastMetadata object to String format.
- */
- private String getBroadcastMetaData() {
- return "TEST";
+ private String getBroadcastMetadata() {
+ return mMediaOutputController.getBroadcastMetadata();
}
- /**
- * TODO(b/222676140): These method are about the LE Audio Broadcast API. The framework APIS
- * will be wrapped in SettingsLib. And the UI will be executed through it.
- */
- private void updateBroadcast(boolean isPassword, String updatedString) {
+ private void updateBroadcastInfo(boolean isBroadcastCode, String updatedString) {
+ Button positiveBtn = mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
+ if (positiveBtn != null) {
+ positiveBtn.setEnabled(false);
+ }
+ if (isBroadcastCode) {
+ handleBroadcastCodeUpdated(updatedString);
+ } else {
+ handleBroadcastNameUpdated(updatedString);
+ }
}
- /**
- * TODO(b/222676140): These method are about the LE Audio Broadcast API. The framework APIS
- * will be wrapped in SettingsLib. And the UI will be executed through it.
- */
- private void stopBroadcast() {
- dismiss();
+ private void handleBroadcastNameUpdated(String name) {
+ // TODO(b/230473995) Add the retry mechanism and error handling when update fails
+ String currentName = mMediaOutputController.getBroadcastName();
+ int retryCount = MAX_BROADCAST_INFO_UPDATE;
+ mMediaOutputController.setBroadcastName(name);
+ if (!mMediaOutputController.updateBluetoothLeBroadcast()) {
+ mMediaOutputController.setBroadcastName(currentName);
+ handleLeUpdateBroadcastFailed(retryCount);
+ }
+ }
+
+ private void handleBroadcastCodeUpdated(String newPassword) {
+ // TODO(b/230473995) Add the retry mechanism and error handling when update fails
+ String currentPassword = mMediaOutputController.getBroadcastCode();
+ int retryCount = MAX_BROADCAST_INFO_UPDATE;
+ if (!mMediaOutputController.stopBluetoothLeBroadcast()) {
+ mMediaOutputController.setBroadcastCode(currentPassword);
+ handleLeUpdateBroadcastFailed(retryCount);
+ return;
+ }
+
+ mMediaOutputController.setBroadcastCode(newPassword);
+ if (!mMediaOutputController.startBluetoothLeBroadcast()) {
+ mMediaOutputController.setBroadcastCode(currentPassword);
+ handleLeUpdateBroadcastFailed(retryCount);
+ return;
+ }
+
+ mAlertDialog.dismiss();
+ }
+
+ private void handleLeUpdateBroadcastFailed(int retryCount) {
+ final Button positiveBtn = mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
+ mBroadcastErrorMessage.setVisibility(View.VISIBLE);
+ if (retryCount < MAX_BROADCAST_INFO_UPDATE) {
+ if (positiveBtn != null) {
+ positiveBtn.setEnabled(true);
+ }
+ mBroadcastErrorMessage.setText(R.string.media_output_broadcast_update_error);
+ } else {
+ mBroadcastErrorMessage.setText(R.string.media_output_broadcast_last_update_error);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt
new file mode 100644
index 000000000000..31266b6dc8ec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.dialog
+
+import android.content.Context
+import android.media.session.MediaSessionManager
+import android.view.View
+import com.android.internal.logging.UiEventLogger
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.media.nearby.NearbyMediaDevicesManager
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
+import java.util.Optional
+import javax.inject.Inject
+
+/**
+ * Factory to create [MediaOutputBroadcastDialog] objects.
+ */
+class MediaOutputBroadcastDialogFactory @Inject constructor(
+ private val context: Context,
+ private val mediaSessionManager: MediaSessionManager,
+ private val lbm: LocalBluetoothManager?,
+ private val starter: ActivityStarter,
+ private val broadcastSender: BroadcastSender,
+ private val notifCollection: CommonNotifCollection,
+ private val uiEventLogger: UiEventLogger,
+ private val dialogLaunchAnimator: DialogLaunchAnimator,
+ private val nearbyMediaDevicesManagerOptional: Optional<NearbyMediaDevicesManager>
+) {
+ var mediaOutputBroadcastDialog: MediaOutputBroadcastDialog? = null
+
+ /** Creates a [MediaOutputBroadcastDialog] for the given package. */
+ fun create(packageName: String, aboveStatusBar: Boolean, view: View? = null) {
+ // Dismiss the previous dialog, if any.
+ mediaOutputBroadcastDialog?.dismiss()
+
+ val controller = MediaOutputController(context, packageName,
+ mediaSessionManager, lbm, starter, notifCollection,
+ dialogLaunchAnimator, nearbyMediaDevicesManagerOptional)
+ val dialog =
+ MediaOutputBroadcastDialog(context, aboveStatusBar, broadcastSender, controller)
+ mediaOutputBroadcastDialog = dialog
+
+ // Show the dialog.
+ if (view != null) {
+ dialogLaunchAnimator.showFromView(dialog, view)
+ } else {
+ dialog.show()
+ }
+ }
+
+ /** dismiss [MediaOutputBroadcastDialog] if exist. */
+ fun dismiss() {
+ mediaOutputBroadcastDialog?.dismiss()
+ mediaOutputBroadcastDialog = null
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 0fbec3baffa6..8723f4fd63bb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -63,7 +63,6 @@ import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.media.BluetoothMediaDevice;
import com.android.settingslib.media.InfoMediaManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
@@ -79,6 +78,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -678,6 +678,56 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
}
+ String getBroadcastName() {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (broadcast == null) {
+ Log.d(TAG, "getBroadcastName: LE Audio Broadcast is null");
+ return "";
+ }
+ return broadcast.getProgramInfo();
+ }
+
+ void setBroadcastName(String broadcastName) {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (broadcast == null) {
+ Log.d(TAG, "setBroadcastName: LE Audio Broadcast is null");
+ return;
+ }
+ broadcast.setProgramInfo(broadcastName);
+ }
+
+ String getBroadcastCode() {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (broadcast == null) {
+ Log.d(TAG, "getBroadcastCode: LE Audio Broadcast is null");
+ return "";
+ }
+ return new String(broadcast.getBroadcastCode(), StandardCharsets.UTF_8);
+ }
+
+ void setBroadcastCode(String broadcastCode) {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (broadcast == null) {
+ Log.d(TAG, "setBroadcastCode: LE Audio Broadcast is null");
+ return;
+ }
+ broadcast.setBroadcastCode(broadcastCode.getBytes(StandardCharsets.UTF_8));
+ }
+
+ String getBroadcastMetadata() {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (broadcast == null) {
+ Log.d(TAG, "getBroadcastMetadata: LE Audio Broadcast is null");
+ return "";
+ }
+ return broadcast.getLocalBluetoothLeBroadcastMetaData().convertToQrCodeString();
+ }
+
boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
final List<String> features = device.getFeatures();
return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)
@@ -723,6 +773,17 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback,
return true;
}
+ boolean updateBluetoothLeBroadcast() {
+ LocalBluetoothLeBroadcast broadcast =
+ mLocalBluetoothManager.getProfileManager().getLeAudioBroadcastProfile();
+ if (broadcast == null) {
+ Log.d(TAG, "The broadcast profile is null");
+ return false;
+ }
+ broadcast.updateBroadcast(getAppSourceName(), /*language*/ null);
+ return true;
+ }
+
void registerLeBroadcastServiceCallBack(
@NonNull @CallbackExecutor Executor executor,
@NonNull BluetoothLeBroadcast.Callback callback) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
index 7fb7d8b0eaa5..dd9d35bf2021 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
@@ -31,7 +31,8 @@ private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
* BroadcastReceiver for handling media output intent
*/
class MediaOutputDialogReceiver @Inject constructor(
- private val mediaOutputDialogFactory: MediaOutputDialogFactory
+ private val mediaOutputDialogFactory: MediaOutputDialogFactory,
+ private val mediaOutputBroadcastDialogFactory: MediaOutputBroadcastDialogFactory
) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (TextUtils.equals(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG,
@@ -43,6 +44,16 @@ class MediaOutputDialogReceiver @Inject constructor(
} else if (DEBUG) {
Log.e(TAG, "Unable to launch media output dialog. Package name is empty.")
}
+ } else if (TextUtils.equals(
+ MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG,
+ intent.action)) {
+ val packageName: String? =
+ intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME)
+ if (!TextUtils.isEmpty(packageName)) {
+ mediaOutputBroadcastDialogFactory.create(packageName!!, false)
+ } else if (DEBUG) {
+ Log.e(TAG, "Unable to launch media output broadcast dialog. Package name is empty.")
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
index fe4cb7182168..d4e164208167 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
@@ -67,7 +67,7 @@ class PrivacyDialog(
attributes.receiveInsetsIgnoringZOrder = true
setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL)
}
-
+ setTitle(R.string.ongoing_privacy_dialog_a11y_title)
setContentView(R.layout.privacy_dialog)
rootView = requireViewById<ViewGroup>(R.id.root)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 34f771ce0431..ce50ddff7b0f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -39,6 +39,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
private static final boolean DEBUG = false;
private static final String CURRENT_PAGE = "current_page";
+ private static final int NO_PAGE = -1;
private static final String TAG = "PagedTileLayout";
private static final int REVEAL_SCROLL_DURATION_MILLIS = 750;
@@ -109,13 +110,14 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
}
public void saveInstanceState(Bundle outState) {
- outState.putInt(CURRENT_PAGE, getCurrentItem());
+ int resolvedPage = mPageToRestore != NO_PAGE ? mPageToRestore : getCurrentPageNumber();
+ outState.putInt(CURRENT_PAGE, resolvedPage);
}
public void restoreInstanceState(Bundle savedInstanceState) {
// There's only 1 page at this point. We want to restore the correct page once the
// pages have been inflated
- mPageToRestore = savedInstanceState.getInt(CURRENT_PAGE, -1);
+ mPageToRestore = savedInstanceState.getInt(CURRENT_PAGE, NO_PAGE);
}
@Override
@@ -151,12 +153,15 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
+ // The configuration change will change the flag in the view (that's returned in
+ // isLayoutRtl). As we detect the change, we use the cached direction to store the page
+ // before setting it.
+ final int page = getPageNumberForDirection(mLayoutDirection == LAYOUT_DIRECTION_RTL);
super.onRtlPropertiesChanged(layoutDirection);
if (mLayoutDirection != layoutDirection) {
mLayoutDirection = layoutDirection;
setAdapter(mAdapter);
- setCurrentItem(0, false);
- mPageToRestore = 0;
+ setCurrentItem(page, false);
}
}
@@ -172,8 +177,12 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
* Obtains the current page number respecting RTL
*/
private int getCurrentPageNumber() {
+ return getPageNumberForDirection(isLayoutRtl());
+ }
+
+ private int getPageNumberForDirection(boolean isLayoutRTL) {
int page = getCurrentItem();
- if (mLayoutDirection == LAYOUT_DIRECTION_RTL) {
+ if (isLayoutRTL) {
page = mPages.size() - 1 - page;
}
return page;
@@ -388,9 +397,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
mPageIndicator.setNumPages(mPages.size());
setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
- if (mPageToRestore != -1) {
+ if (mPageToRestore != NO_PAGE) {
setCurrentItem(mPageToRestore, false);
- mPageToRestore = -1;
+ mPageToRestore = NO_PAGE;
}
}
@@ -479,9 +488,27 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
maxHeight = height;
}
}
+ if (mPages.get(0).getParent() == null) {
+ // Measure page 0 so we know how tall it is if it's not attached to the pager.
+ mPages.get(0).measure(widthMeasureSpec, heightMeasureSpec);
+ int height = mPages.get(0).getMeasuredHeight();
+ if (height > maxHeight) {
+ maxHeight = height;
+ }
+ }
setMeasuredDimension(getMeasuredWidth(), maxHeight + getPaddingBottom());
}
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ if (mPages.get(0).getParent() == null) {
+ // Layout page 0, so we can get the bottom of the tiles. We only do this if the page
+ // is not attached.
+ mPages.get(0).layout(l, t, r, b);
+ }
+ }
+
public int getColumnCount() {
if (mPages.size() == 0) return 0;
return mPages.get(0).mColumns;
@@ -625,8 +652,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
if (mPageIndicator == null) return;
if (mPageListener != null) {
int pageNumber = isLayoutRtl() ? mPages.size() - 1 - position : position;
- mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1
- : position == 0, pageNumber);
+ mPageListener.onPageChanged(pageNumber == 0, pageNumber);
}
}
@@ -645,8 +671,8 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
mPageIndicator.setLocation(mPageIndicatorPosition);
if (mPageListener != null) {
int pageNumber = isLayoutRtl() ? mPages.size() - 1 - position : position;
- mPageListener.onPageChanged(positionOffsetPixels == 0 &&
- (isLayoutRtl() ? position == mPages.size() - 1 : position == 0),
+ mPageListener.onPageChanged(
+ positionOffsetPixels == 0 && pageNumber == 0,
// Send only valid page number on integer pages
positionOffsetPixels == 0 ? pageNumber : PageListener.INVALID_PAGE
);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
index 0fe909552cb1..abebf3e80b21 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
@@ -61,6 +61,7 @@ public class QSFgsManagerFooter implements View.OnClickListener,
private final View mNumberContainer;
private final TextView mNumberView;
private final ImageView mDotView;
+ private final ImageView mCollapsedDotView;
@Nullable
private VisibilityChangedDispatcher.OnVisibilityChangedListener mVisibilityChangedListener;
@@ -75,6 +76,7 @@ public class QSFgsManagerFooter implements View.OnClickListener,
mNumberContainer = mRootView.findViewById(R.id.fgs_number_container);
mNumberView = mRootView.findViewById(R.id.fgs_number);
mDotView = mRootView.findViewById(R.id.fgs_new);
+ mCollapsedDotView = mRootView.findViewById(R.id.fgs_collapsed_new);
mContext = rootView.getContext();
mMainExecutor = mainExecutor;
mExecutor = executor;
@@ -147,8 +149,10 @@ public class QSFgsManagerFooter implements View.OnClickListener,
if (mFgsManagerController.shouldUpdateFooterVisibility()) {
mRootView.setVisibility(mNumPackages > 0
&& mFgsManagerController.isAvailable() ? View.VISIBLE : View.GONE);
- mDotView.setVisibility(
- mFgsManagerController.getChangesSinceDialog() ? View.VISIBLE : View.GONE);
+ int dotVis =
+ mFgsManagerController.getChangesSinceDialog() ? View.VISIBLE : View.GONE;
+ mDotView.setVisibility(dotVis);
+ mCollapsedDotView.setVisibility(dotVis);
if (mVisibilityChangedListener != null) {
mVisibilityChangedListener.onVisibilityChanged(mRootView.getVisibility());
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
index 2959c3b30eec..592da6554b90 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.carrier;
+import android.annotation.StyleRes;
import android.content.Context;
import android.content.res.ColorStateList;
import android.text.TextUtils;
@@ -30,6 +31,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
+import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
import java.util.Objects;
@@ -146,4 +148,8 @@ public class QSCarrier extends LinearLayout {
public void setCarrierText(CharSequence text) {
mCarrierText.setText(text);
}
+
+ public void updateTextAppearance(@StyleRes int resId) {
+ FontSizeUtils.updateFontSizeFromStyle(mCarrierText, resId);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroup.java
index d03563ffb342..a36035b99b4f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroup.java
@@ -16,12 +16,14 @@
package com.android.systemui.qs.carrier;
+import android.annotation.StyleRes;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
+import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
/**
@@ -55,4 +57,11 @@ public class QSCarrierGroup extends LinearLayout {
View getCarrierDivider2() {
return findViewById(R.id.qs_carrier_divider2);
}
+
+ public void updateTextAppearance(@StyleRes int resId) {
+ FontSizeUtils.updateFontSizeFromStyle(getNoSimTextView(), resId);
+ getCarrier1View().updateTextAppearance(resId);
+ getCarrier2View().updateTextAppearance(resId);
+ getCarrier3View().updateTextAppearance(resId);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 8ca095d9a609..6eb54f799a24 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -24,7 +24,6 @@ import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.telephony.ServiceState;
@@ -90,8 +89,6 @@ public class InternetDialog extends SystemUIDialog implements
@VisibleForTesting
protected InternetAdapter mAdapter;
@VisibleForTesting
- protected WifiManager mWifiManager;
- @VisibleForTesting
protected View mDialogView;
@VisibleForTesting
protected boolean mCanConfigWifi;
@@ -179,7 +176,6 @@ public class InternetDialog extends SystemUIDialog implements
mSubscriptionManager = mInternetDialogController.getSubscriptionManager();
mDefaultDataSubId = mInternetDialogController.getDefaultDataSubscriptionId();
mTelephonyManager = mInternetDialogController.getTelephonyManager();
- mWifiManager = mInternetDialogController.getWifiManager();
mCanConfigMobileData = canConfigMobileData;
mCanConfigWifi = canConfigWifi;
mCanChangeWifiState = WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(context);
@@ -332,7 +328,7 @@ public class InternetDialog extends SystemUIDialog implements
showProgressBar();
final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
- final boolean isWifiEnabled = mWifiManager != null && mWifiManager.isWifiEnabled();
+ final boolean isWifiEnabled = mInternetDialogController.isWifiEnabled();
final boolean isWifiScanEnabled = mInternetDialogController.isWifiScanEnabled();
updateWifiToggle(isWifiEnabled, isDeviceLocked);
updateConnectedWifi(isWifiEnabled, isDeviceLocked);
@@ -362,9 +358,8 @@ public class InternetDialog extends SystemUIDialog implements
mSeeAllLayout.setOnClickListener(this::onClickSeeMoreButton);
mWiFiToggle.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
- if (mWifiManager == null) return;
- buttonView.setChecked(isChecked);
- mWifiManager.setWifiEnabled(isChecked);
+ if (mInternetDialogController.isWifiEnabled() == isChecked) return;
+ mInternetDialogController.setWifiEnabled(isChecked);
});
mDoneButton.setOnClickListener(v -> dismiss());
mAirplaneModeButton.setOnClickListener(v -> {
@@ -388,7 +383,7 @@ public class InternetDialog extends SystemUIDialog implements
Log.d(TAG, "setMobileDataLayout, isCarrierNetworkActive = " + isCarrierNetworkActive);
}
- boolean isWifiEnabled = mWifiManager != null && mWifiManager.isWifiEnabled();
+ boolean isWifiEnabled = mInternetDialogController.isWifiEnabled();
if (!mInternetDialogController.hasActiveSubId()
&& (!isWifiEnabled || !isCarrierNetworkActive)) {
mMobileNetworkLayout.setVisibility(View.GONE);
@@ -444,7 +439,9 @@ public class InternetDialog extends SystemUIDialog implements
@MainThread
private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) {
- mWiFiToggle.setChecked(isWifiEnabled);
+ if (mWiFiToggle.isChecked() != isWifiEnabled) {
+ mWiFiToggle.setChecked(isWifiEnabled);
+ }
if (isDeviceLocked) {
mWifiToggleTitleText.setTextAppearance((mConnectedWifiEntry != null)
? R.style.TextAppearance_InternetDialog_Active
@@ -572,7 +569,7 @@ public class InternetDialog extends SystemUIDialog implements
}
protected void showProgressBar() {
- if (mWifiManager == null || !mWifiManager.isWifiEnabled()
+ if (!mInternetDialogController.isWifiEnabled()
|| mInternetDialogController.isDeviceLocked()) {
setProgressBarVisible(false);
return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index d97ce7757d8c..90a3d4586fd3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -22,6 +22,7 @@ import static com.android.wifitrackerlib.WifiEntry.CONNECTED_STATE_CONNECTED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.annotation.AnyThread;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -157,6 +158,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi
private LocationController mLocationController;
private DialogLaunchAnimator mDialogLaunchAnimator;
private boolean mHasWifiEntries;
+ private WifiStateWorker mWifiStateWorker;
@VisibleForTesting
static final float TOAST_PARAMS_HORIZONTAL_WEIGHT = 1.0f;
@@ -210,7 +212,9 @@ public class InternetDialogController implements AccessPointController.AccessPoi
@Background Handler workerHandler,
CarrierConfigTracker carrierConfigTracker,
LocationController locationController,
- DialogLaunchAnimator dialogLaunchAnimator) {
+ DialogLaunchAnimator dialogLaunchAnimator,
+ WifiStateWorker wifiStateWorker
+ ) {
if (DEBUG) {
Log.d(TAG, "Init InternetDialogController");
}
@@ -241,6 +245,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi
mLocationController = locationController;
mDialogLaunchAnimator = dialogLaunchAnimator;
mConnectedWifiInternetMonitor = new ConnectedWifiInternetMonitor();
+ mWifiStateWorker = wifiStateWorker;
}
void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) {
@@ -323,7 +328,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi
@Nullable
CharSequence getSubtitleText(boolean isProgressBarVisible) {
- if (mCanConfigWifi && !mWifiManager.isWifiEnabled()) {
+ if (mCanConfigWifi && !isWifiEnabled()) {
// When Wi-Fi is disabled.
// Sub-Title: Wi-Fi is off
if (DEBUG) {
@@ -648,6 +653,27 @@ public class InternetDialogController implements AccessPointController.AccessPoi
startActivity(intent, view);
}
+ /**
+ * Enable or disable Wi-Fi.
+ *
+ * @param enabled {@code true} to enable, {@code false} to disable.
+ */
+ @AnyThread
+ public void setWifiEnabled(boolean enabled) {
+ mWifiStateWorker.setWifiEnabled(enabled);
+ }
+
+ /**
+ * Return whether Wi-Fi is enabled or disabled.
+ *
+ * @return {@code true} if Wi-Fi is enabled or enabling
+ * @see WifiManager#getWifiState()
+ */
+ @AnyThread
+ public boolean isWifiEnabled() {
+ return mWifiStateWorker.isWifiEnabled();
+ }
+
void connectCarrierNetwork() {
final MergedCarrierEntry mergedCarrierEntry =
mAccessPointController.getMergedCarrierEntry();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/WifiStateWorker.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/WifiStateWorker.java
new file mode 100644
index 000000000000..a7ea50e5e6dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/WifiStateWorker.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.dialog;
+
+import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE;
+import static android.net.wifi.WifiManager.WIFI_STATE_CHANGED_ACTION;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.WifiManager;
+import android.util.Log;
+
+import androidx.annotation.AnyThread;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import javax.inject.Inject;
+
+/**
+ * Worker for the Wi-Fi enabled state cache.
+ */
+@SysUISingleton
+public class WifiStateWorker extends BroadcastReceiver {
+
+ private static final String TAG = "WifiStateWorker";
+
+ private DelayableExecutor mBackgroundExecutor;
+ private WifiManager mWifiManager;
+ private int mWifiState = WIFI_STATE_DISABLED;
+
+ @Inject
+ public WifiStateWorker(
+ BroadcastDispatcher broadcastDispatcher,
+ @Background DelayableExecutor backgroundExecutor,
+ @Nullable WifiManager wifiManager) {
+ mWifiManager = wifiManager;
+ mBackgroundExecutor = backgroundExecutor;
+
+ broadcastDispatcher.registerReceiver(this, new IntentFilter(WIFI_STATE_CHANGED_ACTION));
+ mBackgroundExecutor.execute(() -> {
+ if (mWifiManager == null) return;
+
+ mWifiState = mWifiManager.getWifiState();
+ Log.i(TAG, "WifiManager.getWifiState():" + mWifiState);
+ });
+ }
+
+ /**
+ * Enable or disable Wi-Fi.
+ *
+ * @param enabled {@code true} to enable, {@code false} to disable.
+ */
+ @AnyThread
+ public void setWifiEnabled(boolean enabled) {
+ mBackgroundExecutor.execute(() -> {
+ if (mWifiManager == null) return;
+
+ mWifiState = (enabled) ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING;
+ if (!mWifiManager.setWifiEnabled(enabled)) {
+ Log.e(TAG, "Failed to WifiManager.setWifiEnabled(" + enabled + ");");
+ }
+ });
+ }
+
+ /**
+ * Gets the Wi-Fi enabled state.
+ *
+ * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
+ * {@link WifiManager#WIFI_STATE_DISABLING}, {@link WifiManager#WIFI_STATE_ENABLED},
+ * {@link WifiManager#WIFI_STATE_ENABLING}
+ */
+ @AnyThread
+ public int getWifiState() {
+ return mWifiState;
+ }
+
+ /**
+ * Return whether Wi-Fi is enabled or disabled.
+ *
+ * @return {@code true} if Wi-Fi is enabled or enabling
+ * @see WifiManager#getWifiState()
+ */
+ @AnyThread
+ public boolean isWifiEnabled() {
+ return (mWifiState == WIFI_STATE_ENABLED || mWifiState == WIFI_STATE_ENABLING);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent == null) return;
+
+ if (WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
+ final int wifiState = intent.getIntExtra(EXTRA_WIFI_STATE, WIFI_STATE_DISABLED);
+ if (wifiState == WIFI_STATE_UNKNOWN) return;
+
+ mWifiState = wifiState;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 009d4b9b48e6..4728c678f96c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -674,15 +674,21 @@ public class ScreenshotController {
if (mLastScrollCaptureRequest != null) {
mLastScrollCaptureRequest.cancel(true);
}
- mLastScrollCaptureRequest = mScrollCaptureClient.request(DEFAULT_DISPLAY);
+ final ListenableFuture<ScrollCaptureResponse> future =
+ mScrollCaptureClient.request(DEFAULT_DISPLAY);
+ mLastScrollCaptureRequest = future;
mLastScrollCaptureRequest.addListener(() ->
- onScrollCaptureResponseReady(mLastScrollCaptureRequest), mMainExecutor);
+ onScrollCaptureResponseReady(future), mMainExecutor);
}
private void onScrollCaptureResponseReady(Future<ScrollCaptureResponse> responseFuture) {
try {
if (mLastScrollCaptureResponse != null) {
mLastScrollCaptureResponse.close();
+ mLastScrollCaptureResponse = null;
+ }
+ if (responseFuture.isCancelled()) {
+ return;
}
mLastScrollCaptureResponse = responseFuture.get();
if (!mLastScrollCaptureResponse.isConnected()) {
@@ -707,8 +713,6 @@ public class ScreenshotController {
// delay starting scroll capture to make sure the scrim is up before the app moves
mScreenshotView.post(() -> runBatchScrollCapture(response));
});
- } catch (CancellationException e) {
- // Ignore
} catch (InterruptedException | ExecutionException e) {
Log.e(TAG, "requestScrollCapture failed", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 924351df3117..7f3758e208db 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -27,6 +27,7 @@ import static com.android.systemui.screenshot.LogConfig.logTag;
import android.annotation.MainThread;
import android.app.Service;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -42,9 +43,11 @@ import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.view.WindowManager;
+import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -62,9 +65,11 @@ public class TakeScreenshotService extends Service {
private ScreenshotController mScreenshot;
private final UserManager mUserManager;
+ private final DevicePolicyManager mDevicePolicyManager;
private final UiEventLogger mUiEventLogger;
private final ScreenshotNotificationsController mNotificationsController;
private final Handler mHandler;
+ private final Context mContext;
private final BroadcastReceiver mCloseSystemDialogs = new BroadcastReceiver() {
@Override
@@ -91,16 +96,18 @@ public class TakeScreenshotService extends Service {
@Inject
public TakeScreenshotService(ScreenshotController screenshotController, UserManager userManager,
- UiEventLogger uiEventLogger,
- ScreenshotNotificationsController notificationsController) {
+ DevicePolicyManager devicePolicyManager, UiEventLogger uiEventLogger,
+ ScreenshotNotificationsController notificationsController, Context context) {
if (DEBUG_SERVICE) {
Log.d(TAG, "new " + this);
}
mHandler = new Handler(Looper.getMainLooper(), this::handleMessage);
mScreenshot = screenshotController;
mUserManager = userManager;
+ mDevicePolicyManager = devicePolicyManager;
mUiEventLogger = uiEventLogger;
mNotificationsController = notificationsController;
+ mContext = context;
}
@Override
@@ -182,6 +189,14 @@ public class TakeScreenshotService extends Service {
requestCallback.reportError();
return true;
}
+ if(mDevicePolicyManager.getScreenCaptureDisabled(null, UserHandle.USER_ALL)) {
+ Log.w(TAG, "Skipping screenshot because an IT admin has disabled "
+ + "screenshots on the device");
+ Toast.makeText(mContext, R.string.screenshot_blocked_by_admin,
+ Toast.LENGTH_SHORT).show();
+ requestCallback.reportError();
+ return true;
+ }
ScreenshotHelper.ScreenshotRequest screenshotRequest =
(ScreenshotHelper.ScreenshotRequest) msg.obj;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 270bdc785178..0a616c095551 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -17,6 +17,7 @@ import android.util.MathUtils.lerp
import android.view.View
import com.android.systemui.animation.Interpolators
import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold
+import com.android.systemui.util.getColorWithAlpha
import java.util.function.Consumer
/**
@@ -367,7 +368,7 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context,
}
if (startColorAlpha > 0f) {
- canvas.drawColor(updateColorAlpha(revealGradientEndColor, startColorAlpha))
+ canvas.drawColor(getColorWithAlpha(revealGradientEndColor, startColorAlpha))
}
with(shaderGradientMatrix) {
@@ -383,15 +384,7 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context,
private fun setPaintColorFilter() {
gradientPaint.colorFilter = PorterDuffColorFilter(
- updateColorAlpha(revealGradientEndColor, revealGradientEndColorAlpha),
+ getColorWithAlpha(revealGradientEndColor, revealGradientEndColorAlpha),
PorterDuff.Mode.MULTIPLY)
}
-
- private fun updateColorAlpha(color: Int, alpha: Float): Int =
- Color.argb(
- (alpha * 255).toInt(),
- Color.red(color),
- Color.green(color),
- Color.blue(color)
- )
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index afce945a5bc5..734bc48093b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -39,7 +39,6 @@ import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
-import com.android.systemui.statusbar.notification.row.NotificationBackgroundView;
import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
@@ -411,7 +410,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
setBackgroundTop(backgroundTop);
setFirstElementRoundness(firstElementRoundness);
mShelfIcons.setSpeedBumpIndex(mHostLayoutController.getSpeedBumpIndex());
- mShelfIcons.calculateIconTranslations();
+ mShelfIcons.calculateIconXTranslations();
mShelfIcons.applyIconStates();
for (int i = 0; i < mHostLayoutController.getChildCount(); i++) {
View child = mHostLayoutController.getChildAt(i);
@@ -636,7 +635,7 @@ public class NotificationShelf extends ActivatableNotificationView implements
float viewEnd = viewStart + fullHeight;
float fullTransitionAmount = 0.0f;
float iconTransitionAmount = 0.0f;
- float shelfStart = getTranslationY();
+ float shelfStart = getTranslationY() - mPaddingBetweenElements;
if (mAmbientState.isExpansionChanging() && !mAmbientState.isOnKeyguard()) {
// TODO(b/172289889) handle icon placement for notification that is clipped by the shelf
if (mIndexOfFirstViewInShelf != -1 && i >= mIndexOfFirstViewInShelf) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index a4e2d5ec0829..a35bced819c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -28,7 +28,8 @@ import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
import android.os.UserHandle
-import android.provider.Settings
+import android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
+import android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS
import android.util.Log
import android.view.View
import android.view.ViewGroup
@@ -85,6 +86,7 @@ class LockscreenSmartspaceController @Inject constructor(
// Smartspace can be used on multiple displays, such as when the user casts their screen
private var smartspaceViews = mutableSetOf<SmartspaceView>()
+ private var showNotifications = false
private var showSensitiveContentForCurrentUser = false
private var showSensitiveContentForManagedUser = false
private var managedUserHandle: UserHandle? = null
@@ -233,7 +235,13 @@ class LockscreenSmartspaceController @Inject constructor(
deviceProvisionedController.removeCallback(deviceProvisionedListener)
userTracker.addCallback(userTrackerCallback, uiExecutor)
contentResolver.registerContentObserver(
- secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+ secureSettings.getUriFor(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+ true,
+ settingsObserver,
+ UserHandle.USER_ALL
+ )
+ contentResolver.registerContentObserver(
+ secureSettings.getUriFor(LOCK_SCREEN_SHOW_NOTIFICATIONS),
true,
settingsObserver,
UserHandle.USER_ALL
@@ -286,6 +294,9 @@ class LockscreenSmartspaceController @Inject constructor(
}
private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
+ if (!showNotifications) {
+ return t.getFeatureType() == SmartspaceTarget.FEATURE_WEATHER
+ }
return when (t.userHandle) {
userTracker.userHandle -> {
!t.isSensitive || showSensitiveContentForCurrentUser
@@ -310,16 +321,26 @@ class LockscreenSmartspaceController @Inject constructor(
}
private fun reloadSmartspace() {
- val setting = Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
-
- showSensitiveContentForCurrentUser =
- secureSettings.getIntForUser(setting, 0, userTracker.userId) == 1
+ showNotifications = secureSettings.getIntForUser(
+ LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ 0,
+ userTracker.userId
+ ) == 1
+
+ showSensitiveContentForCurrentUser = secureSettings.getIntForUser(
+ LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ 0,
+ userTracker.userId
+ ) == 1
managedUserHandle = getWorkProfileUser()
val managedId = managedUserHandle?.identifier
if (managedId != null) {
- showSensitiveContentForManagedUser =
- secureSettings.getIntForUser(setting, 0, managedId) == 1
+ showSensitiveContentForManagedUser = secureSettings.getIntForUser(
+ LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ 0,
+ managedId
+ ) == 1
}
session?.requestSmartspaceUpdate()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 51af9559eda2..6f65131ba452 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -709,8 +709,8 @@ public class ShadeListBuilder implements Dumpable {
new ArraySet<>(groupsWithChildrenLostToStability);
// Any group which lost a child to filtering or promotion is exempt from having its summary
// promoted when it has no attached children.
- getGroupsWithChildrenLostToFiltering(groupsExemptFromSummaryPromotion);
- getGroupsWithChildrenLostToPromotion(shadeList, groupsExemptFromSummaryPromotion);
+ addGroupsWithChildrenLostToFiltering(groupsExemptFromSummaryPromotion);
+ addGroupsWithChildrenLostToPromotion(shadeList, groupsExemptFromSummaryPromotion);
// Iterate backwards, so that we can remove elements without affecting indices of
// yet-to-be-accessed entries.
@@ -865,7 +865,7 @@ public class ShadeListBuilder implements Dumpable {
*
* These groups will be exempt from appearing without any children.
*/
- private void getGroupsWithChildrenLostToPromotion(List<ListEntry> shadeList, Set<String> out) {
+ private void addGroupsWithChildrenLostToPromotion(List<ListEntry> shadeList, Set<String> out) {
for (int i = 0; i < shadeList.size(); i++) {
final ListEntry tle = shadeList.get(i);
if (tle.getAttachState().getPromoter() != null) {
@@ -882,13 +882,13 @@ public class ShadeListBuilder implements Dumpable {
*
* These groups will be exempt from appearing without any children.
*/
- private void getGroupsWithChildrenLostToFiltering(Set<String> out) {
+ private void addGroupsWithChildrenLostToFiltering(Set<String> out) {
for (ListEntry tle : mAllEntries) {
StatusBarNotification sbn = tle.getRepresentativeEntry().getSbn();
if (sbn.isGroup()
&& !sbn.getNotification().isGroupSummary()
&& tle.getAttachState().getExcludingFilter() != null) {
- out.add(sbn.getGroup());
+ out.add(sbn.getGroupKey());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
index 032e6784ae08..386e2d31380c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.collection.render
import android.annotation.MainThread
import android.view.View
+import com.android.systemui.util.kotlin.transform
import com.android.systemui.util.traceSection
/**
@@ -40,6 +41,7 @@ class ShadeViewDiffer(
) {
private val rootNode = ShadeNode(rootController)
private val nodes = mutableMapOf(rootController to rootNode)
+ private val views = mutableMapOf<View, ShadeNode>()
/**
* Adds and removes views from the root (and its children) until their structure matches the
@@ -64,25 +66,26 @@ class ShadeViewDiffer(
*
* For debugging purposes.
*/
- fun getViewLabel(view: View): String =
- nodes.values.firstOrNull { node -> node.view === view }?.label ?: view.toString()
-
- private fun detachChildren(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
- val views = nodes.values.asSequence().map { node -> node.view to node }.toMap()
- fun detachRecursively(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
- val parentSpec = specMap[parentNode.controller]
- for (i in parentNode.getChildCount() - 1 downTo 0) {
- val childView = parentNode.getChildAt(i)
- views[childView]?.let { childNode ->
- val childSpec = specMap[childNode.controller]
- maybeDetachChild(parentNode, parentSpec, childNode, childSpec)
- if (childNode.controller.getChildCount() > 0) {
- detachRecursively(childNode, specMap)
- }
+ fun getViewLabel(view: View): String = views[view]?.label ?: view.toString()
+
+ private fun detachChildren(
+ parentNode: ShadeNode,
+ specMap: Map<NodeController, NodeSpec>
+ ) {
+ val parentSpec = specMap[parentNode.controller]
+
+ for (i in parentNode.getChildCount() - 1 downTo 0) {
+ val childView = parentNode.getChildAt(i)
+ views[childView]?.let { childNode ->
+ val childSpec = specMap[childNode.controller]
+
+ maybeDetachChild(parentNode, parentSpec, childNode, childSpec)
+
+ if (childNode.controller.getChildCount() > 0) {
+ detachChildren(childNode, specMap)
}
}
}
- detachRecursively(parentNode, specMap)
}
private fun maybeDetachChild(
@@ -91,13 +94,14 @@ class ShadeViewDiffer(
childNode: ShadeNode,
childSpec: NodeSpec?
) {
- val newParentNode = childSpec?.parent?.let { getNode(it) }
+ val newParentNode = transform(childSpec?.parent) { getNode(it) }
if (newParentNode != parentNode) {
val childCompletelyRemoved = newParentNode == null
if (childCompletelyRemoved) {
nodes.remove(childNode.controller)
+ views.remove(childNode.controller.view)
}
logger.logDetachingChild(
@@ -111,7 +115,10 @@ class ShadeViewDiffer(
}
}
- private fun attachChildren(parentNode: ShadeNode, specMap: Map<NodeController, NodeSpec>) {
+ private fun attachChildren(
+ parentNode: ShadeNode,
+ specMap: Map<NodeController, NodeSpec>
+ ) {
val parentSpec = checkNotNull(specMap[parentNode.controller])
for ((index, childSpec) in parentSpec.children.withIndex()) {
@@ -153,6 +160,7 @@ class ShadeViewDiffer(
if (node == null) {
node = ShadeNode(spec.controller)
nodes[node.controller] = node
+ views[node.view] = node
}
return node
}
@@ -186,9 +194,10 @@ class ShadeViewDiffer(
private class DuplicateNodeException(message: String) : RuntimeException(message)
-private class ShadeNode(val controller: NodeController) {
- val view: View
- get() = controller.view
+private class ShadeNode(
+ val controller: NodeController
+) {
+ val view = controller.view
var parent: ShadeNode? = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index bf27550b331b..36cd173d2d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -415,6 +415,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private boolean mForwardScrollable;
private boolean mBackwardScrollable;
private NotificationShelf mShelf;
+ /**
+ * Limits the number of visible notifications. The remaining are collapsed in the notification
+ * shelf. -1 when there is no limit.
+ */
private int mMaxDisplayedNotifications = -1;
private float mKeyguardBottomPadding = -1;
@VisibleForTesting int mStatusBarHeight;
@@ -1323,7 +1327,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
private float updateStackEndHeight(float height, float bottomMargin, float topPadding) {
- final float stackEndHeight = Math.max(0f, height - bottomMargin - topPadding);
+ final float stackEndHeight;
+ if (mMaxDisplayedNotifications != -1) {
+ // The stack intrinsic height already contains the correct value when there is a limit
+ // in the max number of notifications (e.g. as in keyguard).
+ stackEndHeight = mIntrinsicContentHeight;
+ } else {
+ stackEndHeight = Math.max(0f, height - bottomMargin - topPadding);
+ }
mAmbientState.setStackEndHeight(stackEndHeight);
return stackEndHeight;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index ae1fd2b180e5..2493ccbe5a48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -117,6 +117,7 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
+import com.android.systemui.statusbar.phone.shade.transition.ShadeTransitionController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -178,6 +179,7 @@ public class NotificationStackScrollLayoutController {
private final CentralSurfaces mCentralSurfaces;
private final SectionHeaderController mSilentHeaderController;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private final ShadeTransitionController mShadeTransitionController;
private final InteractionJankMonitor mJankMonitor;
private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
private final StackStateLogger mStackStateLogger;
@@ -647,6 +649,7 @@ public class NotificationStackScrollLayoutController {
NotifCollection notifCollection,
NotificationEntryManager notificationEntryManager,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
+ ShadeTransitionController shadeTransitionController,
IStatusBarService iStatusBarService,
UiEventLogger uiEventLogger,
LayoutInflater layoutInflater,
@@ -675,6 +678,7 @@ public class NotificationStackScrollLayoutController {
mLockscreenUserManager = lockscreenUserManager;
mMetricsLogger = metricsLogger;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
+ mShadeTransitionController = shadeTransitionController;
mFalsingCollector = falsingCollector;
mFalsingManager = falsingManager;
mResources = resources;
@@ -769,6 +773,7 @@ public class NotificationStackScrollLayoutController {
mScrimController.setScrimBehindChangeRunnable(mView::updateBackgroundDimming);
mLockscreenShadeTransitionController.setStackScroller(this);
+ mShadeTransitionController.setNotificationStackScrollLayoutController(this);
mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
@@ -1207,7 +1212,7 @@ public class NotificationStackScrollLayoutController {
*/
public void updateShowEmptyShadeView() {
Trace.beginSection("NSSLC.updateShowEmptyShadeView");
- mShowEmptyShadeView = mBarState != KEYGUARD
+ mShowEmptyShadeView = mStatusBarStateController.getCurrentOrUpcomingState() != KEYGUARD
&& !mView.isQsFullScreen()
&& getVisibleNotificationCount() == 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
index 2b11f693da1d..9ea36d540f4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -207,9 +207,7 @@ constructor(
visibleIndex: Int
): Float {
var height = stack.calculateGapHeight(previous, current, visibleIndex)
- if (visibleIndex != 0) {
- height += dividerHeight
- }
+ height += dividerHeight
return height
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 22242b8fb4b4..2b79986662f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -314,7 +314,8 @@ public class StackScrollAlgorithm {
if (ambientState.getShelf() != null) {
final float shelfStart = ambientState.getStackEndHeight()
- - ambientState.getShelf().getIntrinsicHeight();
+ - ambientState.getShelf().getIntrinsicHeight()
+ - mPaddingBetweenElements;
if (currentY >= shelfStart
&& !(view instanceof FooterView)
&& state.firstViewInShelf == null) {
@@ -507,8 +508,9 @@ public class StackScrollAlgorithm {
|| bypassPulseNotExpanding
? ambientState.getInnerHeight()
: (int) ambientState.getStackHeight();
- final int shelfStart =
- stackBottom - ambientState.getShelf().getIntrinsicHeight();
+ final int shelfStart = stackBottom
+ - ambientState.getShelf().getIntrinsicHeight()
+ - mPaddingBetweenElements;
viewState.yTranslation = Math.min(viewState.yTranslation, shelfStart);
if (viewState.yTranslation >= shelfStart) {
viewState.hidden = !view.isExpandAnimationRunning()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index b14e92bf39cf..62b11c59923f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -1748,6 +1748,23 @@ public class CentralSurfaces extends CoreStartable implements
}
@Override
+ public void onLaunchAnimationStart(boolean isExpandingFullyAbove) {
+ super.onLaunchAnimationStart(isExpandingFullyAbove);
+
+ // Double check that the keyguard is still showing and not going away, but if so
+ // set the keyguard occluded. Typically, WM will let KeyguardViewMediator know
+ // directly, but we're overriding that to play the custom launch animation, so
+ // we need to take care of that here. The unocclude animation is not overridden,
+ // so WM will call KeyguardViewMediator's unocclude animation runner when the
+ // activity is exited.
+ if (mKeyguardStateController.isShowing()
+ && !mKeyguardStateController.isKeyguardGoingAway()) {
+ mKeyguardViewMediator.setOccluded(true /* isOccluded */,
+ true /* animate */);
+ }
+ }
+
+ @Override
public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) {
// Set mIsLaunchingActivityOverLockscreen to false before actually finishing the
// animation so that we can assume that mIsLaunchingActivityOverLockscreen
@@ -2934,8 +2951,6 @@ public class CentralSurfaces extends CoreStartable implements
public void showKeyguardImpl() {
Trace.beginSection("CentralSurfaces#showKeyguard");
- // In case we're locking while a smartspace transition is in progress, reset it.
- mKeyguardUnlockAnimationController.resetSmartspaceTransition();
if (mKeyguardStateController.isLaunchTransitionFadingAway()) {
mNotificationPanelViewController.cancelAnimation();
onLaunchTransitionFadingEnded();
@@ -4514,9 +4529,12 @@ public class CentralSurfaces extends CoreStartable implements
* @return UserHandle
*/
private UserHandle getActivityUserHandle(Intent intent) {
- if (intent.getComponent() != null
- && mContext.getPackageName().equals(intent.getComponent().getPackageName())) {
- return new UserHandle(UserHandle.myUserId());
+ String[] packages = mContext.getResources().getStringArray(R.array.system_ui_packages);
+ for (String pkg : packages) {
+ if (intent.getComponent() == null) break;
+ if (pkg.equals(intent.getComponent().getPackageName())) {
+ return new UserHandle(UserHandle.myUserId());
+ }
}
return UserHandle.CURRENT;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderController.kt
index 289dfc889e75..178c17dd5694 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderController.kt
@@ -18,9 +18,11 @@ package com.android.systemui.statusbar.phone
import android.app.StatusBarManager
import android.view.View
+import android.widget.TextView
import androidx.constraintlayout.motion.widget.MotionLayout
import com.android.settingslib.Utils
import com.android.systemui.Dumpable
+import com.android.systemui.FontSizeUtils
import com.android.systemui.R
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
@@ -30,10 +32,12 @@ import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.qs.ChipVisibilityListener
import com.android.systemui.qs.HeaderPrivacyIconsController
+import com.android.systemui.qs.carrier.QSCarrierGroup
import com.android.systemui.qs.carrier.QSCarrierGroupController
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.LARGE_SCREEN_BATTERY_CONTROLLER
import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.LARGE_SCREEN_SHADE_HEADER
+import com.android.systemui.statusbar.policy.ConfigurationController
import java.io.PrintWriter
import javax.inject.Inject
import javax.inject.Named
@@ -43,6 +47,7 @@ class LargeScreenShadeHeaderController @Inject constructor(
@Named(LARGE_SCREEN_SHADE_HEADER) private val header: View,
private val statusBarIconController: StatusBarIconController,
private val privacyIconsController: HeaderPrivacyIconsController,
+ private val configurationController: ConfigurationController,
qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder,
featureFlags: FeatureFlags,
@Named(LARGE_SCREEN_BATTERY_CONTROLLER) batteryMeterViewController: BatteryMeterViewController,
@@ -69,6 +74,9 @@ class LargeScreenShadeHeaderController @Inject constructor(
private val iconContainer: StatusIconContainer
private val carrierIconSlots: List<String>
private val qsCarrierGroupController: QSCarrierGroupController
+ private val clock: TextView = header.findViewById(R.id.clock)
+ private val date: TextView = header.findViewById(R.id.date)
+ private val qsCarrierGroup: QSCarrierGroup = header.findViewById(R.id.carrier_group)
private var qsDisabled = false
@@ -148,9 +156,9 @@ class LargeScreenShadeHeaderController @Inject constructor(
.load(context, resources.getXml(R.xml.large_screen_shade_header))
privacyIconsController.chipVisibilityListener = chipVisibilityListener
}
- }
- init {
+ bindConfigurationListener()
+
batteryMeterViewController.init()
val batteryIcon: BatteryMeterView = header.findViewById(R.id.batteryRemainingIcon)
@@ -194,6 +202,18 @@ class LargeScreenShadeHeaderController @Inject constructor(
}
}
+ private fun bindConfigurationListener() {
+ val listener = object : ConfigurationController.ConfigurationListener {
+ override fun onDensityOrFontScaleChanged() {
+ val qsStatusStyle = R.style.TextAppearance_QS_Status
+ FontSizeUtils.updateFontSizeFromStyle(clock, qsStatusStyle)
+ FontSizeUtils.updateFontSizeFromStyle(date, qsStatusStyle)
+ qsCarrierGroup.updateTextAppearance(qsStatusStyle)
+ }
+ }
+ configurationController.addCallback(listener)
+ }
+
private fun onShadeExpandedChanged() {
if (shadeExpanded) {
privacyIconsController.startListening()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 034b751d1e61..2dc3261eb886 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -27,11 +27,13 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.util.AttributeSet;
+import android.util.MathUtils;
import android.util.Property;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.view.animation.Interpolator;
+import androidx.annotation.VisibleForTesting;
import androidx.collection.ArrayMap;
import com.android.internal.statusbar.StatusBarIcon;
@@ -136,6 +138,8 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
}.setDuration(CONTENT_FADE_DURATION);
private static final int MAX_ICONS_ON_AOD = 3;
+
+ /* Maximum number of icons in short shelf on lockscreen when also showing overflow dot. */
public static final int MAX_ICONS_ON_LOCKSCREEN = 3;
public static final int MAX_STATIC_ICONS = 4;
private static final int MAX_DOTS = 1;
@@ -145,7 +149,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
private int mDotPadding;
private int mStaticDotRadius;
private int mStaticDotDiameter;
- private int mOverflowWidth;
private int mActualLayoutWidth = NO_VALUE;
private float mActualPaddingEnd = NO_VALUE;
private float mActualPaddingStart = NO_VALUE;
@@ -219,10 +222,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
paint.setColor(Color.RED);
canvas.drawLine(mVisualOverflowStart, 0, mVisualOverflowStart, height, paint);
-
- paint.setColor(Color.YELLOW);
- float overflow = getMaxOverflowStart();
- canvas.drawLine(overflow, 0, overflow, height, paint);
}
}
@@ -255,14 +254,14 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
}
}
- private void setIconSize(int size) {
+ @VisibleForTesting
+ public void setIconSize(int size) {
mIconSize = size;
- mOverflowWidth = mIconSize + (MAX_DOTS - 1) * (mStaticDotDiameter + mDotPadding);
}
private void updateState() {
resetViewStates();
- calculateIconTranslations();
+ calculateIconXTranslations();
applyIconStates();
}
@@ -390,12 +389,11 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
* @return Width of shelf for the given number of icons
*/
public float calculateWidthFor(float numIcons) {
- if (getChildCount() == 0) {
+ if (numIcons == 0) {
return 0f;
}
- final float contentWidth = numIcons <= MAX_ICONS_ON_LOCKSCREEN + 1
- ? numIcons * mIconSize
- : MAX_ICONS_ON_LOCKSCREEN * mIconSize + (float) mOverflowWidth;
+ final float contentWidth =
+ mIconSize * MathUtils.min(numIcons, MAX_ICONS_ON_LOCKSCREEN + 1);
return getActualPaddingStart()
+ contentWidth
+ getActualPaddingEnd();
@@ -406,14 +404,13 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
* are inserted into the notification container.
* If this is not a whole number, the fraction means by how much the icon is appearing.
*/
- public void calculateIconTranslations() {
+ public void calculateIconXTranslations() {
float translationX = getActualPaddingStart();
int firstOverflowIndex = -1;
int childCount = getChildCount();
int maxVisibleIcons = mOnLockScreen ? MAX_ICONS_ON_AOD :
mIsStaticLayout ? MAX_STATIC_ICONS : childCount;
float layoutEnd = getLayoutEnd();
- float overflowStart = getMaxOverflowStart();
mVisualOverflowStart = 0;
mFirstVisibleIconState = null;
for (int i = 0; i < childCount; i++) {
@@ -438,12 +435,12 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
? StatusBarIconView.STATE_HIDDEN
: StatusBarIconView.STATE_ICON;
- boolean isOverflowing =
- (translationX > (isLastChild ? layoutEnd - mIconSize
- : overflowStart - mIconSize));
+ final float overflowDotX = layoutEnd - mIconSize;
+ boolean isOverflowing = translationX > overflowDotX;
+
if (firstOverflowIndex == -1 && (forceOverflow || isOverflowing)) {
firstOverflowIndex = isLastChild && !forceOverflow ? i - 1 : i;
- mVisualOverflowStart = layoutEnd - mOverflowWidth;
+ mVisualOverflowStart = layoutEnd - mIconSize;
if (forceOverflow || mIsStaticLayout) {
mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
}
@@ -477,7 +474,6 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
mLastVisibleIconState = mIconStates.get(lastChild);
mFirstVisibleIconState = mIconStates.get(getChildAt(0));
}
-
if (isLayoutRtl()) {
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
@@ -568,7 +564,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
}
private float getMaxOverflowStart() {
- return getLayoutEnd() - mOverflowWidth;
+ return getLayoutEnd() - mIconSize;
}
public void setChangingViewPositions(boolean changingViewPositions) {
@@ -635,7 +631,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
return 0;
}
- int collapsedPadding = mOverflowWidth;
+ int collapsedPadding = mIconSize;
if (collapsedPadding + getFinalTranslationX() > getWidth()) {
collapsedPadding = getWidth() - getFinalTranslationX();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index adf70a255b4f..0e8c8a2b4f2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -179,6 +179,7 @@ import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.phone.panelstate.PanelState;
+import com.android.systemui.statusbar.phone.shade.transition.ShadeTransitionController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -310,6 +311,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final NotificationRemoteInputManager mRemoteInputManager;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private final ShadeTransitionController mShadeTransitionController;
private final TapAgainViewController mTapAgainViewController;
private final LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
private final RecordingController mRecordingController;
@@ -745,7 +747,8 @@ public class NotificationPanelViewController extends PanelViewController {
NotificationListContainer notificationListContainer,
PanelEventsEmitter panelEventsEmitter,
NotificationStackSizeCalculator notificationStackSizeCalculator,
- UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
+ UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
+ ShadeTransitionController shadeTransitionController) {
super(view,
falsingManager,
dozeLog,
@@ -826,7 +829,9 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardBypassController = bypassController;
mUpdateMonitor = keyguardUpdateMonitor;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
+ mShadeTransitionController = shadeTransitionController;
lockscreenShadeTransitionController.setNotificationPanelController(this);
+ shadeTransitionController.setNotificationPanelViewController(this);
DynamicPrivacyControlListener
dynamicPrivacyControlListener =
new DynamicPrivacyControlListener();
@@ -885,7 +890,10 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public void onUnlockAnimationStarted(
- boolean playingCannedAnimation, boolean isWakeAndUnlock) {
+ boolean playingCannedAnimation,
+ boolean isWakeAndUnlock,
+ long unlockAnimationStartDelay,
+ long unlockAnimationDuration) {
// Disable blurs while we're unlocking so that panel expansion does not
// cause blurring. This will eventually be re-enabled by the panel view on
// ACTION_UP, since the user's finger might still be down after a swipe to
@@ -902,7 +910,22 @@ public class NotificationPanelViewController extends PanelViewController {
onTrackingStopped(false);
instantCollapse();
} else {
- fling(0f, false, 1f, false);
+ mView.animate()
+ .alpha(0f)
+ .setStartDelay(0)
+ // Translate up by 4%.
+ .translationY(mView.getHeight() * -0.04f)
+ // This start delay is to give us time to animate out before
+ // the launcher icons animation starts, so use that as our
+ // duration.
+ .setDuration(unlockAnimationStartDelay)
+ .setInterpolator(EMPHASIZED_DECELERATE)
+ .withEndAction(() -> {
+ instantCollapse();
+ mView.setAlpha(1f);
+ mView.setTranslationY(0f);
+ })
+ .start();
}
}
}
@@ -1233,6 +1256,11 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardBottomArea.initQRCodeScanner(mQRCodeScannerController);
}
+ @VisibleForTesting
+ void setMaxDisplayedNotifications(int maxAllowed) {
+ mMaxAllowedKeyguardNotifications = maxAllowed;
+ }
+
private void updateMaxDisplayedNotifications(boolean recompute) {
if (recompute) {
mMaxAllowedKeyguardNotifications = Math.max(computeMaxKeyguardNotifications(), 1);
@@ -1463,7 +1491,11 @@ public class NotificationPanelViewController extends PanelViewController {
/**
* @return the maximum keyguard notifications that can fit on the screen
*/
- private int computeMaxKeyguardNotifications() {
+ @VisibleForTesting
+ int computeMaxKeyguardNotifications() {
+ if (mAmbientState.getFractionToShade() > 0 || mAmbientState.getDozeAmount() > 0) {
+ return mMaxAllowedKeyguardNotifications;
+ }
float topPadding = mNotificationStackScrollLayoutController.getTopPadding();
float shelfIntrinsicHeight =
mNotificationShelfController.getVisibility() == View.GONE
@@ -3169,12 +3201,6 @@ public class NotificationPanelViewController extends PanelViewController {
mFalsingCollector.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
super.onTrackingStarted();
mScrimController.onTrackingStarted();
- // normally we want to set mQsExpandImmediate for every split shade case (at least when
- // expanding), but keyguard tracking logic is different - this callback is called when
- // unlocking with swipe up but not when swiping down to reveal shade
- if (mShouldUseSplitNotificationShade && !mKeyguardShowing) {
- mQsExpandImmediate = true;
- }
if (mQsFullyExpanded) {
mQsExpandImmediate = true;
setShowShelfOnly(true);
@@ -3604,6 +3630,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
});
mLockscreenShadeTransitionController.setQS(mQs);
+ mShadeTransitionController.setQs(mQs);
mNotificationStackScrollLayoutController.setQsHeader((ViewGroup) mQs.getHeader());
mQs.setScrollListener(mScrollListener);
updateQsExpansion();
@@ -4921,6 +4948,12 @@ public class NotificationPanelViewController extends PanelViewController {
mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
if (state == STATE_OPENING) {
+ // we need to ignore it on keyguard as this is a false alarm - transition from unlocked
+ // to locked will trigger this event and we're not actually in the process of opening
+ // the shade, lockscreen is just always expanded
+ if (mShouldUseSplitNotificationShade && !isOnKeyguard()) {
+ mQsExpandImmediate = true;
+ }
mCentralSurfaces.makeExpandedVisible(false);
}
if (state == STATE_CLOSED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 9e707644782c..6637394e2b2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -108,6 +108,8 @@ public abstract class PanelViewController {
*/
private boolean mIsSpringBackAnimation;
+ private boolean mInSplitShade;
+
private void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
}
@@ -303,8 +305,9 @@ public abstract class PanelViewController {
mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
mHintDistance = mResources.getDimension(R.dimen.hint_move_distance);
mPanelFlingOvershootAmount = mResources.getDimension(R.dimen.panel_overshoot_amount);
- mUnlockFalsingThreshold = mResources.getDimensionPixelSize(
- R.dimen.unlock_falsing_threshold);
+ mUnlockFalsingThreshold =
+ mResources.getDimensionPixelSize(R.dimen.unlock_falsing_threshold);
+ mInSplitShade = mResources.getBoolean(R.bool.config_use_split_notification_shade);
}
protected float getTouchSlop(MotionEvent event) {
@@ -600,10 +603,12 @@ public abstract class PanelViewController {
}
mIsFlinging = true;
// we want to perform an overshoot animation when flinging open
- final boolean addOverscroll = expand
- && mStatusBarStateController.getState() != StatusBarState.KEYGUARD
- && mOverExpansion == 0.0f
- && vel >= 0;
+ final boolean addOverscroll =
+ expand
+ && !mInSplitShade // Split shade has its own overscroll logic
+ && mStatusBarStateController.getState() != StatusBarState.KEYGUARD
+ && mOverExpansion == 0.0f
+ && vel >= 0;
final boolean shouldSpringBack = addOverscroll || (mOverExpansion != 0.0f && expand);
float overshootAmount = 0.0f;
if (addOverscroll) {
@@ -777,7 +782,8 @@ public abstract class PanelViewController {
}
float maxPanelHeight = getMaxPanelHeight();
if (mHeightAnimator == null) {
- if (mTracking) {
+ // Split shade has its own overscroll logic
+ if (mTracking && !mInSplitShade) {
float overExpansionPixels = Math.max(0, h - maxPanelHeight);
setOverExpansionInternal(overExpansionPixels, true /* isFromGesture */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 052a4f7c5f7c..639be24ac46e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -390,6 +390,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
&& !mBouncer.isShowing() && !mBouncer.isAnimatingAway()) {
mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
}
+ } else if (!mShowing && mBouncer.inTransit()) {
+ // Keyguard is not visible anymore, but expansion animation was still running.
+ // We need to keep propagating the expansion state to the bouncer, otherwise it will be
+ // stuck in transit.
+ mBouncer.setExpansion(fraction);
} else if (mPulsing && fraction == KeyguardBouncer.EXPANSION_VISIBLE) {
// Panel expanded while pulsing but didn't translate the bouncer (because we are
// unlocked.) Let's simply wake-up to dismiss the lock screen.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt
index e29959290355..ca667dddbe8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt
@@ -17,7 +17,7 @@
package com.android.systemui.statusbar.phone.panelstate
/** A listener interface to be notified of state change events for the notification panel. */
-interface PanelStateListener {
+fun interface PanelStateListener {
/** Called when the panel's expansion state has changed. */
fun onPanelStateChanged(@PanelState state: Int)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/NoOpOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/NoOpOverScroller.kt
new file mode 100644
index 000000000000..2789db874249
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/NoOpOverScroller.kt
@@ -0,0 +1,14 @@
+package com.android.systemui.statusbar.phone.shade.transition
+
+import javax.inject.Inject
+
+/**
+ * An implementation on [ShadeOverScroller] that does nothing.
+ *
+ * At the moment there is only a concrete implementation [ShadeOverScroller] for split-shade, so
+ * this one is used when we are not in split-shade.
+ */
+class NoOpOverScroller @Inject constructor() : ShadeOverScroller {
+ override fun onPanelStateChanged(newPanelState: Int) {}
+ override fun onDragDownAmountChanged(newDragDownAmount: Float) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/ShadeOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/ShadeOverScroller.kt
new file mode 100644
index 000000000000..f1cedeb21e0a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/ShadeOverScroller.kt
@@ -0,0 +1,11 @@
+package com.android.systemui.statusbar.phone.shade.transition
+
+import com.android.systemui.statusbar.phone.panelstate.PanelState
+
+/** Represents an over scroller for the non-lockscreen shade. */
+interface ShadeOverScroller {
+
+ fun onPanelStateChanged(@PanelState newPanelState: Int)
+
+ fun onDragDownAmountChanged(newDragDownAmount: Float)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/ShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/ShadeTransitionController.kt
new file mode 100644
index 000000000000..2762b9a38e92
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/ShadeTransitionController.kt
@@ -0,0 +1,73 @@
+package com.android.systemui.statusbar.phone.shade.transition
+
+import android.content.Context
+import android.content.res.Configuration
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.NotificationPanelViewController
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import com.android.systemui.statusbar.phone.panelstate.PanelState
+import com.android.systemui.statusbar.policy.ConfigurationController
+import javax.inject.Inject
+
+/** Controls the shade expansion transition on non-lockscreen. */
+@SysUISingleton
+class ShadeTransitionController
+@Inject
+constructor(
+ configurationController: ConfigurationController,
+ panelExpansionStateManager: PanelExpansionStateManager,
+ private val context: Context,
+ private val splitShadeOverScrollerFactory: SplitShadeOverScroller.Factory,
+ private val noOpOverScroller: NoOpOverScroller
+) {
+
+ lateinit var notificationPanelViewController: NotificationPanelViewController
+ lateinit var notificationStackScrollLayoutController: NotificationStackScrollLayoutController
+ lateinit var qs: QS
+
+ private var inSplitShade = false
+
+ private val splitShadeOverScroller by lazy {
+ splitShadeOverScrollerFactory.create(qs, notificationStackScrollLayoutController)
+ }
+ private val shadeOverScroller: ShadeOverScroller
+ get() =
+ if (inSplitShade && propertiesInitialized()) {
+ splitShadeOverScroller
+ } else {
+ noOpOverScroller
+ }
+
+ init {
+ updateResources()
+ configurationController.addCallback(
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ updateResources()
+ }
+ })
+ panelExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
+ panelExpansionStateManager.addStateListener(this::onPanelStateChanged)
+ }
+
+ private fun updateResources() {
+ inSplitShade = context.resources.getBoolean(R.bool.config_use_split_notification_shade)
+ }
+
+ private fun onPanelStateChanged(@PanelState state: Int) {
+ shadeOverScroller.onPanelStateChanged(state)
+ }
+
+ private fun onPanelExpansionChanged(event: PanelExpansionChangeEvent) {
+ shadeOverScroller.onDragDownAmountChanged(event.dragDownPxAmount)
+ }
+
+ private fun propertiesInitialized() =
+ this::qs.isInitialized &&
+ this::notificationPanelViewController.isInitialized &&
+ this::notificationStackScrollLayoutController.isInitialized
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/SplitShadeOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/SplitShadeOverScroller.kt
new file mode 100644
index 000000000000..71050f2e7c67
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/shade/transition/SplitShadeOverScroller.kt
@@ -0,0 +1,142 @@
+package com.android.systemui.statusbar.phone.shade.transition
+
+import android.animation.Animator
+import android.animation.ValueAnimator
+import android.content.Context
+import android.content.res.Configuration
+import android.util.MathUtils
+import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.ScrimController
+import com.android.systemui.statusbar.phone.panelstate.PanelState
+import com.android.systemui.statusbar.phone.panelstate.STATE_CLOSED
+import com.android.systemui.statusbar.phone.panelstate.STATE_OPENING
+import com.android.systemui.statusbar.policy.ConfigurationController
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.io.PrintWriter
+
+class SplitShadeOverScroller
+@AssistedInject
+constructor(
+ configurationController: ConfigurationController,
+ dumpManager: DumpManager,
+ private val context: Context,
+ private val scrimController: ScrimController,
+ @Assisted private val qS: QS,
+ @Assisted private val nsslController: NotificationStackScrollLayoutController
+) : ShadeOverScroller {
+
+ private var releaseOverScrollDuration = 0L
+ private var maxOverScrollAmount = 0
+ private var previousOverscrollAmount = 0
+ private var dragDownAmount: Float = 0f
+ @PanelState private var panelState: Int = STATE_CLOSED
+ private var releaseOverScrollAnimator: Animator? = null
+
+ init {
+ updateResources()
+ configurationController.addCallback(
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ updateResources()
+ }
+ })
+ dumpManager.registerDumpable(this::dump)
+ }
+
+ private fun updateResources() {
+ val resources = context.resources
+ maxOverScrollAmount = resources.getDimensionPixelSize(R.dimen.shade_max_over_scroll_amount)
+ releaseOverScrollDuration =
+ resources.getInteger(R.integer.lockscreen_shade_over_scroll_release_duration).toLong()
+ }
+
+ override fun onPanelStateChanged(@PanelState newPanelState: Int) {
+ if (shouldReleaseOverscroll(previousState = panelState, newState = newPanelState)) {
+ releaseOverScroll()
+ }
+ panelState = newPanelState
+ }
+
+ override fun onDragDownAmountChanged(newDragDownAmount: Float) {
+ if (dragDownAmount == newDragDownAmount) {
+ return
+ }
+ dragDownAmount = newDragDownAmount
+ if (shouldOverscroll()) {
+ overScroll(newDragDownAmount)
+ }
+ }
+
+ private fun shouldOverscroll() = panelState == STATE_OPENING
+
+ private fun shouldReleaseOverscroll(@PanelState previousState: Int, @PanelState newState: Int) =
+ previousState == STATE_OPENING && newState != STATE_OPENING
+
+ private fun overScroll(dragDownAmount: Float) {
+ val overscrollAmount: Int = calculateOverscrollAmount(dragDownAmount)
+ applyOverscroll(overscrollAmount)
+ previousOverscrollAmount = overscrollAmount
+ }
+
+ private fun calculateOverscrollAmount(dragDownAmount: Float): Int {
+ val fullHeight: Int = nsslController.height
+ val fullHeightProgress: Float = MathUtils.saturate(dragDownAmount / fullHeight)
+ return (fullHeightProgress * maxOverScrollAmount).toInt()
+ }
+
+ private fun applyOverscroll(overscrollAmount: Int) {
+ qS.setOverScrollAmount(overscrollAmount)
+ scrimController.setNotificationsOverScrollAmount(overscrollAmount)
+ nsslController.setOverScrollAmount(overscrollAmount)
+ }
+
+ private fun releaseOverScroll() {
+ val animator = ValueAnimator.ofInt(previousOverscrollAmount, 0)
+ animator.addUpdateListener {
+ val overScrollAmount = it.animatedValue as Int
+ qS.setOverScrollAmount(overScrollAmount)
+ scrimController.setNotificationsOverScrollAmount(overScrollAmount)
+ nsslController.setOverScrollAmount(overScrollAmount)
+ }
+ animator.interpolator = Interpolators.STANDARD
+ animator.duration = releaseOverScrollDuration
+ animator.start()
+ releaseOverScrollAnimator = animator
+ previousOverscrollAmount = 0
+ }
+
+ @VisibleForTesting
+ internal fun finishAnimations() {
+ releaseOverScrollAnimator?.end()
+ releaseOverScrollAnimator = null
+ }
+
+ private fun dump(pw: PrintWriter, strings: Array<String>) {
+ pw.println(
+ """
+ SplitShadeOverScroller:
+ Resources:
+ releaseOverScrollDuration: $releaseOverScrollDuration
+ maxOverScrollAmount: $maxOverScrollAmount
+ State:
+ previousOverscrollAmount: $previousOverscrollAmount
+ dragDownAmount: $dragDownAmount
+ panelState: $panelState
+ """.trimIndent())
+ }
+
+ @AssistedFactory
+ fun interface Factory {
+ fun create(
+ qS: QS,
+ nsslController: NotificationStackScrollLayoutController
+ ): SplitShadeOverScroller
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index 2a9048a6eb73..169347a5ac1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -78,6 +78,7 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
private final UiEventLogger mUiEventLogger;
@VisibleForTesting
UserAvatarView mUserAvatarView;
+ private View mUserAvatarViewWithBackground;
UserSwitcherController.UserRecord mCurrentUser;
private boolean mIsKeyguardShowing;
@@ -167,6 +168,8 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
super.onInit();
if (DEBUG) Log.d(TAG, "onInit");
mUserAvatarView = mView.findViewById(R.id.kg_multi_user_avatar);
+ mUserAvatarViewWithBackground = mView.findViewById(
+ R.id.kg_multi_user_avatar_with_background);
mAdapter = new UserSwitcherController.BaseUserAdapter(mUserSwitcherController) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
@@ -186,7 +189,7 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
mUiEventLogger.log(
LockscreenGestureLogger.LockscreenUiEvent.LOCKSCREEN_SWITCH_USER_TAP);
- mUserSwitchDialogController.showDialog(mView);
+ mUserSwitchDialogController.showDialog(mUserAvatarViewWithBackground);
});
mUserAvatarView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 7920d388c670..a50d3d607aec 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -474,7 +474,7 @@ public class ThemeOverlayController extends CoreStartable implements Dumpable {
mThemeStyle = fetchThemeStyleFromSetting();
mSecondaryOverlay = getOverlay(mMainWallpaperColor, ACCENT, mThemeStyle);
mNeutralOverlay = getOverlay(mMainWallpaperColor, NEUTRAL, mThemeStyle);
- if (colorSchemeIsApplied()) {
+ if (colorSchemeIsApplied() && !forceReload) {
Log.d(TAG, "Skipping overlay creation. Theme was already: " + mColorScheme);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt b/packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt
new file mode 100644
index 000000000000..27a53bf2ceda
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt
@@ -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.systemui.util
+
+import android.content.res.TypedArray
+import android.graphics.Color
+import android.view.ContextThemeWrapper
+
+/** Returns an ARGB color version of [color] at the given [alpha]. */
+fun getColorWithAlpha(color: Int, alpha: Float): Int =
+ Color.argb(
+ (alpha * 255).toInt(),
+ Color.red(color),
+ Color.green(color),
+ Color.blue(color)
+ )
+
+
+/**
+ * Returns the color provided at the specified {@param attrIndex} in {@param a} if it exists,
+ * otherwise, returns the color from the private attribute {@param privAttrId}.
+ */
+fun getPrivateAttrColorIfUnset(
+ ctw: ContextThemeWrapper, attrArray: TypedArray,
+ attrIndex: Int, defColor: Int, privAttrId: Int
+): Int {
+ // If the index is specified, use that value
+ var a = attrArray
+ if (a.hasValue(attrIndex)) {
+ return a.getColor(attrIndex, defColor)
+ }
+
+ // Otherwise fallback to the value of the private attribute
+ val customAttrs = intArrayOf(privAttrId)
+ a = ctw.obtainStyledAttributes(customAttrs)
+ val color = a.getColor(0, defColor)
+ a.recycle()
+ return color
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 8e5e1d2e1b87..5b5dca30620a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -105,25 +105,6 @@ public class Utils {
}
/**
- * Returns the color provided at the specified {@param attrIndex} in {@param a} if it exists,
- * otherwise, returns the color from the private attribute {@param privAttrId}.
- */
- public static int getPrivateAttrColorIfUnset(ContextThemeWrapper ctw, TypedArray a,
- int attrIndex, int defColor, int privAttrId) {
- // If the index is specified, use that value
- if (a.hasValue(attrIndex)) {
- return a.getColor(attrIndex, defColor);
- }
-
- // Otherwise fallback to the value of the private attribute
- int[] customAttrs = { privAttrId };
- a = ctw.obtainStyledAttributes(customAttrs);
- int color = a.getColor(0, defColor);
- a.recycle();
- return color;
- }
-
- /**
* Gets the {@link R.dimen#status_bar_header_height_keyguard}.
*/
public static int getStatusBarHeaderHeightKeyguard(Context context) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
index 4beec574cd2a..01365b43b4b8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
@@ -70,7 +70,7 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase {
private Display mSecondaryDisplay;
// This display is in a different group from the default and secondary displays.
- private Display mDifferentGroupDisplay;
+ private Display mAlwaysUnlockedDisplay;
@Before
public void setUp() {
@@ -86,12 +86,12 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase {
Display.DEFAULT_DISPLAY + 1,
new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
- DisplayInfo differentGroupInfo = new DisplayInfo();
- differentGroupInfo.displayId = Display.DEFAULT_DISPLAY + 2;
- differentGroupInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
- mDifferentGroupDisplay = new Display(DisplayManagerGlobal.getInstance(),
+ DisplayInfo alwaysUnlockedDisplayInfo = new DisplayInfo();
+ alwaysUnlockedDisplayInfo.displayId = Display.DEFAULT_DISPLAY + 2;
+ alwaysUnlockedDisplayInfo.flags = Display.FLAG_ALWAYS_UNLOCKED;
+ mAlwaysUnlockedDisplay = new Display(DisplayManagerGlobal.getInstance(),
Display.DEFAULT_DISPLAY,
- differentGroupInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
+ alwaysUnlockedDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
}
@Test
@@ -110,18 +110,18 @@ public class KeyguardDisplayManagerTest extends SysuiTestCase {
}
@Test
- public void testShow_includeNonDefaultGroupDisplay() {
+ public void testShow_includeAlwaysUnlockedDisplay() {
when(mDisplayManager.getDisplays()).thenReturn(
- new Display[]{mDefaultDisplay, mDifferentGroupDisplay});
+ new Display[]{mDefaultDisplay, mAlwaysUnlockedDisplay});
mManager.show();
verify(mManager, never()).createPresentation(any());
}
@Test
- public void testShow_includeSecondaryAndNonDefaultGroupDisplays() {
+ public void testShow_includeSecondaryAndAlwaysUnlockedDisplays() {
when(mDisplayManager.getDisplays()).thenReturn(
- new Display[]{mDefaultDisplay, mSecondaryDisplay, mDifferentGroupDisplay});
+ new Display[]{mDefaultDisplay, mSecondaryDisplay, mAlwaysUnlockedDisplay});
mManager.show();
verify(mManager, times(1)).createPresentation(eq(mSecondaryDisplay));
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 1753157c631d..650a5d0a8712 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -22,7 +22,6 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -55,8 +54,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
@Mock
DozeParameters mDozeParameters;
@Mock
- KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
- @Mock
ScreenOffAnimationController mScreenOffAnimationController;
@Captor
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
@@ -75,7 +72,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
mKeyguardUpdateMonitor,
mConfigurationController,
mDozeParameters,
- mKeyguardUnlockAnimationController,
mScreenOffAnimationController);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt
index e62b4e63e3d5..55f0591b6ce0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt
@@ -142,6 +142,25 @@ class DisplayCutoutBaseViewTest : SysuiTestCase() {
assertThat(cutoutBaseView.protectionRect).isEqualTo(pathBounds)
}
+ @Test
+ fun testCutoutProtection_withDisplayRatio() {
+ setupDisplayCutoutBaseView(true /* fillCutout */, false /* hasCutout */)
+ whenever(cutoutBaseView.getPhysicalPixelDisplaySizeRatio()).thenReturn(0.5f)
+ val bounds = Rect(0, 0, 10, 10)
+ val path = Path()
+ val pathBounds = RectF(bounds)
+ path.addRect(pathBounds, Path.Direction.CCW)
+
+ context.mainExecutor.execute {
+ cutoutBaseView.setProtection(path, bounds)
+ cutoutBaseView.enableShowProtection(true)
+ }
+ waitForIdleSync()
+
+ assertThat(cutoutBaseView.protectionPath.isRect(pathBounds)).isTrue()
+ assertThat(cutoutBaseView.protectionRect).isEqualTo(RectF(0f, 0f, 5f, 5f))
+ }
+
private fun setupDisplayCutoutBaseView(fillCutout: Boolean, hasCutout: Boolean) {
mContext.orCreateTestableResources.addOverride(
R.array.config_displayUniqueIdArray, arrayOf<String>())
@@ -151,6 +170,7 @@ class DisplayCutoutBaseViewTest : SysuiTestCase() {
cutoutBaseView = spy(DisplayCutoutBaseView(mContext))
whenever(cutoutBaseView.display).thenReturn(mockDisplay)
whenever(cutoutBaseView.rootView).thenReturn(mockRootView)
+ whenever(cutoutBaseView.getPhysicalPixelDisplaySizeRatio()).thenReturn(1f)
whenever(mockDisplay.getDisplayInfo(eq(cutoutBaseView.displayInfo))
).then {
val info = it.getArgument<DisplayInfo>(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
index 23129d247ad5..6a9bb3e343be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -6,8 +6,10 @@ import android.testing.TestableLooper
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
+import android.widget.RelativeLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.children
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertNotNull
@@ -28,18 +30,11 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
private val TEST_INTERPOLATOR = Interpolators.LINEAR
}
- private val childParams = LinearLayout.LayoutParams(
- 0 /* width */,
- LinearLayout.LayoutParams.MATCH_PARENT
- )
- private lateinit var rootView: LinearLayout
+ private lateinit var rootView: ViewGroup
@Before
fun setUp() {
rootView = LinearLayout(mContext)
- rootView.orientation = LinearLayout.HORIZONTAL
- rootView.weightSum = 1f
- childParams.weight = 0.5f
}
@After
@@ -93,6 +88,19 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
animator = rootView.getTag(R.id.tag_animator) as ObjectAnimator
assertEquals(animator.interpolator, TEST_INTERPOLATOR)
assertEquals(animator.duration, TEST_DURATION)
+
+ // animateRemoval()
+ setUpRootWithChildren()
+ val child = rootView.getChildAt(0)
+ success = ViewHierarchyAnimator.animateRemoval(
+ child, interpolator = TEST_INTERPOLATOR, duration = TEST_DURATION
+ )
+
+ assertTrue(success)
+ assertNotNull(child.getTag(R.id.tag_animator))
+ animator = child.getTag(R.id.tag_animator) as ObjectAnimator
+ assertEquals(animator.interpolator, TEST_INTERPOLATOR)
+ assertEquals(animator.duration, TEST_DURATION)
}
@Test
@@ -170,17 +178,7 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
@Test
fun animatesRootAndChildren() {
- val firstChild = View(mContext)
- firstChild.layoutParams = childParams
- rootView.addView(firstChild)
- val secondChild = View(mContext)
- secondChild.layoutParams = childParams
- rootView.addView(secondChild)
- rootView.measure(
- View.MeasureSpec.makeMeasureSpec(150, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
- )
- rootView.layout(0 /* l */, 0 /* t */, 150 /* r */, 100 /* b */)
+ setUpRootWithChildren()
val success = ViewHierarchyAnimator.animate(rootView)
// Change all bounds.
@@ -192,20 +190,20 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
assertTrue(success)
assertNotNull(rootView.getTag(R.id.tag_animator))
- assertNotNull(firstChild.getTag(R.id.tag_animator))
- assertNotNull(secondChild.getTag(R.id.tag_animator))
+ assertNotNull(rootView.getChildAt(0).getTag(R.id.tag_animator))
+ assertNotNull(rootView.getChildAt(1).getTag(R.id.tag_animator))
// The initial values should be those of the previous layout.
- checkBounds(rootView, l = 0, t = 0, r = 150, b = 100)
- checkBounds(firstChild, l = 0, t = 0, r = 75, b = 100)
- checkBounds(secondChild, l = 75, t = 0, r = 150, b = 100)
+ checkBounds(rootView, l = 0, t = 0, r = 200, b = 100)
+ checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 100, b = 100)
+ checkBounds(rootView.getChildAt(1), l = 100, t = 0, r = 200, b = 100)
endAnimation(rootView)
assertNull(rootView.getTag(R.id.tag_animator))
- assertNull(firstChild.getTag(R.id.tag_animator))
- assertNull(secondChild.getTag(R.id.tag_animator))
+ assertNull(rootView.getChildAt(0).getTag(R.id.tag_animator))
+ assertNull(rootView.getChildAt(1).getTag(R.id.tag_animator))
// The end values should be those of the latest layout.
checkBounds(rootView, l = 10, t = 20, r = 200, b = 120)
- checkBounds(firstChild, l = 0, t = 0, r = 95, b = 100)
- checkBounds(secondChild, l = 95, t = 0, r = 190, b = 100)
+ checkBounds(rootView.getChildAt(0), l = 0, t = 0, r = 95, b = 100)
+ checkBounds(rootView.getChildAt(1), l = 95, t = 0, r = 190, b = 100)
}
@Test
@@ -522,6 +520,251 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
endAnimation(rootView)
}
+ fun animatesViewRemovalFromStartToEnd() {
+ setUpRootWithChildren()
+
+ val child = rootView.getChildAt(0)
+ val success = ViewHierarchyAnimator.animateRemoval(
+ child,
+ destination = ViewHierarchyAnimator.Hotspot.LEFT,
+ interpolator = Interpolators.LINEAR
+ )
+
+ assertTrue(success)
+ assertNotNull(child.getTag(R.id.tag_animator))
+ checkBounds(child, l = 0, t = 0, r = 100, b = 100)
+ advanceAnimation(child, 0.5f)
+ checkBounds(child, l = 0, t = 0, r = 50, b = 100)
+ advanceAnimation(child, 1.0f)
+ checkBounds(child, l = 0, t = 0, r = 0, b = 100)
+ endAnimation(rootView)
+ endAnimation(child)
+ assertEquals(1, rootView.childCount)
+ assertFalse(child in rootView.children)
+ }
+
+ @Test
+ fun animatesViewRemovalRespectingDestination() {
+ // CENTER
+ setUpRootWithChildren()
+ var removedChild = rootView.getChildAt(0)
+ var remainingChild = rootView.getChildAt(1)
+ var success = ViewHierarchyAnimator.animateRemoval(
+ removedChild, destination = ViewHierarchyAnimator.Hotspot.CENTER
+ )
+ // Ensure that the layout happens before the checks.
+ forceLayout()
+
+ assertTrue(success)
+ assertNotNull(removedChild.getTag(R.id.tag_animator))
+ advanceAnimation(removedChild, 1.0f)
+ checkBounds(removedChild, l = 50, t = 50, r = 50, b = 50)
+ endAnimation(rootView)
+ endAnimation(removedChild)
+ checkBounds(remainingChild, l = 0, t = 0, r = 100, b = 100)
+
+ // LEFT
+ setUpRootWithChildren()
+ removedChild = rootView.getChildAt(0)
+ remainingChild = rootView.getChildAt(1)
+ success = ViewHierarchyAnimator.animateRemoval(
+ removedChild, destination = ViewHierarchyAnimator.Hotspot.LEFT
+ )
+ // Ensure that the layout happens before the checks.
+ forceLayout()
+
+ assertTrue(success)
+ assertNotNull(removedChild.getTag(R.id.tag_animator))
+ advanceAnimation(removedChild, 1.0f)
+ checkBounds(removedChild, l = 0, t = 0, r = 0, b = 100)
+ endAnimation(rootView)
+ endAnimation(removedChild)
+ checkBounds(remainingChild, l = 0, t = 0, r = 100, b = 100)
+
+ // TOP_LEFT
+ setUpRootWithChildren()
+ removedChild = rootView.getChildAt(0)
+ remainingChild = rootView.getChildAt(1)
+ success = ViewHierarchyAnimator.animateRemoval(
+ removedChild, destination = ViewHierarchyAnimator.Hotspot.TOP_LEFT
+ )
+ // Ensure that the layout happens before the checks.
+ forceLayout()
+
+ assertTrue(success)
+ assertNotNull(removedChild.getTag(R.id.tag_animator))
+ advanceAnimation(removedChild, 1.0f)
+ checkBounds(removedChild, l = 0, t = 0, r = 0, b = 0)
+ endAnimation(rootView)
+ endAnimation(removedChild)
+ checkBounds(remainingChild, l = 0, t = 0, r = 100, b = 100)
+
+ // TOP
+ setUpRootWithChildren()
+ removedChild = rootView.getChildAt(0)
+ remainingChild = rootView.getChildAt(1)
+ success = ViewHierarchyAnimator.animateRemoval(
+ removedChild, destination = ViewHierarchyAnimator.Hotspot.TOP
+ )
+ // Ensure that the layout happens before the checks.
+ forceLayout()
+
+ assertTrue(success)
+ assertNotNull(removedChild.getTag(R.id.tag_animator))
+ advanceAnimation(removedChild, 1.0f)
+ checkBounds(removedChild, l = 0, t = 0, r = 100, b = 0)
+ endAnimation(rootView)
+ endAnimation(removedChild)
+ checkBounds(remainingChild, l = 0, t = 0, r = 100, b = 100)
+
+ // TOP_RIGHT
+ setUpRootWithChildren()
+ removedChild = rootView.getChildAt(0)
+ remainingChild = rootView.getChildAt(1)
+ success = ViewHierarchyAnimator.animateRemoval(
+ removedChild, destination = ViewHierarchyAnimator.Hotspot.TOP_RIGHT
+ )
+ // Ensure that the layout happens before the checks.
+ forceLayout()
+
+ assertTrue(success)
+ assertNotNull(removedChild.getTag(R.id.tag_animator))
+ advanceAnimation(removedChild, 1.0f)
+ checkBounds(removedChild, l = 100, t = 0, r = 100, b = 0)
+ endAnimation(rootView)
+ endAnimation(removedChild)
+ checkBounds(remainingChild, l = 0, t = 0, r = 100, b = 100)
+
+ // RIGHT
+ setUpRootWithChildren()
+ removedChild = rootView.getChildAt(0)
+ remainingChild = rootView.getChildAt(1)
+ success = ViewHierarchyAnimator.animateRemoval(
+ removedChild, destination = ViewHierarchyAnimator.Hotspot.RIGHT
+ )
+ // Ensure that the layout happens before the checks.
+ forceLayout()
+
+ assertTrue(success)
+ assertNotNull(removedChild.getTag(R.id.tag_animator))
+ advanceAnimation(removedChild, 1.0f)
+ checkBounds(removedChild, l = 100, t = 0, r = 100, b = 100)
+ endAnimation(rootView)
+ endAnimation(removedChild)
+ checkBounds(remainingChild, l = 0, t = 0, r = 100, b = 100)
+
+ // BOTTOM_RIGHT
+ setUpRootWithChildren()
+ removedChild = rootView.getChildAt(0)
+ remainingChild = rootView.getChildAt(1)
+ success = ViewHierarchyAnimator.animateRemoval(
+ removedChild, destination = ViewHierarchyAnimator.Hotspot.BOTTOM_RIGHT
+ )
+ // Ensure that the layout happens before the checks.
+ forceLayout()
+
+ assertTrue(success)
+ assertNotNull(removedChild.getTag(R.id.tag_animator))
+ advanceAnimation(removedChild, 1.0f)
+ checkBounds(removedChild, l = 100, t = 100, r = 100, b = 100)
+ endAnimation(rootView)
+ endAnimation(removedChild)
+ checkBounds(remainingChild, l = 0, t = 0, r = 100, b = 100)
+
+ // BOTTOM
+ setUpRootWithChildren()
+ removedChild = rootView.getChildAt(0)
+ remainingChild = rootView.getChildAt(1)
+ success = ViewHierarchyAnimator.animateRemoval(
+ removedChild, destination = ViewHierarchyAnimator.Hotspot.BOTTOM
+ )
+ // Ensure that the layout happens before the checks.
+ forceLayout()
+
+ assertTrue(success)
+ assertNotNull(removedChild.getTag(R.id.tag_animator))
+ advanceAnimation(removedChild, 1.0f)
+ checkBounds(removedChild, l = 0, t = 100, r = 100, b = 100)
+ endAnimation(rootView)
+ endAnimation(removedChild)
+ checkBounds(remainingChild, l = 0, t = 0, r = 100, b = 100)
+
+ // BOTTOM_LEFT
+ setUpRootWithChildren()
+ removedChild = rootView.getChildAt(0)
+ remainingChild = rootView.getChildAt(1)
+ success = ViewHierarchyAnimator.animateRemoval(
+ removedChild, destination = ViewHierarchyAnimator.Hotspot.BOTTOM_LEFT
+ )
+ // Ensure that the layout happens before the checks.
+ forceLayout()
+
+ assertTrue(success)
+ assertNotNull(removedChild.getTag(R.id.tag_animator))
+ advanceAnimation(removedChild, 1.0f)
+ checkBounds(removedChild, l = 0, t = 100, r = 0, b = 100)
+ endAnimation(rootView)
+ endAnimation(removedChild)
+ checkBounds(remainingChild, l = 0, t = 0, r = 100, b = 100)
+ }
+
+ @Test
+ fun animatesChildrenDuringViewRemoval() {
+ setUpRootWithChildren()
+
+ val child = rootView.getChildAt(0) as ViewGroup
+ val firstGrandChild = child.getChildAt(0)
+ val secondGrandChild = child.getChildAt(1)
+ val success = ViewHierarchyAnimator.animateRemoval(
+ child, interpolator = Interpolators.LINEAR
+ )
+
+ assertTrue(success)
+ assertNotNull(child.getTag(R.id.tag_animator))
+ assertNotNull(firstGrandChild.getTag(R.id.tag_animator))
+ assertNotNull(secondGrandChild.getTag(R.id.tag_animator))
+ checkBounds(child, l = 0, t = 0, r = 100, b = 100)
+ checkBounds(firstGrandChild, l = 0, t = 0, r = 40, b = 40)
+ checkBounds(secondGrandChild, l = 60, t = 60, r = 100, b = 100)
+
+ advanceAnimation(child, 0.5f)
+ checkBounds(child, l = 25, t = 25, r = 75, b = 75)
+ checkBounds(firstGrandChild, l = -10, t = -10, r = 30, b = 30)
+ checkBounds(secondGrandChild, l = 20, t = 20, r = 60, b = 60)
+
+ advanceAnimation(child, 1.0f)
+ checkBounds(child, l = 50, t = 50, r = 50, b = 50)
+ checkBounds(firstGrandChild, l = -20, t = -20, r = 20, b = 20)
+ checkBounds(secondGrandChild, l = -20, t = -20, r = 20, b = 20)
+
+ endAnimation(rootView)
+ endAnimation(child)
+ }
+
+ @Test
+ fun animatesSiblingsDuringViewRemoval() {
+ setUpRootWithChildren()
+
+ val removedChild = rootView.getChildAt(0)
+ val remainingChild = rootView.getChildAt(1)
+ val success = ViewHierarchyAnimator.animateRemoval(
+ removedChild, interpolator = Interpolators.LINEAR
+ )
+ // Ensure that the layout happens before the checks.
+ forceLayout()
+
+ assertTrue(success)
+ assertNotNull(remainingChild.getTag(R.id.tag_animator))
+ checkBounds(remainingChild, l = 100, t = 0, r = 200, b = 100)
+ advanceAnimation(rootView, 0.5f)
+ checkBounds(remainingChild, l = 50, t = 0, r = 150, b = 100)
+ advanceAnimation(rootView, 1.0f)
+ checkBounds(remainingChild, l = 0, t = 0, r = 100, b = 100)
+ endAnimation(rootView)
+ endAnimation(removedChild)
+ assertNull(remainingChild.getTag(R.id.tag_animator))
+ }
+
@Test
fun cleansUpListenersCorrectly() {
val firstChild = View(mContext)
@@ -700,6 +943,49 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
}
+ private fun setUpRootWithChildren() {
+ rootView = LinearLayout(mContext)
+ (rootView as LinearLayout).orientation = LinearLayout.HORIZONTAL
+ (rootView as LinearLayout).weightSum = 1f
+
+ val firstChild = RelativeLayout(mContext)
+ rootView.addView(firstChild)
+ val firstGrandChild = View(mContext)
+ firstChild.addView(firstGrandChild)
+ val secondGrandChild = View(mContext)
+ firstChild.addView(secondGrandChild)
+ val secondChild = View(mContext)
+ rootView.addView(secondChild)
+
+ val childParams = LinearLayout.LayoutParams(
+ 0 /* width */,
+ LinearLayout.LayoutParams.MATCH_PARENT
+ )
+ childParams.weight = 0.5f
+ firstChild.layoutParams = childParams
+ secondChild.layoutParams = childParams
+ firstGrandChild.layoutParams = RelativeLayout.LayoutParams(40 /* width */, 40 /* height */)
+ (firstGrandChild.layoutParams as RelativeLayout.LayoutParams)
+ .addRule(RelativeLayout.ALIGN_PARENT_START)
+ (firstGrandChild.layoutParams as RelativeLayout.LayoutParams)
+ .addRule(RelativeLayout.ALIGN_PARENT_TOP)
+ secondGrandChild.layoutParams = RelativeLayout.LayoutParams(40 /* width */, 40 /* height */)
+ (secondGrandChild.layoutParams as RelativeLayout.LayoutParams)
+ .addRule(RelativeLayout.ALIGN_PARENT_END)
+ (secondGrandChild.layoutParams as RelativeLayout.LayoutParams)
+ .addRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
+
+ forceLayout()
+ }
+
+ private fun forceLayout() {
+ rootView.measure(
+ View.MeasureSpec.makeMeasureSpec(200 /* width */, View.MeasureSpec.AT_MOST),
+ View.MeasureSpec.makeMeasureSpec(100 /* height */, View.MeasureSpec.AT_MOST)
+ )
+ rootView.layout(0 /* l */, 0 /* t */, 200 /* r */, 100 /* b */)
+ }
+
private fun checkBounds(v: View, l: Int, t: Int, r: Int, b: Int) {
assertEquals(l, v.left)
assertEquals(t, v.top)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
index fb1a968acceb..2d8c4d5dceb0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
@@ -17,6 +17,7 @@ import com.android.systemui.flags.FeatureFlags
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.policy.KeyguardStateController
import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
@@ -125,4 +126,69 @@ class KeyguardUnlockAnimationControllerTest : SysuiTestCase() {
verify(keyguardViewMediator, times(0)).onKeyguardExitRemoteAnimationFinished(
false /* cancelled */)
}
+
+ /**
+ * If we requested that the surface behind be made visible, and we're not flinging away the
+ * keyguard, it means that we're swiping to unlock and want the surface visible so it can follow
+ * the user's touch event as they swipe to unlock.
+ *
+ * In this case, we should verify that the surface was made visible via the alpha fade in
+ * animator, and verify that we did not start the canned animation to animate the surface in
+ * (since it's supposed to be following the touch events).
+ */
+ @Test
+ fun fadeInSurfaceBehind_ifRequestedShowSurface_butNotFlinging() {
+ `when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(false)
+
+ keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
+ remoteAnimationTarget,
+ 0 /* startTime */,
+ true /* requestedShowSurfaceBehindKeyguard */
+ )
+
+ assertTrue(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning)
+ assertFalse(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
+ }
+
+ /**
+ * We requested the surface behind to be made visible, but we're now flinging to dismiss the
+ * keyguard. This means this was a swipe to dismiss gesture but the user flung the keyguard and
+ * lifted their finger while we were requesting the surface be made visible.
+ *
+ * In this case, we should verify that we are playing the canned unlock animation and not
+ * simply fading in the surface.
+ */
+ @Test
+ fun playCannedUnlockAnimation_ifRequestedShowSurface_andFlinging() {
+ `when`(keyguardStateController.isFlingingToDismissKeyguard).thenReturn(true)
+
+ keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
+ remoteAnimationTarget,
+ 0 /* startTime */,
+ true /* requestedShowSurfaceBehindKeyguard */
+ )
+
+ assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
+ assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning)
+ }
+
+ /**
+ * We never requested the surface behind to be made visible, which means no swiping to unlock
+ * ever happened and we're just playing the simple canned animation (happens via UDFPS unlock,
+ * long press on the lock icon, etc).
+ *
+ * In this case, we should verify that we are playing the canned unlock animation and not
+ * simply fading in the surface.
+ */
+ @Test
+ fun playCannedUnlockAnimation_ifDidNotRequestShowSurface() {
+ keyguardUnlockAnimationController.notifyStartSurfaceBehindRemoteAnimation(
+ remoteAnimationTarget,
+ 0 /* startTime */,
+ false /* requestedShowSurfaceBehindKeyguard */
+ )
+
+ assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
+ assertFalse(keyguardUnlockAnimationController.surfaceBehindAlphaAnimator.isRunning)
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
index 8f967ab5294f..65d501442d87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
@@ -19,9 +19,9 @@ package com.android.systemui.media
import org.mockito.Mockito.`when` as whenever
import android.animation.ValueAnimator
import android.graphics.Color
-import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.monet.ColorScheme
import junit.framework.Assert.assertEquals
@@ -46,28 +46,35 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
private interface ExtractCB : (ColorScheme) -> Int
private interface ApplyCB : (Int) -> Unit
- private lateinit var colorTransition: ColorTransition
+ private lateinit var colorTransition: AnimatingColorTransition
private lateinit var colorSchemeTransition: ColorSchemeTransition
- @Mock private lateinit var mockTransition: ColorTransition
+ @Mock private lateinit var mockAnimatingTransition: AnimatingColorTransition
+ @Mock private lateinit var mockGenericTransition: GenericColorTransition
@Mock private lateinit var valueAnimator: ValueAnimator
@Mock private lateinit var colorScheme: ColorScheme
@Mock private lateinit var extractColor: ExtractCB
@Mock private lateinit var applyColor: ApplyCB
- private lateinit var transitionFactory: ColorTransitionFactory
+ private lateinit var animatingColorTransitionFactory: AnimatingColorTransitionFactory
+ private lateinit var genericColorTransitionFactory: GenericColorTransitionFactory
@Mock private lateinit var mediaViewHolder: MediaViewHolder
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
@Before
fun setUp() {
- transitionFactory = { default, extractColor, applyColor -> mockTransition }
+ animatingColorTransitionFactory = { _, _, _ -> mockAnimatingTransition }
+ genericColorTransitionFactory = { _ -> mockGenericTransition }
whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR)
- colorSchemeTransition = ColorSchemeTransition(context, mediaViewHolder, transitionFactory)
+ colorSchemeTransition = ColorSchemeTransition(
+ context, mediaViewHolder, animatingColorTransitionFactory, genericColorTransitionFactory
+ )
- colorTransition = object : ColorTransition(DEFAULT_COLOR, extractColor, applyColor) {
+ colorTransition = object : AnimatingColorTransition(
+ DEFAULT_COLOR, extractColor, applyColor
+ ) {
override fun buildAnimator(): ValueAnimator {
return valueAnimator
}
@@ -142,6 +149,7 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
@Test
fun testColorSchemeTransition_update() {
colorSchemeTransition.updateColorScheme(colorScheme)
- verify(mockTransition, times(6)).updateColorScheme(colorScheme)
+ verify(mockAnimatingTransition, times(6)).updateColorScheme(colorScheme)
+ verify(mockGenericTransition).updateColorScheme(colorScheme)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 6a9c3e349522..b8c85bb41726 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -25,8 +25,12 @@ import org.mockito.Mockito.`when` as whenever
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
import android.graphics.drawable.Animatable2
import android.graphics.drawable.AnimatedVectorDrawable
+import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.Icon
import android.graphics.drawable.RippleDrawable
@@ -124,7 +128,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var transitionParent: ViewGroup
private lateinit var appIcon: ImageView
- private lateinit var albumView: ImageView
+ @Mock private lateinit var albumView: ImageView
private lateinit var titleText: TextView
private lateinit var artistText: TextView
private lateinit var seamless: ViewGroup
@@ -296,7 +300,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
// Set up mock views for the players
appIcon = ImageView(context)
- albumView = ImageView(context)
titleText = TextView(context)
artistText = TextView(context)
seamless = FrameLayout(context)
@@ -416,7 +419,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(coverContainer1.context).thenReturn(mockContext)
whenever(coverContainer2.context).thenReturn(mockContext)
whenever(coverContainer3.context).thenReturn(mockContext)
-
}
@After
@@ -537,6 +539,60 @@ public class MediaControlPanelTest : SysuiTestCase() {
}
@Test
+ fun bindAlbumView_setAfterExecutors() {
+ val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(bmp)
+ canvas.drawColor(Color.RED)
+ val albumArt = Icon.createWithBitmap(bmp)
+ val state = mediaData.copy(artwork = albumArt)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(state, PACKAGE)
+ bgExecutor.runAllReady()
+ mainExecutor.runAllReady()
+
+ verify(albumView).setImageDrawable(any(Drawable::class.java))
+ }
+
+ @Test
+ fun bindAlbumView_bitmapInLaterStates_setAfterExecutors() {
+ val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(bmp)
+ canvas.drawColor(Color.RED)
+ val albumArt = Icon.createWithBitmap(bmp)
+
+ val state0 = mediaData.copy(artwork = null)
+ val state1 = mediaData.copy(artwork = albumArt)
+ val state2 = mediaData.copy(artwork = albumArt)
+ player.attachPlayer(viewHolder)
+
+ // First binding sets (empty) drawable
+ player.bindPlayer(state0, PACKAGE)
+ bgExecutor.runAllReady()
+ mainExecutor.runAllReady()
+ verify(albumView).setImageDrawable(any(Drawable::class.java))
+
+ // Run Metadata update so that later states don't update
+ val captor = argumentCaptor<Animator.AnimatorListener>()
+ verify(mockAnimator, times(2)).addListener(captor.capture())
+ captor.value.onAnimationEnd(mockAnimator)
+ assertThat(titleText.getText()).isEqualTo(TITLE)
+ assertThat(artistText.getText()).isEqualTo(ARTIST)
+
+ // Second binding sets transition drawable
+ player.bindPlayer(state1, PACKAGE)
+ bgExecutor.runAllReady()
+ mainExecutor.runAllReady()
+ verify(albumView, times(2)).setImageDrawable(any(Drawable::class.java))
+
+ // Third binding does run transition or update background
+ player.bindPlayer(state2, PACKAGE)
+ bgExecutor.runAllReady()
+ mainExecutor.runAllReady()
+ verify(albumView, times(2)).setImageDrawable(any(Drawable::class.java))
+ }
+
+ @Test
fun bind_seekBarDisabled_hasActions_seekBarVisibilityIsSetToInvisible() {
useRealConstraintSets()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 0cbceb6700b4..333e148475df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -30,6 +30,7 @@ import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
@@ -47,6 +48,7 @@ import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.junit.MockitoJUnit
@@ -938,6 +940,38 @@ class MediaDataManagerTest : SysuiTestCase() {
eq(instanceId), eq(MediaData.PLAYBACK_CAST_REMOTE))
}
+ @Test
+ fun testPlaybackStateChange_keyExists_callsListener() {
+ // Notification has been added
+ addNotificationAndLoad()
+ val callbackCaptor = argumentCaptor<(String, PlaybackState) -> Unit>()
+ verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
+
+ // Callback gets an updated state
+ val state = PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PLAYING, 0L, 1f)
+ .build()
+ callbackCaptor.value.invoke(KEY, state)
+
+ // Listener is notified of updated state
+ verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY),
+ capture(mediaDataCaptor), eq(true), eq(0), eq(false))
+ assertThat(mediaDataCaptor.value.isPlaying).isTrue()
+ }
+
+ @Test
+ fun testPlaybackStateChange_keyDoesNotExist_doesNothing() {
+ val state = PlaybackState.Builder().build()
+ val callbackCaptor = argumentCaptor<(String, PlaybackState) -> Unit>()
+ verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
+
+ // No media added with this key
+
+ callbackCaptor.value.invoke(KEY, state)
+ verify(listener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(), anyInt(),
+ anyBoolean())
+ }
+
/**
* Helper function to add a media notification and capture the resulting MediaData
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
index 60cbb1754db6..91c0cc2ff891 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -65,6 +65,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Mock private lateinit var logger: MediaTimeoutLogger
private lateinit var executor: FakeExecutor
@Mock private lateinit var timeoutCallback: (String, Boolean) -> Unit
+ @Mock private lateinit var stateCallback: (String, PlaybackState) -> Unit
@Captor private lateinit var mediaCallbackCaptor: ArgumentCaptor<MediaController.Callback>
@JvmField @Rule val mockito = MockitoJUnit.rule()
private lateinit var metadataBuilder: MediaMetadata.Builder
@@ -80,6 +81,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
executor = FakeExecutor(FakeSystemClock())
mediaTimeoutListener = MediaTimeoutListener(mediaControllerFactory, executor, logger)
mediaTimeoutListener.timeoutCallback = timeoutCallback
+ mediaTimeoutListener.stateCallback = stateCallback
// Create a media session and notification for testing.
metadataBuilder = MediaMetadata.Builder().apply {
@@ -368,4 +370,169 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
// THEN the timeout runnable is cancelled
assertThat(executor.numPending()).isEqualTo(0)
}
+
+ @Test
+ fun testOnMediaDataLoaded_playbackActionsChanged_noCallback() {
+ // Load media data once
+ val pausedState = PlaybackState.Builder()
+ .setActions(PlaybackState.ACTION_PAUSE)
+ .build()
+ loadMediaDataWithPlaybackState(pausedState)
+
+ // When media data is loaded again, with different actions
+ val playingState = PlaybackState.Builder()
+ .setActions(PlaybackState.ACTION_PLAY)
+ .build()
+ loadMediaDataWithPlaybackState(playingState)
+
+ // Then the callback is not invoked
+ verify(stateCallback, never()).invoke(eq(KEY), any())
+ }
+
+ @Test
+ fun testOnPlaybackStateChanged_playbackActionsChanged_sendsCallback() {
+ // Load media data once
+ val pausedState = PlaybackState.Builder()
+ .setActions(PlaybackState.ACTION_PAUSE)
+ .build()
+ loadMediaDataWithPlaybackState(pausedState)
+
+ // When the playback state changes, and has different actions
+ val playingState = PlaybackState.Builder()
+ .setActions(PlaybackState.ACTION_PLAY)
+ .build()
+ mediaCallbackCaptor.value.onPlaybackStateChanged(playingState)
+
+ // Then the callback is invoked
+ verify(stateCallback).invoke(eq(KEY), eq(playingState!!))
+ }
+
+ @Test
+ fun testOnPlaybackStateChanged_differentCustomActions_sendsCallback() {
+ val customOne = PlaybackState.CustomAction.Builder(
+ "ACTION_1",
+ "custom action 1",
+ android.R.drawable.ic_media_ff)
+ .build()
+ val pausedState = PlaybackState.Builder()
+ .setActions(PlaybackState.ACTION_PAUSE)
+ .addCustomAction(customOne)
+ .build()
+ loadMediaDataWithPlaybackState(pausedState)
+
+ // When the playback state actions change
+ val customTwo = PlaybackState.CustomAction.Builder(
+ "ACTION_2",
+ "custom action 2",
+ android.R.drawable.ic_media_rew)
+ .build()
+ val pausedStateTwoActions = PlaybackState.Builder()
+ .setActions(PlaybackState.ACTION_PAUSE)
+ .addCustomAction(customOne)
+ .addCustomAction(customTwo)
+ .build()
+ mediaCallbackCaptor.value.onPlaybackStateChanged(pausedStateTwoActions)
+
+ // Then the callback is invoked
+ verify(stateCallback).invoke(eq(KEY), eq(pausedStateTwoActions!!))
+ }
+
+ @Test
+ fun testOnPlaybackStateChanged_sameActions_noCallback() {
+ val stateWithActions = PlaybackState.Builder()
+ .setActions(PlaybackState.ACTION_PLAY)
+ .build()
+ loadMediaDataWithPlaybackState(stateWithActions)
+
+ // When the playback state updates with the same actions
+ mediaCallbackCaptor.value.onPlaybackStateChanged(stateWithActions)
+
+ // Then the callback is not invoked again
+ verify(stateCallback, never()).invoke(eq(KEY), any())
+ }
+
+ @Test
+ fun testOnPlaybackStateChanged_sameCustomActions_noCallback() {
+ val actionName = "custom action"
+ val actionIcon = android.R.drawable.ic_media_ff
+ val customOne = PlaybackState.CustomAction.Builder(actionName, actionName, actionIcon)
+ .build()
+ val stateOne = PlaybackState.Builder()
+ .setActions(PlaybackState.ACTION_PAUSE)
+ .addCustomAction(customOne)
+ .build()
+ loadMediaDataWithPlaybackState(stateOne)
+
+ // When the playback state is updated, but has the same actions
+ val customTwo = PlaybackState.CustomAction.Builder(actionName, actionName, actionIcon)
+ .build()
+ val stateTwo = PlaybackState.Builder()
+ .setActions(PlaybackState.ACTION_PAUSE)
+ .addCustomAction(customTwo)
+ .build()
+ mediaCallbackCaptor.value.onPlaybackStateChanged(stateTwo)
+
+ // Then the callback is not invoked
+ verify(stateCallback, never()).invoke(eq(KEY), any())
+ }
+
+ @Test
+ fun testOnMediaDataLoaded_isPlayingChanged_noCallback() {
+ // Load media data in paused state
+ val pausedState = PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PAUSED, 0L, 0f)
+ .build()
+ loadMediaDataWithPlaybackState(pausedState)
+
+ // When media data is loaded again but playing
+ val playingState = PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PLAYING, 0L, 1f)
+ .build()
+ loadMediaDataWithPlaybackState(playingState)
+
+ // Then the callback is not invoked
+ verify(stateCallback, never()).invoke(eq(KEY), any())
+ }
+
+ @Test
+ fun testOnPlaybackStateChanged_isPlayingChanged_sendsCallback() {
+ // Load media data in paused state
+ val pausedState = PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PAUSED, 0L, 0f)
+ .build()
+ loadMediaDataWithPlaybackState(pausedState)
+
+ // When the playback state changes to playing
+ val playingState = PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PLAYING, 0L, 1f)
+ .build()
+ mediaCallbackCaptor.value.onPlaybackStateChanged(playingState)
+
+ // Then the callback is invoked
+ verify(stateCallback).invoke(eq(KEY), eq(playingState!!))
+ }
+
+ @Test
+ fun testOnPlaybackStateChanged_isPlayingSame_noCallback() {
+ // Load media data in paused state
+ val pausedState = PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PAUSED, 0L, 0f)
+ .build()
+ loadMediaDataWithPlaybackState(pausedState)
+
+ // When the playback state is updated, but still not playing
+ val playingState = PlaybackState.Builder()
+ .setState(PlaybackState.STATE_STOPPED, 0L, 0f)
+ .build()
+ mediaCallbackCaptor.value.onPlaybackStateChanged(playingState)
+
+ // Then the callback is not invoked
+ verify(stateCallback, never()).invoke(eq(KEY), eq(playingState!!))
+ }
+
+ private fun loadMediaDataWithPlaybackState(state: PlaybackState) {
+ `when`(mediaController.playbackState).thenReturn(state)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
+ verify(mediaController).registerCallback(capture(mediaCallbackCaptor))
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
index 51088b1d929b..863484b62a00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
@@ -62,6 +62,16 @@ public class ColorSchemeTest extends SysuiTestCase {
Assert.assertEquals(rankedSeedColors, List.of(0xffaec00a));
}
+ @Test
+ public void testStyleApplied() {
+ WallpaperColors wallpaperColors = new WallpaperColors(Color.valueOf(0xffaec00a),
+ null, null);
+ // Expressive applies hue rotations to the theme color. The input theme color has hue
+ // 117, ensuring the hue changed significantly is a strong signal styles are being applied.
+ ColorScheme colorScheme = new ColorScheme(wallpaperColors, false, Style.EXPRESSIVE);
+ Assert.assertEquals(Cam.fromInt(colorScheme.getAccent1().get(6)).getHue(), 357.46, 0.1);
+ }
+
@Test
public void testFiltersInvalidColors() {
@@ -123,7 +133,7 @@ public class ColorSchemeTest extends SysuiTestCase {
Style.VIBRANT /* style */);
int neutralMid = colorScheme.getNeutral1().get(colorScheme.getNeutral1().size() / 2);
Cam cam = Cam.fromInt(neutralMid);
- Assert.assertTrue(cam.getChroma() <= 8.0);
+ Assert.assertTrue("chroma was " + cam.getChroma(), Math.floor(cam.getChroma()) <= 10.0);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
index c714fa0e5b27..1d687b141d1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
@@ -35,6 +35,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import android.content.Intent
+import android.text.TextUtils
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -373,4 +374,31 @@ class PrivacyDialogTest : SysuiTestCase() {
)
)
}
+
+ @Test
+ fun testDialogHasTitle() {
+ // Dialog must have a non-empty title for a11y purposes.
+
+ val list = listOf(
+ PrivacyDialog.PrivacyElement(
+ PrivacyType.TYPE_MICROPHONE,
+ TEST_PACKAGE_NAME,
+ TEST_USER_ID,
+ "App",
+ null,
+ null,
+ null,
+ 0L,
+ false,
+ false,
+ false,
+ TEST_PERM_GROUP,
+ null
+ )
+ )
+ dialog = PrivacyDialog(context, list, starter)
+ dialog.show()
+
+ assertThat(TextUtils.isEmpty(dialog.window?.attributes?.title)).isFalse()
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 633a9c3a03d8..4a8cb0b76dc4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -138,6 +138,8 @@ public class InternetDialogControllerTest extends SysuiTestCase {
private DialogLaunchAnimator mDialogLaunchAnimator;
@Mock
private View mDialogLaunchView;
+ @Mock
+ private WifiStateWorker mWifiStateWorker;
private TestableResources mTestableResources;
private InternetDialogController mInternetDialogController;
@@ -166,6 +168,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
when(mSystemUIToast.getView()).thenReturn(mToastView);
when(mSystemUIToast.getGravity()).thenReturn(GRAVITY_FLAGS);
when(mSystemUIToast.getInAnimation()).thenReturn(mAnimator);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
mInternetDialogController = new InternetDialogController(mContext,
mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController,
@@ -173,7 +176,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher,
mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController,
mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker,
- mLocationController, mDialogLaunchAnimator);
+ mLocationController, mDialogLaunchAnimator, mWifiStateWorker);
mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
mInternetDialogController.mOnSubscriptionsChangedListener);
mInternetDialogController.onStart(mInternetDialogCallback, true);
@@ -239,7 +242,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
@Test
public void getSubtitleText_withApmOnAndWifiOff_returnWifiIsOff() {
fakeAirplaneModeEnabled(true);
- when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(false);
assertThat(mInternetDialogController.getSubtitleText(false))
.isEqualTo(getResourcesString("wifi_is_off"));
@@ -254,7 +257,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
@Test
public void getSubtitleText_withWifiOff_returnWifiIsOff() {
fakeAirplaneModeEnabled(false);
- when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(false);
assertThat(mInternetDialogController.getSubtitleText(false))
.isEqualTo(getResourcesString("wifi_is_off"));
@@ -269,7 +272,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
@Test
public void getSubtitleText_withNoWifiEntry_returnSearchWifi() {
fakeAirplaneModeEnabled(false);
- when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
assertThat(mInternetDialogController.getSubtitleText(true))
@@ -286,7 +289,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
public void getSubtitleText_withWifiEntry_returnTapToConnect() {
// The preconditions WiFi Entries is already in setUp()
fakeAirplaneModeEnabled(false);
- when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
assertThat(mInternetDialogController.getSubtitleText(false))
.isEqualTo(getResourcesString("tap_a_network_to_connect"));
@@ -301,7 +304,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
@Test
public void getSubtitleText_deviceLockedWithWifiOn_returnUnlockToViewNetworks() {
fakeAirplaneModeEnabled(false);
- when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
@@ -311,7 +314,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
@Test
public void getSubtitleText_withNoService_returnNoNetworksAvailable() {
fakeAirplaneModeEnabled(false);
- when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState();
@@ -325,7 +328,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
@Test
public void getSubtitleText_withMobileDataDisabled_returnNoOtherAvailable() {
fakeAirplaneModeEnabled(false);
- when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState();
@@ -346,7 +349,7 @@ public class InternetDialogControllerTest extends SysuiTestCase {
@Test
public void getSubtitleText_withCarrierNetworkActiveOnly_returnNoOtherAvailable() {
fakeAirplaneModeEnabled(false);
- when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
when(mMergedCarrierEntry.isDefaultNetwork()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index 616f89455c74..d09a5a11040f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -14,7 +14,6 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.net.wifi.WifiManager;
import android.os.Handler;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
@@ -64,8 +63,6 @@ public class InternetDialogTest extends SysuiTestCase {
@Mock
private TelephonyManager mTelephonyManager;
@Mock
- private WifiManager mWifiManager;
- @Mock
private WifiEntry mInternetWifiEntry;
@Mock
private List<WifiEntry> mWifiEntries;
@@ -97,7 +94,6 @@ public class InternetDialogTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
- when(mWifiManager.isWifiEnabled()).thenReturn(true);
when(mInternetWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
@@ -107,7 +103,7 @@ public class InternetDialogTest extends SysuiTestCase {
when(mInternetDialogController.getMobileNetworkTitle()).thenReturn(MOBILE_NETWORK_TITLE);
when(mInternetDialogController.getMobileNetworkSummary())
.thenReturn(MOBILE_NETWORK_SUMMARY);
- when(mInternetDialogController.getWifiManager()).thenReturn(mWifiManager);
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
mMockitoSession = ExtendedMockito.mockitoSession()
.spyStatic(WifiEnterpriseRestrictionUtils.class)
@@ -232,7 +228,7 @@ public class InternetDialogTest extends SysuiTestCase {
// Carrier network should be gone if airplane mode ON and Wi-Fi is off.
when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
- when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
mInternetDialog.updateDialog(true);
@@ -241,7 +237,7 @@ public class InternetDialogTest extends SysuiTestCase {
// Carrier network should be visible if airplane mode ON and Wi-Fi is ON.
when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
- when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
mInternetDialog.updateDialog(true);
@@ -468,7 +464,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void updateDialog_wifiOffAndWifiScanOff_hideWifiScanNotify() {
- when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
when(mInternetDialogController.isWifiScanEnabled()).thenReturn(false);
mInternetDialog.updateDialog(false);
@@ -478,7 +474,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void updateDialog_wifiOffAndWifiScanOnAndDeviceLocked_hideWifiScanNotify() {
- when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true);
when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
@@ -489,7 +485,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void updateDialog_wifiOffAndWifiScanOnAndDeviceUnlocked_showWifiScanNotify() {
- when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true);
when(mInternetDialogController.isDeviceLocked()).thenReturn(false);
@@ -502,6 +498,26 @@ public class InternetDialogTest extends SysuiTestCase {
}
@Test
+ public void updateDialog_wifiIsDisabled_uncheckWifiSwitch() {
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
+ mWifiToggleSwitch.setChecked(true);
+
+ mInternetDialog.updateDialog(false);
+
+ assertThat(mWifiToggleSwitch.isChecked()).isFalse();
+ }
+
+ @Test
+ public void updateDialog_wifiIsEnabled_checkWifiSwitch() {
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
+ mWifiToggleSwitch.setChecked(false);
+
+ mInternetDialog.updateDialog(false);
+
+ assertThat(mWifiToggleSwitch.isChecked()).isTrue();
+ }
+
+ @Test
public void onClickSeeMoreButton_clickSeeAll_verifyLaunchNetworkSetting() {
mSeeAll.performClick();
@@ -512,7 +528,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void showProgressBar_wifiDisabled_hideProgressBar() {
Mockito.reset(mHandler);
- when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
mInternetDialog.showProgressBar();
@@ -534,7 +550,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void showProgressBar_wifiEnabledWithWifiEntry_showProgressBarThenHide() {
Mockito.reset(mHandler);
- when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
mInternetDialog.showProgressBar();
@@ -553,7 +569,7 @@ public class InternetDialogTest extends SysuiTestCase {
@Test
public void showProgressBar_wifiEnabledWithoutWifiEntries_showProgressBarThenHideSearch() {
Mockito.reset(mHandler);
- when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
mInternetDialog.mConnectedWifiEntry = null;
mInternetDialog.mWifiEntriesCount = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/WifiStateWorkerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/WifiStateWorkerTest.java
new file mode 100644
index 000000000000..5d7ba7bc673d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/WifiStateWorkerTest.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.dialog;
+
+import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE;
+import static android.net.wifi.WifiManager.WIFI_STATE_CHANGED_ACTION;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.net.wifi.WifiManager;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+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;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class WifiStateWorkerTest extends SysuiTestCase {
+
+ @Rule
+ public MockitoRule mRule = MockitoJUnit.rule();
+ @Mock
+ private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private WifiManager mWifiManager;
+ @Mock
+ private Intent mIntent;
+
+ private WifiStateWorker mWifiStateWorker;
+ private FakeExecutor mBackgroundExecutor = new FakeExecutor(new FakeSystemClock());
+
+ @Before
+ public void setup() {
+ when(mWifiManager.setWifiEnabled(anyBoolean())).thenReturn(true);
+ when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLED);
+ when(mIntent.getAction()).thenReturn(WIFI_STATE_CHANGED_ACTION);
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_ENABLED);
+
+ mWifiStateWorker = new WifiStateWorker(mBroadcastDispatcher, mBackgroundExecutor,
+ mWifiManager);
+ mBackgroundExecutor.runAllReady();
+ }
+
+ @Test
+ public void constructor_shouldGetWifiState() {
+ verify(mWifiManager).getWifiState();
+ }
+
+ @Test
+ public void setWifiEnabled_wifiManagerIsNull_shouldNotSetWifiEnabled() {
+ mWifiStateWorker = new WifiStateWorker(mBroadcastDispatcher, mBackgroundExecutor,
+ null /* wifiManager */);
+
+ mWifiStateWorker.setWifiEnabled(true);
+ mBackgroundExecutor.runAllReady();
+
+ verify(mWifiManager, never()).setWifiEnabled(anyBoolean());
+ }
+
+ @Test
+ public void setWifiEnabled_enabledIsTrue_shouldSetWifiEnabled() {
+ mWifiStateWorker.setWifiEnabled(true);
+ mBackgroundExecutor.runAllReady();
+
+ verify(mWifiManager).setWifiEnabled(true);
+ }
+
+ @Test
+ public void setWifiEnabled_enabledIsFalse_shouldSetWifiDisabled() {
+ mWifiStateWorker.setWifiEnabled(false);
+ mBackgroundExecutor.runAllReady();
+
+ verify(mWifiManager).setWifiEnabled(false);
+ }
+
+ @Test
+ public void getWifiState_receiveWifiStateDisabling_getWifiStateDisabling() {
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_DISABLING);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_DISABLING);
+ }
+
+ @Test
+ public void getWifiState_receiveWifiStateDisabled_getWifiStateDisabled() {
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_DISABLED);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_DISABLED);
+ }
+
+ @Test
+ public void getWifiState_receiveWifiStateEnabling_getWifiStateEnabling() {
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_ENABLING);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_ENABLING);
+ }
+
+ @Test
+ public void getWifiState_receiveWifiStateEnabled_getWifiStateEnabled() {
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_ENABLED);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_ENABLED);
+ }
+
+ @Test
+ public void getWifiState_receiveWifiStateUnknown_ignoreTheIntent() {
+ // Update the Wi-Fi state to WIFI_STATE_DISABLED
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_DISABLED);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_DISABLED);
+
+ // Receiver WIFI_STATE_UNKNOWN
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_UNKNOWN);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+
+ // Ignore the intent and keep the Wi-Fi state to WIFI_STATE_DISABLED
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_DISABLED);
+
+ // Update the Wi-Fi state to WIFI_STATE_ENABLED
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_ENABLED);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_ENABLED);
+
+ // Receiver WIFI_STATE_UNKNOWN change
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_UNKNOWN);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+
+ // Ignore the intent and keep the Wi-Fi state to WIFI_STATE_ENABLED
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_ENABLED);
+ }
+
+ @Test
+ public void isWifiEnabled_receiveWifiStateDisabling_returnFalse() {
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_DISABLING);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+
+ assertThat(mWifiStateWorker.isWifiEnabled()).isFalse();
+ }
+
+ @Test
+ public void isWifiEnabled_receiveWifiStateDisabled_returnFalse() {
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_DISABLED);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+
+ assertThat(mWifiStateWorker.isWifiEnabled()).isFalse();
+ }
+
+ @Test
+ public void isWifiEnabled_receiveWifiStateEnabling_returnTrue() {
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_ENABLING);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+
+ assertThat(mWifiStateWorker.isWifiEnabled()).isTrue();
+ }
+
+ @Test
+ public void isWifiEnabled_receiveWifiStateEnabled_returnTrue() {
+ when(mIntent.getIntExtra(eq(EXTRA_WIFI_STATE), anyInt())).thenReturn(WIFI_STATE_ENABLED);
+ mWifiStateWorker.onReceive(mContext, mIntent);
+
+ assertThat(mWifiStateWorker.isWifiEnabled()).isTrue();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index ce58a6c82142..64aa7fb57da8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -128,6 +128,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
private val execution = FakeExecution()
private val fakeParent = FrameLayout(context)
private val fakePrivateLockscreenSettingUri = Uri.Builder().appendPath("test").build()
+ private val fakeNotifOnLockscreenSettingUri = Uri.Builder().appendPath("notif").build()
private val userHandlePrimary: UserHandle = UserHandle(0)
private val userHandleManaged: UserHandle = UserHandle(2)
@@ -149,6 +150,8 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
`when`(secureSettings.getUriFor(PRIVATE_LOCKSCREEN_SETTING))
.thenReturn(fakePrivateLockscreenSettingUri)
+ `when`(secureSettings.getUriFor(NOTIF_ON_LOCKSCREEN_SETTING))
+ .thenReturn(fakeNotifOnLockscreenSettingUri)
`when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(smartspaceSession)
`when`(plugin.getView(any())).thenReturn(createSmartspaceView(), createSmartspaceView())
`when`(userTracker.userProfiles).thenReturn(userList)
@@ -160,6 +163,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
setAllowPrivateNotifications(userHandlePrimary, true)
setAllowPrivateNotifications(userHandleManaged, true)
setAllowPrivateNotifications(userHandleSecondary, true)
+ setShowNotifications(userHandlePrimary, true)
controller = LockscreenSmartspaceController(
context,
@@ -341,6 +345,26 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
}
@Test
+ fun testAllTargetsAreFilteredExceptWeatherWhenNotificationsAreDisabled() {
+ // GIVEN the active user doesn't allow any notifications on lockscreen
+ setShowNotifications(userHandlePrimary, false)
+ connectSession()
+
+ // WHEN we receive a list of targets
+ val targets = listOf(
+ makeTarget(1, userHandlePrimary, isSensitive = true),
+ makeTarget(2, userHandlePrimary),
+ makeTarget(3, userHandleManaged),
+ makeTarget(4, userHandlePrimary, featureType = SmartspaceTarget.FEATURE_WEATHER)
+ )
+
+ sessionListener.onTargetsAvailable(targets)
+
+ // THEN all non-sensitive content is still shown
+ verify(plugin).onTargetsAvailable(eq(listOf(targets[3])))
+ }
+
+ @Test
fun testSensitiveTargetsAreFilteredOutForAppropriateUsers() {
// GIVEN the active and managed users don't allow sensitive lockscreen content
setAllowPrivateNotifications(userHandlePrimary, false)
@@ -391,6 +415,7 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
fun testRecognizeSwitchToSecondaryUser() {
// GIVEN an inactive secondary user that doesn't allow sensitive content
setAllowPrivateNotifications(userHandleSecondary, false)
+ setShowNotifications(userHandleSecondary, true)
connectSession()
// WHEN the secondary user becomes the active user
@@ -518,13 +543,15 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
fun makeTarget(
id: Int,
userHandle: UserHandle,
- isSensitive: Boolean = false
+ isSensitive: Boolean = false,
+ featureType: Int = 0
): SmartspaceTarget {
return SmartspaceTarget.Builder(
"target$id",
ComponentName("testpackage", "testclass$id"),
userHandle)
.setSensitive(isSensitive)
+ .setFeatureType(featureType)
.build()
}
@@ -536,6 +563,14 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
).thenReturn(if (value) 1 else 0)
}
+ private fun setShowNotifications(user: UserHandle, value: Boolean) {
+ `when`(secureSettings.getIntForUser(
+ eq(NOTIF_ON_LOCKSCREEN_SETTING),
+ anyInt(),
+ eq(user.identifier))
+ ).thenReturn(if (value) 1 else 0)
+ }
+
private fun createSmartspaceView(): SmartspaceView {
return spy(object : View(context), SmartspaceView {
override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {
@@ -574,3 +609,5 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() {
private const val PRIVATE_LOCKSCREEN_SETTING =
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
+private const val NOTIF_ON_LOCKSCREEN_SETTING =
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 7638452eaf90..9c12c5c7e2d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -1489,25 +1489,6 @@ public class ShadeListBuilderTest extends SysuiTestCase {
}
@Test
- public void testFinalizeFilteredChildrenPromotesSummary() {
- // GIVEN a group with only one child was already drawn
- addGroupSummary(0, PACKAGE_1, GROUP_1);
- addGroupChild(1, PACKAGE_1, GROUP_1);
- addGroupChild(2, PACKAGE_1, GROUP_1);
-
- // WHEN the parent is filtered out at the finalize step
- mFinalizeFilter.mIndicesToFilter.add(1);
- mFinalizeFilter.mIndicesToFilter.add(2);
-
- dispatchBuild();
-
- // THEN the children should be promoted to the top level
- verifyBuiltList(
- notif(0)
- );
- }
-
- @Test
public void testFinalizeFilteredChildPromotesSibling() {
// GIVEN a group with only one child was already drawn
addGroupSummary(0, PACKAGE_1, GROUP_1);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index c9de60806b66..94a93ad6cf33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -74,6 +74,7 @@ import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.shade.transition.ShadeTransitionController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -135,6 +136,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
@Mock private StackStateLogger mStackLogger;
@Mock private NotificationStackScrollLogger mLogger;
@Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
+ @Mock private ShadeTransitionController mShadeTransitionController;
@Captor
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -179,6 +181,7 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
mNotifCollection,
mEntryManager,
mLockscreenShadeTransitionController,
+ mShadeTransitionController,
mIStatusBarService,
mUiEventLogger,
mLayoutInflater,
@@ -228,19 +231,15 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
public void testUpdateEmptyShadeView_notificationsVisible_zenHiding() {
when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(true);
mController.attach(mNotificationStackScrollLayout);
- verify(mSysuiStatusBarStateController).addCallback(
- mStateListenerArgumentCaptor.capture(), anyInt());
- StatusBarStateController.StateListener stateListener =
- mStateListenerArgumentCaptor.getValue();
- setupShowEmptyShadeViewState(stateListener, true);
+ setupShowEmptyShadeViewState(true);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ true,
/* notifVisibleInShade= */ true);
- setupShowEmptyShadeViewState(stateListener, false);
+ setupShowEmptyShadeViewState(false);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
@@ -252,19 +251,15 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
public void testUpdateEmptyShadeView_notificationsHidden_zenNotHiding() {
when(mZenModeController.areNotificationsHiddenInShade()).thenReturn(false);
mController.attach(mNotificationStackScrollLayout);
- verify(mSysuiStatusBarStateController).addCallback(
- mStateListenerArgumentCaptor.capture(), anyInt());
- StatusBarStateController.StateListener stateListener =
- mStateListenerArgumentCaptor.getValue();
- setupShowEmptyShadeViewState(stateListener, true);
+ setupShowEmptyShadeViewState(true);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
/* visible= */ true,
/* notifVisibleInShade= */ false);
- setupShowEmptyShadeViewState(stateListener, false);
+ setupShowEmptyShadeViewState(false);
reset(mNotificationStackScrollLayout);
mController.updateShowEmptyShadeView();
verify(mNotificationStackScrollLayout).updateEmptyShadeView(
@@ -407,15 +402,13 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
return argThat(new LogMatcher(category, type));
}
- private void setupShowEmptyShadeViewState(
- StatusBarStateController.StateListener statusBarStateListener,
- boolean toShow) {
+ private void setupShowEmptyShadeViewState(boolean toShow) {
if (toShow) {
- statusBarStateListener.onStateChanged(SHADE);
+ when(mSysuiStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(SHADE);
mController.setQsFullScreen(false);
mController.getView().removeAllViews();
} else {
- statusBarStateListener.onStateChanged(KEYGUARD);
+ when(mSysuiStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(KEYGUARD);
mController.setQsFullScreen(true);
mController.getView().addContainerView(mock(ExpandableNotificationRow.class));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
index c3658ba11b2d..663490ebfde0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
@@ -49,7 +49,7 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
@Mock private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
@Mock private lateinit var stackLayout: NotificationStackScrollLayout
- private val testableResources = mContext.getOrCreateTestableResources()
+ private val testableResources = mContext.orCreateTestableResources
private lateinit var sizeCalculator: NotificationStackSizeCalculator
@@ -121,17 +121,16 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
}
@Test
- fun computeHeight_returnsAtMostSpaceAvailable_withGapBeforeShelf() {
+ fun computeHeight_gapBeforeShelf_returnsSpaceUsed() {
+ // Each row in separate section.
setGapHeight(gapHeight)
- val shelfHeight = shelfHeight
- val availableSpace =
+ val spaceUsed =
listOf(
- rowHeight + dividerHeight,
- gapHeight + rowHeight + dividerHeight,
- gapHeight + dividerHeight + shelfHeight)
+ dividerHeight + rowHeight,
+ dividerHeight + gapHeight + rowHeight,
+ dividerHeight + gapHeight + shelfHeight)
.sum()
-
- // All rows in separate sections (default setup).
+ val availableSpace = spaceUsed + 1;
val rows =
listOf(createMockRow(rowHeight), createMockRow(rowHeight), createMockRow(rowHeight))
@@ -139,23 +138,29 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
assertThat(maxNotifications).isEqualTo(2)
val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight)
- assertThat(height).isAtMost(availableSpace)
+ assertThat(height).isEqualTo(spaceUsed)
}
@Test
- fun computeHeight_noGapBeforeShelf_returnsAtMostSpaceAvailable() {
+ fun computeHeight_noGapBeforeShelf_returnsSpaceUsed() {
// Both rows are in the same section.
setGapHeight(0f)
+
val rowHeight = rowHeight
val shelfHeight = shelfHeight
- val availableSpace = listOf(rowHeight + dividerHeight, dividerHeight + shelfHeight).sum()
+ val spaceUsed =
+ listOf(
+ dividerHeight + rowHeight,
+ dividerHeight + shelfHeight)
+ .sum()
+ val availableSpace = spaceUsed + 1
val rows = listOf(createMockRow(rowHeight), createMockRow(rowHeight))
val maxNotifications = computeMaxKeyguardNotifications(rows, availableSpace, shelfHeight)
assertThat(maxNotifications).isEqualTo(1)
val height = sizeCalculator.computeHeight(stackLayout, maxNotifications, this.shelfHeight)
- assertThat(height).isAtMost(availableSpace)
+ assertThat(height).isEqualTo(spaceUsed)
}
@Test
@@ -190,7 +195,7 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
val space = sizeCalculator.spaceNeeded(expandableView, visibleIndex = 0,
previousView = null, stack = stackLayout, onLockscreen = true)
- assertThat(space).isEqualTo(5)
+ assertThat(space).isEqualTo(5 + dividerHeight)
}
@Test
@@ -204,7 +209,7 @@ class NotificationStackSizeCalculatorTest : SysuiTestCase() {
val space = sizeCalculator.spaceNeeded(expandableView, visibleIndex = 0,
previousView = null, stack = stackLayout, onLockscreen = false)
- assertThat(space).isEqualTo(10)
+ assertThat(space).isEqualTo(10 + dividerHeight)
}
private fun computeMaxKeyguardNotifications(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderControllerTest.kt
index 01e95950e45a..80664013f95d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LargeScreenShadeHeaderControllerTest.kt
@@ -1,8 +1,12 @@
package com.android.systemui.statusbar.phone
import android.app.StatusBarManager
+import android.content.Context
+import android.content.res.TypedArray
import android.testing.AndroidTestingRunner
+import android.util.TypedValue.COMPLEX_UNIT_PX
import android.view.View
+import android.widget.TextView
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -13,7 +17,9 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.qs.HeaderPrivacyIconsController
+import com.android.systemui.qs.carrier.QSCarrierGroup
import com.android.systemui.qs.carrier.QSCarrierGroupController
+import com.android.systemui.statusbar.policy.FakeConfigurationController
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
@@ -22,6 +28,7 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
+import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
@@ -36,19 +43,32 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() {
@Mock private lateinit var qsCarrierGroupController: QSCarrierGroupController
@Mock private lateinit var qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder
@Mock private lateinit var featureFlags: FeatureFlags
+ @Mock private lateinit var clock: TextView
+ @Mock private lateinit var date: TextView
+ @Mock private lateinit var carrierGroup: QSCarrierGroup
@Mock private lateinit var batteryMeterView: BatteryMeterView
@Mock private lateinit var batteryMeterViewController: BatteryMeterViewController
@Mock private lateinit var privacyIconsController: HeaderPrivacyIconsController
@Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var mockedContext: Context
+ @Mock private lateinit var typedArray: TypedArray
+
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
var viewVisibility = View.GONE
private lateinit var mLargeScreenShadeHeaderController: LargeScreenShadeHeaderController
private lateinit var carrierIconSlots: List<String>
+ private val configurationController = FakeConfigurationController()
@Before
fun setup() {
+ whenever<TextView>(view.findViewById(R.id.clock)).thenReturn(clock)
+ whenever(clock.context).thenReturn(mockedContext)
+ whenever(mockedContext.obtainStyledAttributes(anyInt(), any())).thenReturn(typedArray)
+ whenever<TextView>(view.findViewById(R.id.date)).thenReturn(date)
+ whenever(date.context).thenReturn(mockedContext)
+ whenever<QSCarrierGroup>(view.findViewById(R.id.carrier_group)).thenReturn(carrierGroup)
whenever<BatteryMeterView>(view.findViewById(R.id.batteryRemainingIcon))
.thenReturn(batteryMeterView)
whenever<StatusIconContainer>(view.findViewById(R.id.statusIcons)).thenReturn(statusIcons)
@@ -67,6 +87,7 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() {
view,
statusBarIconController,
privacyIconsController,
+ configurationController,
qsCarrierGroupControllerBuilder,
featureFlags,
batteryMeterViewController,
@@ -138,4 +159,38 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() {
mLargeScreenShadeHeaderController.active = true
mLargeScreenShadeHeaderController.shadeExpanded = true
}
+
+ @Test
+ fun updateConfig_changesFontSize() {
+ val updatedTextPixelSize = 32
+ setReturnTextSize(updatedTextPixelSize)
+
+ configurationController.notifyDensityOrFontScaleChanged()
+
+ verify(clock).setTextSize(COMPLEX_UNIT_PX, updatedTextPixelSize.toFloat())
+ verify(date).setTextSize(COMPLEX_UNIT_PX, updatedTextPixelSize.toFloat())
+ verify(carrierGroup).updateTextAppearance(R.style.TextAppearance_QS_Status)
+ }
+
+ @Test
+ fun updateConfig_changesFontSizeMultipleTimes() {
+ val updatedTextPixelSize1 = 32
+ setReturnTextSize(updatedTextPixelSize1)
+ configurationController.notifyDensityOrFontScaleChanged()
+ verify(clock).setTextSize(COMPLEX_UNIT_PX, updatedTextPixelSize1.toFloat())
+ verify(date).setTextSize(COMPLEX_UNIT_PX, updatedTextPixelSize1.toFloat())
+ verify(carrierGroup).updateTextAppearance(R.style.TextAppearance_QS_Status)
+ clearInvocations(carrierGroup)
+
+ val updatedTextPixelSize2 = 42
+ setReturnTextSize(updatedTextPixelSize2)
+ configurationController.notifyDensityOrFontScaleChanged()
+ verify(clock).setTextSize(COMPLEX_UNIT_PX, updatedTextPixelSize2.toFloat())
+ verify(date).setTextSize(COMPLEX_UNIT_PX, updatedTextPixelSize2.toFloat())
+ verify(carrierGroup).updateTextAppearance(R.style.TextAppearance_QS_Status)
+ }
+
+ private fun setReturnTextSize(resultTextSize: Int) {
+ whenever(typedArray.getDimensionPixelSize(anyInt(), anyInt())).thenReturn(resultTextSize)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
new file mode 100644
index 000000000000..2ff6dd43e84e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.phone
+
+import android.service.notification.StatusBarNotification
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.StatusBarIconView
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
+
+/**
+ * Tests for {@link NotificationIconContainer}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class NotificationIconContainerTest : SysuiTestCase() {
+
+ private val iconContainer = NotificationIconContainer(context, /* attrs= */ null)
+
+ @Test
+ fun calculateWidthFor_zeroIcons_widthIsZero() {
+ assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 0f),
+ /* actual= */ 0f)
+ }
+
+ @Test
+ fun calculateWidthFor_oneIcon_widthForOneIcon() {
+ iconContainer.setActualPaddingStart(10f)
+ iconContainer.setActualPaddingEnd(10f)
+ iconContainer.setIconSize(10);
+
+ assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f),
+ /* actual= */ 30f)
+ }
+
+ @Test
+ fun calculateWidthFor_fourIcons_widthForFourIcons() {
+ iconContainer.setActualPaddingStart(10f)
+ iconContainer.setActualPaddingEnd(10f)
+ iconContainer.setIconSize(10);
+
+ assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f),
+ /* actual= */ 60f)
+ }
+
+ @Test
+ fun calculateWidthFor_fiveIcons_widthForFourIcons() {
+ iconContainer.setActualPaddingStart(10f)
+ iconContainer.setActualPaddingEnd(10f)
+ iconContainer.setIconSize(10);
+ assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f),
+ /* actual= */ 60f)
+ }
+
+ @Test
+ fun calculateIconXTranslations_shortShelfOneIcon_atCorrectXWithoutOverflowDot() {
+ iconContainer.setActualPaddingStart(10f)
+ iconContainer.setActualPaddingEnd(10f)
+ iconContainer.setIconSize(10);
+
+ val icon = mockStatusBarIcon()
+ iconContainer.addView(icon)
+ assertEquals(1, iconContainer.childCount)
+
+ val iconState = iconContainer.getIconState(icon)
+ iconState.iconAppearAmount = 1f
+
+ val width = iconContainer.calculateWidthFor(/* numIcons= */ 1f)
+ iconContainer.setActualLayoutWidth(width.toInt())
+
+ iconContainer.calculateIconXTranslations()
+ assertEquals(10f, iconState.xTranslation)
+ assertFalse(iconContainer.hasOverflow())
+ }
+
+ @Test
+ fun calculateIconXTranslations_shortShelfFourIcons_atCorrectXWithoutOverflowDot() {
+ iconContainer.setActualPaddingStart(10f)
+ iconContainer.setActualPaddingEnd(10f)
+ iconContainer.setIconSize(10);
+
+ val iconOne = mockStatusBarIcon()
+ val iconTwo = mockStatusBarIcon()
+ val iconThree = mockStatusBarIcon()
+ val iconFour = mockStatusBarIcon()
+
+ iconContainer.addView(iconOne)
+ iconContainer.addView(iconTwo)
+ iconContainer.addView(iconThree)
+ iconContainer.addView(iconFour)
+ assertEquals(4, iconContainer.childCount)
+
+ val width = iconContainer.calculateWidthFor(/* numIcons= */ 4f)
+ iconContainer.setActualLayoutWidth(width.toInt())
+
+ iconContainer.calculateIconXTranslations()
+ assertEquals(10f, iconContainer.getIconState(iconOne).xTranslation)
+ assertEquals(20f, iconContainer.getIconState(iconTwo).xTranslation)
+ assertEquals(30f, iconContainer.getIconState(iconThree).xTranslation)
+ assertEquals(40f, iconContainer.getIconState(iconFour).xTranslation)
+
+ assertFalse(iconContainer.hasOverflow())
+ }
+
+ @Test
+ fun calculateIconXTranslations_shortShelfFiveIcons_atCorrectXWithOverflowDot() {
+ iconContainer.setActualPaddingStart(10f)
+ iconContainer.setActualPaddingEnd(10f)
+ iconContainer.setIconSize(10);
+
+ val iconOne = mockStatusBarIcon()
+ val iconTwo = mockStatusBarIcon()
+ val iconThree = mockStatusBarIcon()
+ val iconFour = mockStatusBarIcon()
+ val iconFive = mockStatusBarIcon()
+
+ iconContainer.addView(iconOne)
+ iconContainer.addView(iconTwo)
+ iconContainer.addView(iconThree)
+ iconContainer.addView(iconFour)
+ iconContainer.addView(iconFive)
+ assertEquals(5, iconContainer.childCount)
+
+ val width = iconContainer.calculateWidthFor(/* numIcons= */ 5f)
+ iconContainer.setActualLayoutWidth(width.toInt())
+
+ iconContainer.calculateIconXTranslations()
+ assertEquals(10f, iconContainer.getIconState(iconOne).xTranslation)
+ assertEquals(20f, iconContainer.getIconState(iconTwo).xTranslation)
+ assertEquals(30f, iconContainer.getIconState(iconThree).xTranslation)
+ assertTrue(iconContainer.hasOverflow())
+ }
+
+ private fun mockStatusBarIcon() : StatusBarIconView {
+ val iconView = mock(StatusBarIconView::class.java)
+ whenever(iconView.width).thenReturn(10)
+
+ val icon = mock(android.graphics.drawable.Icon::class.java)
+ whenever(iconView.sourceIcon).thenReturn(icon)
+
+ val sbn = mock(StatusBarNotification::class.java)
+ whenever(sbn.groupKey).thenReturn("groupKey")
+ whenever(iconView.notification).thenReturn(sbn)
+ return iconView
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 71f1f0b0f7cf..708a5b584cbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -128,6 +128,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
+import com.android.systemui.statusbar.phone.shade.transition.ShadeTransitionController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -337,6 +338,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Mock
+ private ShadeTransitionController mShadeTransitionController;
+ @Mock
private QS mQs;
@Mock
private View mQsHeader;
@@ -352,6 +355,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private FalsingManagerFake mFalsingManager = new FalsingManagerFake();
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private Handler mMainHandler;
+ private final PanelExpansionStateManager mPanelExpansionStateManager =
+ new PanelExpansionStateManager();
@Before
public void setup() {
@@ -516,7 +521,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mLargeScreenShadeHeaderController,
mScreenOffAnimationController,
mLockscreenGestureLogger,
- new PanelExpansionStateManager(),
+ mPanelExpansionStateManager,
mNotificationRemoteInputManager,
mSysUIUnfoldComponent,
mControlsComponent,
@@ -527,7 +532,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mNotificationListContainer,
mPanelEventsEmitter,
mNotificationStackSizeCalculator,
- mUnlockedScreenOffAnimationController);
+ mUnlockedScreenOffAnimationController,
+ mShadeTransitionController);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
() -> {},
@@ -558,6 +564,37 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}
@Test
+ public void computeMaxKeyguardNotifications_lockscreenToShade_returnsExistingMax() {
+ when(mAmbientState.getFractionToShade()).thenReturn(0.5f);
+ mNotificationPanelViewController.setMaxDisplayedNotifications(-1);
+
+ // computeMaxKeyguardNotifications sets maxAllowed to 0 at minimum if it updates the value
+ assertThat(mNotificationPanelViewController.computeMaxKeyguardNotifications())
+ .isEqualTo(-1);
+ }
+
+ @Test
+ public void computeMaxKeyguardNotifications_dozeAmountNotZero_returnsExistingMax() {
+ when(mAmbientState.getDozeAmount()).thenReturn(0.5f);
+ mNotificationPanelViewController.setMaxDisplayedNotifications(-1);
+
+ // computeMaxKeyguardNotifications sets maxAllowed to 0 at minimum if it updates the value
+ assertThat(mNotificationPanelViewController.computeMaxKeyguardNotifications())
+ .isEqualTo(-1);
+ }
+
+ @Test
+ public void computeMaxKeyguardNotifications_noTransition_updatesMax() {
+ when(mAmbientState.getFractionToShade()).thenReturn(0f);
+ when(mAmbientState.getDozeAmount()).thenReturn(0f);
+ mNotificationPanelViewController.setMaxDisplayedNotifications(-1);
+
+ // computeMaxKeyguardNotifications sets maxAllowed to 0 at minimum if it updates the value
+ assertThat(mNotificationPanelViewController.computeMaxKeyguardNotifications())
+ .isNotEqualTo(-1);
+ }
+
+ @Test
public void testSetPanelScrimMinFraction() {
mNotificationPanelViewController.setPanelScrimMinFraction(0.5f);
verify(mNotificationShadeDepthController).setPanelPullDownMinFraction(eq(0.5f));
@@ -987,15 +1024,36 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}
@Test
- public void testQsToBeImmediatelyExpandedInSplitShade() {
+ public void testQsToBeImmediatelyExpandedWhenOpeningPanelInSplitShade() {
enableSplitShade(/* enabled= */ true);
+ // set panel state to CLOSED
+ mPanelExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 0,
+ /* expanded= */ false, /* tracking= */ false, /* dragDownPxAmount= */ 0);
+ assertThat(mNotificationPanelViewController.mQsExpandImmediate).isFalse();
- mNotificationPanelViewController.onTrackingStarted();
+ // change panel state to OPENING
+ mPanelExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 0.5f,
+ /* expanded= */ true, /* tracking= */ true, /* dragDownPxAmount= */ 100);
assertThat(mNotificationPanelViewController.mQsExpandImmediate).isTrue();
}
@Test
+ public void testQsNotToBeImmediatelyExpandedWhenGoingFromUnlockedToLocked() {
+ enableSplitShade(/* enabled= */ true);
+ // set panel state to CLOSED
+ mPanelExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 0,
+ /* expanded= */ false, /* tracking= */ false, /* dragDownPxAmount= */ 0);
+
+ // go to lockscreen, which also sets fraction to 1.0f and makes shade "expanded"
+ mStatusBarStateController.setState(KEYGUARD);
+ mPanelExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 1,
+ /* expanded= */ true, /* tracking= */ true, /* dragDownPxAmount= */ 0);
+
+ assertThat(mNotificationPanelViewController.mQsExpandImmediate).isFalse();
+ }
+
+ @Test
public void interceptTouchEvent_withinQs_shadeExpanded_startsQsTracking() {
mNotificationPanelViewController.mQs = mQs;
when(mQsFrame.getX()).thenReturn(0f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index a94ad0b763aa..38e018b42985 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -192,6 +192,15 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
}
@Test
+ public void onPanelExpansionChanged_propagatesToBouncer_evenAfterHidden() {
+ mStatusBarKeyguardViewManager.hide(0, 0);
+ when(mBouncer.inTransit()).thenReturn(true);
+
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
+ verify(mBouncer).setExpansion(eq(EXPANSION_EVENT.getFraction()));
+ }
+
+ @Test
public void onPanelExpansionChanged_showsBouncerWhenSwiping() {
when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/shade/transition/ShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/shade/transition/ShadeTransitionControllerTest.kt
new file mode 100644
index 000000000000..39d33e86925e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/shade/transition/ShadeTransitionControllerTest.kt
@@ -0,0 +1,118 @@
+package com.android.systemui.statusbar.phone.shade.transition
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.NotificationPanelViewController
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
+import com.android.systemui.statusbar.phone.panelstate.STATE_OPENING
+import com.android.systemui.statusbar.policy.FakeConfigurationController
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ShadeTransitionControllerTest : SysuiTestCase() {
+
+ @Mock private lateinit var npvc: NotificationPanelViewController
+ @Mock private lateinit var nsslController: NotificationStackScrollLayoutController
+ @Mock private lateinit var qs: QS
+ @Mock private lateinit var noOpOverScroller: NoOpOverScroller
+ @Mock private lateinit var splitShadeOverScroller: SplitShadeOverScroller
+
+ private lateinit var controller: ShadeTransitionController
+
+ private val configurationController = FakeConfigurationController()
+ private val panelExpansionStateManager = PanelExpansionStateManager()
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ controller =
+ ShadeTransitionController(
+ configurationController,
+ panelExpansionStateManager,
+ context,
+ splitShadeOverScrollerFactory = { _, _ -> splitShadeOverScroller },
+ noOpOverScroller)
+
+ // Resetting as they are notified upon initialization.
+ reset(noOpOverScroller, splitShadeOverScroller)
+ }
+
+ @Test
+ fun onPanelExpansionChanged_inSplitShade_forwardsToSplitShadeOverScroller() {
+ initLateProperties()
+ enableSplitShade()
+
+ startPanelExpansion()
+
+ verify(splitShadeOverScroller).onPanelStateChanged(STATE_OPENING)
+ verify(splitShadeOverScroller).onDragDownAmountChanged(DEFAULT_DRAG_DOWN_AMOUNT)
+ verifyZeroInteractions(noOpOverScroller)
+ }
+
+ @Test
+ fun onPanelStateChanged_inSplitShade_propertiesNotInitialized_forwardsToNoOpOverScroller() {
+ enableSplitShade()
+
+ startPanelExpansion()
+
+ verify(noOpOverScroller).onPanelStateChanged(STATE_OPENING)
+ verify(noOpOverScroller).onDragDownAmountChanged(DEFAULT_DRAG_DOWN_AMOUNT)
+ verifyZeroInteractions(splitShadeOverScroller)
+ }
+
+ @Test
+ fun onPanelStateChanged_notInSplitShade_forwardsToNoOpOverScroller() {
+ initLateProperties()
+ disableSplitShade()
+
+ startPanelExpansion()
+
+ verify(noOpOverScroller).onPanelStateChanged(STATE_OPENING)
+ verify(noOpOverScroller).onDragDownAmountChanged(DEFAULT_DRAG_DOWN_AMOUNT)
+ verifyZeroInteractions(splitShadeOverScroller)
+ }
+
+ private fun initLateProperties() {
+ controller.qs = qs
+ controller.notificationStackScrollLayoutController = nsslController
+ controller.notificationPanelViewController = npvc
+ }
+
+ private fun disableSplitShade() {
+ setSplitShadeEnabled(false)
+ }
+
+ private fun enableSplitShade() {
+ setSplitShadeEnabled(true)
+ }
+
+ private fun setSplitShadeEnabled(enabled: Boolean) {
+ overrideResource(R.bool.config_use_split_notification_shade, enabled)
+ configurationController.notifyConfigurationChanged()
+ }
+
+ private fun startPanelExpansion() {
+ panelExpansionStateManager.onPanelExpansionChanged(
+ fraction = 0.5f,
+ expanded = true,
+ tracking = true,
+ dragDownPxAmount = DEFAULT_DRAG_DOWN_AMOUNT)
+ }
+
+ companion object {
+ private const val DEFAULT_DRAG_DOWN_AMOUNT = 123f
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/shade/transition/SplitShadeOverScrollerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/shade/transition/SplitShadeOverScrollerTest.kt
new file mode 100644
index 000000000000..219737d1dfb4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/shade/transition/SplitShadeOverScrollerTest.kt
@@ -0,0 +1,107 @@
+package com.android.systemui.statusbar.phone.shade.transition
+
+import org.mockito.Mockito.`when` as whenever
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.plugins.qs.QS
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.phone.ScrimController
+import com.android.systemui.statusbar.phone.panelstate.STATE_CLOSED
+import com.android.systemui.statusbar.phone.panelstate.STATE_OPEN
+import com.android.systemui.statusbar.phone.panelstate.STATE_OPENING
+import com.android.systemui.statusbar.policy.FakeConfigurationController
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class SplitShadeOverScrollerTest : SysuiTestCase() {
+
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var scrimController: ScrimController
+ @Mock private lateinit var qs: QS
+ @Mock private lateinit var nsslController: NotificationStackScrollLayoutController
+
+ private val configurationController = FakeConfigurationController()
+ private lateinit var overScroller: SplitShadeOverScroller
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(nsslController.height).thenReturn(1000)
+ overScroller =
+ SplitShadeOverScroller(
+ configurationController, dumpManager, context, scrimController, qs, nsslController)
+ }
+
+ @Test
+ fun onDragDownAmountChanged_panelOpening_overScrolls_basedOnHeightAndMaxAmount() {
+ val maxOverScrollAmount = 50
+ val dragDownAmount = 100f
+ overrideResource(R.dimen.shade_max_over_scroll_amount, maxOverScrollAmount)
+ configurationController.notifyConfigurationChanged()
+
+ overScroller.onPanelStateChanged(STATE_OPENING)
+ overScroller.onDragDownAmountChanged(dragDownAmount)
+
+ val expectedOverScrollAmount =
+ (dragDownAmount / nsslController.height * maxOverScrollAmount).toInt()
+ verify(qs).setOverScrollAmount(expectedOverScrollAmount)
+ verify(nsslController).setOverScrollAmount(expectedOverScrollAmount)
+ verify(scrimController).setNotificationsOverScrollAmount(expectedOverScrollAmount)
+ }
+
+ @Test
+ fun onDragDownAmountChanged_panelClosed_doesNotOverScroll() {
+ overScroller.onPanelStateChanged(STATE_CLOSED)
+ overScroller.onDragDownAmountChanged(100f)
+
+ verifyZeroInteractions(qs, scrimController, nsslController)
+ }
+
+ @Test
+ fun onDragDownAmountChanged_panelOpen_doesNotOverScroll() {
+ overScroller.onPanelStateChanged(STATE_OPEN)
+ overScroller.onDragDownAmountChanged(100f)
+
+ verifyZeroInteractions(qs, scrimController, nsslController)
+ }
+
+ @Test
+ fun onPanelStateChanged_opening_thenOpen_releasesOverScroll() {
+ overScroller.onPanelStateChanged(STATE_OPENING)
+ overScroller.onDragDownAmountChanged(100f)
+
+ overScroller.onPanelStateChanged(STATE_OPEN)
+ overScroller.finishAnimations()
+
+ verify(qs, atLeastOnce()).setOverScrollAmount(0)
+ verify(scrimController, atLeastOnce()).setNotificationsOverScrollAmount(0)
+ verify(nsslController, atLeastOnce()).setOverScrollAmount(0)
+ }
+
+ @Test
+ fun onPanelStateChanged_opening_thenClosed_releasesOverScroll() {
+ overScroller.onPanelStateChanged(STATE_OPENING)
+ overScroller.onDragDownAmountChanged(100f)
+
+ overScroller.onPanelStateChanged(STATE_CLOSED)
+ overScroller.finishAnimations()
+
+ verify(qs, atLeastOnce()).setOverScrollAmount(0)
+ verify(scrimController, atLeastOnce()).setNotificationsOverScrollAmount(0)
+ verify(nsslController, atLeastOnce()).setOverScrollAmount(0)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
index 146b56e49e65..16a326869562 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
@@ -23,6 +23,10 @@ class FakeConfigurationController : ConfigurationController {
listeners.forEach { it.onThemeChanged() }
}
+ fun notifyDensityOrFontScaleChanged() {
+ listeners.forEach { it.onDensityOrFontScaleChanged() }
+ }
+
fun notifyConfigurationChanged() {
onConfigurationChanged(newConfiguration = null)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 3dfc94bcd5b6..c625dc7d4b50 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -729,6 +729,18 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
USER_SYSTEM);
+ reset(mResources);
+ when(mResources.getColor(eq(android.R.color.system_accent1_500), any()))
+ .thenReturn(mThemeOverlayController.mColorScheme.getAccent1().get(6));
+ when(mResources.getColor(eq(android.R.color.system_accent2_500), any()))
+ .thenReturn(mThemeOverlayController.mColorScheme.getAccent2().get(6));
+ when(mResources.getColor(eq(android.R.color.system_accent3_500), any()))
+ .thenReturn(mThemeOverlayController.mColorScheme.getAccent3().get(6));
+ when(mResources.getColor(eq(android.R.color.system_neutral1_500), any()))
+ .thenReturn(mThemeOverlayController.mColorScheme.getNeutral1().get(6));
+ when(mResources.getColor(eq(android.R.color.system_neutral2_500), any()))
+ .thenReturn(mThemeOverlayController.mColorScheme.getNeutral2().get(6));
+
// Defers event because we already have initial colors.
verify(mThemeOverlayApplier, never())
.applyCurrentUserOverlays(any(), any(), anyInt(), any());
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 5acae4859ee8..8fe57e18ea37 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -4414,7 +4414,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// a given package. Keep track of what we've done so far here; the list is
// cleared at the start of every system restore pass, but preserved through
// any install-time restore operations.
- private final HashSet<String> mPrunedApps = new HashSet<>();
+ private final SparseArray<Set<String>> mPrunedAppsPerUser = new SparseArray<>();
private final HashMap<Provider, ArrayList<RestoreUpdateRecord>> mUpdatesByProvider =
new HashMap<>();
@@ -4537,7 +4537,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// We're starting a new "system" restore operation, so any widget restore
// state that we see from here on is intended to replace the current
// widget configuration of any/all of the affected apps.
- mPrunedApps.clear();
+ getPrunedAppsLocked(userId).clear();
mUpdatesByProvider.clear();
mUpdatesByHost.clear();
}
@@ -4934,8 +4934,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// instances that are hosted by that app, and (b) all instances in other hosts
// for which 'pkg' is the provider. We assume that we'll be restoring all of
// these hosts & providers, so will be reconstructing a correct live state.
+ @GuardedBy("mLock")
private void pruneWidgetStateLocked(String pkg, int userId) {
- if (!mPrunedApps.contains(pkg)) {
+ final Set<String> prunedApps = getPrunedAppsLocked(userId);
+ if (!prunedApps.contains(pkg)) {
if (DEBUG) {
Slog.i(TAG, "pruning widget state for restoring package " + pkg);
}
@@ -4958,7 +4960,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
removeWidgetLocked(widget);
}
}
- mPrunedApps.add(pkg);
+ prunedApps.add(pkg);
} else {
if (DEBUG) {
Slog.i(TAG, "already pruned " + pkg + ", continuing normally");
@@ -4966,6 +4968,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
+ @GuardedBy("mLock")
+ @NonNull
+ private Set<String> getPrunedAppsLocked(int userId) {
+ if (!mPrunedAppsPerUser.contains(userId)) {
+ mPrunedAppsPerUser.set(userId, new ArraySet<>());
+ }
+ return mPrunedAppsPerUser.get(userId);
+ }
+
private boolean isProviderAndHostInUser(Widget widget, int userId) {
// Backup only widgets hosted or provided by the owner profile.
return widget.host.getUserId() == userId && (widget.provider == null
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 8c4db70c301d..aa5c501cd94e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -805,12 +805,13 @@ final class AutofillManagerServiceImpl
* Updates the last fill response when a dataset was selected.
*/
void logDatasetSelected(@Nullable String selectedDataset, int sessionId,
- @Nullable Bundle clientState) {
+ @Nullable Bundle clientState, int presentationType) {
synchronized (mLock) {
if (isValidEventLocked("logDatasetSelected()", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null,
- null, null, null, null, null, null, null));
+ null, null, null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
+ presentationType));
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 7e277ba3c0d0..f18d13d30da6 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -21,6 +21,7 @@ import static android.service.autofill.AutofillService.EXTRA_FILL_RESPONSE;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_UNKNOWN;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
@@ -1406,7 +1407,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// AutoFillUiCallback
@Override
- public void fill(int requestId, int datasetIndex, Dataset dataset) {
+ public void fill(int requestId, int datasetIndex, Dataset dataset, int uiType) {
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#fill() rejected - session: "
@@ -1416,7 +1417,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
mHandler.sendMessage(obtainMessage(
Session::autoFill,
- this, requestId, datasetIndex, dataset, true));
+ this, requestId, datasetIndex, dataset, true, uiType));
}
// AutoFillUiCallback
@@ -1657,7 +1658,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (!isAuthResultDatasetEphemeral(oldDataset, data)) {
authenticatedResponse.getDatasets().set(datasetIdx, dataset);
}
- autoFill(requestId, datasetIdx, dataset, false);
+ autoFill(requestId, datasetIdx, dataset, false, UI_TYPE_UNKNOWN);
} else {
Slog.w(TAG, "invalid index (" + datasetIdx + ") for authentication id "
+ authenticationId);
@@ -3376,7 +3377,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
new InlineFillUi.InlineSuggestionUiCallback() {
@Override
public void autofill(@NonNull Dataset dataset, int datasetIndex) {
- fill(response.getRequestId(), datasetIndex, dataset);
+ fill(response.getRequestId(), datasetIndex, dataset, UI_TYPE_INLINE);
}
@Override
@@ -3895,7 +3896,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return viewState;
}
- void autoFill(int requestId, int datasetIndex, Dataset dataset, boolean generateEvent) {
+ void autoFill(int requestId, int datasetIndex, Dataset dataset, boolean generateEvent,
+ int uiType) {
if (sDebug) {
Slog.d(TAG, "autoFill(): requestId=" + requestId + "; datasetIdx=" + datasetIndex
+ "; dataset=" + dataset);
@@ -3909,7 +3911,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// Autofill it directly...
if (dataset.getAuthentication() == null) {
if (generateEvent) {
- mService.logDatasetSelected(dataset.getId(), id, mClientState);
+ mService.logDatasetSelected(dataset.getId(), id, mClientState, uiType);
}
if (mCurrentViewId != null) {
mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 056ab92fffb2..57768ef32391 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -15,6 +15,9 @@
*/
package com.android.server.autofill.ui;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
+
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
@@ -31,6 +34,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.service.autofill.Dataset;
+import android.service.autofill.FillEventHistory;
import android.service.autofill.FillResponse;
import android.service.autofill.SaveInfo;
import android.service.autofill.ValueFinder;
@@ -81,7 +85,8 @@ public final class AutoFillUI {
public interface AutoFillUiCallback {
void authenticate(int requestId, int datasetIndex, @NonNull IntentSender intent,
@Nullable Bundle extras, boolean authenticateInline);
- void fill(int requestId, int datasetIndex, @NonNull Dataset dataset);
+ void fill(int requestId, int datasetIndex, @NonNull Dataset dataset,
+ @FillEventHistory.Event.UiType int uiType);
void save();
void cancelSave();
void requestShowFillUi(AutofillId id, int width, int height,
@@ -236,7 +241,8 @@ public final class AutoFillUI {
hideFillUiUiThread(callback, true);
if (mCallback != null) {
final int datasetIndex = response.getDatasets().indexOf(dataset);
- mCallback.fill(response.getRequestId(), datasetIndex, dataset);
+ mCallback.fill(response.getRequestId(), datasetIndex,
+ dataset, UI_TYPE_MENU);
}
}
@@ -414,7 +420,8 @@ public final class AutoFillUI {
hideFillDialogUiThread(callback);
if (mCallback != null) {
final int datasetIndex = response.getDatasets().indexOf(dataset);
- mCallback.fill(response.getRequestId(), datasetIndex, dataset);
+ mCallback.fill(response.getRequestId(), datasetIndex, dataset,
+ UI_TYPE_DIALOG);
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 730907c7d049..235dbeeb9e27 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -21,7 +21,6 @@ import static android.Manifest.permission.REQUEST_COMPANION_START_FOREGROUND_SER
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
-import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -6527,10 +6526,14 @@ public final class ActiveServices {
for (int con = 0; con < crs.size(); con++) {
final ConnectionRecord cr = crs.get(con);
final ProcessRecord clientPr = cr.binding.client;
- // Persistent process does not propagate BG-FGS-start capability
- // down to service over binding.
- if (clientPr.mState.getCurProcState()
- <= PROCESS_STATE_PERSISTENT_UI) {
+ // If a binding is from a persistent process, we don't automatically
+ // always allow the bindee to allow FGS BG starts. In this case,
+ // the binder will have to explicitly make sure the bindee's
+ // procstate will be BFGS or above. Otherwise, for example, even if
+ // the system server binds to an app with BIND_NOT_FOREGROUND,
+ // the binder would have to be able to start FGS, which is not what
+ // we want. (e.g. job services shouldn't be allowed BG-FGS.)
+ if (clientPr.isPersistent()) {
continue;
}
final int clientPid = clientPr.mPid;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c5a4ca4dc0e5..91f6eeb875f6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1024,30 +1024,9 @@ public class ActivityManagerService extends IActivityManager.Stub
private final ActivityMetricsLaunchObserver mActivityLaunchObserver =
new ActivityMetricsLaunchObserver() {
@Override
- public void onActivityLaunched(byte[] activity, int temperature) {
+ public void onActivityLaunched(long id, ComponentName name, int temperature) {
mAppProfiler.onActivityLaunched();
}
-
- // The other observer methods are unused
- @Override
- public void onIntentStarted(Intent intent, long timestampNs) {
- }
-
- @Override
- public void onIntentFailed() {
- }
-
- @Override
- public void onActivityLaunchCancelled(byte[] abortingActivity) {
- }
-
- @Override
- public void onActivityLaunchFinished(byte[] finalActivity, long timestampNs) {
- }
-
- @Override
- public void onReportFullyDrawn(byte[] finalActivity, long timestampNs) {
- }
};
private volatile boolean mBinderTransactionTrackingEnabled = false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 71ae92aecbcf..3e5786eaa333 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1200,8 +1200,19 @@ final class ActivityManagerShellCommand extends ShellCommand {
} catch (NumberFormatException e) {
packageName = arg;
}
- mInterface.crashApplicationWithType(-1, pid, packageName, userId, "shell-induced crash",
- false, CrashedByAdbException.TYPE_ID);
+
+ int[] userIds = (userId == UserHandle.USER_ALL) ? mInternal.mUserController.getUserIds()
+ : new int[]{userId};
+ for (int id : userIds) {
+ if (mInternal.mUserController.hasUserRestriction(
+ UserManager.DISALLOW_DEBUGGING_FEATURES, id)) {
+ getOutPrintWriter().println(
+ "Shell does not have permission to crash packages for user " + id);
+ continue;
+ }
+ mInterface.crashApplicationWithType(-1, pid, packageName, id, "shell-induced crash",
+ false, CrashedByAdbException.TYPE_ID);
+ }
return 0;
}
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 9894a52b58e1..6e28d8fbad59 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -276,7 +276,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
AppBackgroundRestrictionsInfo.REASON_UNKNOWN, // ExemptionReason
AppBackgroundRestrictionsInfo.UNKNOWN, // OptimizationLevel
AppBackgroundRestrictionsInfo.SDK_UNKNOWN, // TargetSdk
- isLowRamDeviceStatic());
+ isLowRamDeviceStatic(),
+ AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN // previous RestrictionLevel
+ );
}
}
}
@@ -304,11 +306,17 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_BACKGROUND];
final double usageFgs =
bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND_SERVICE];
+ final double usageForeground =
+ bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_FOREGROUND];
+ final double usageCached =
+ bgUsage.mPercentage[BatteryUsage.BATTERY_USAGE_INDEX_CACHED];
if (DEBUG_BACKGROUND_BATTERY_TRACKER_VERBOSE) {
Slog.d(TAG, "getBatteryTrackerInfoProtoLocked uid:" + uid
+ " allUsage:" + String.format("%4.2f%%", allUsage)
+ " usageBackground:" + String.format("%4.2f%%", usageBackground)
- + " usageFgs:" + String.format("%4.2f%%", usageFgs));
+ + " usageFgs:" + String.format("%4.2f%%", usageFgs)
+ + " usageForeground:" + String.format("%4.2f%%", usageForeground)
+ + " usageCached:" + String.format("%4.2f%%", usageCached));
}
final ProtoOutputStream proto = new ProtoOutputStream();
proto.write(AppBackgroundRestrictionsInfo.BatteryTrackerInfo.BATTERY_24H,
@@ -317,6 +325,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
usageBackground * 10000);
proto.write(AppBackgroundRestrictionsInfo.BatteryTrackerInfo.BATTERY_USAGE_FGS,
usageFgs * 10000);
+ proto.write(AppBackgroundRestrictionsInfo.BatteryTrackerInfo.BATTERY_USAGE_FOREGROUND,
+ usageForeground * 10000);
+ proto.write(AppBackgroundRestrictionsInfo.BatteryTrackerInfo.BATTERY_USAGE_CACHED,
+ usageCached * 10000);
proto.flush();
return proto.getBytes();
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 36c40a1b97dc..ed492bc7344c 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -33,6 +33,7 @@ import android.app.ActivityOptions;
import android.app.AnrController;
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
+import android.app.RemoteServiceException.CrashedByAdbException;
import android.app.usage.UsageStatsManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -523,6 +524,16 @@ class AppErrors {
return;
}
+ if (exceptionTypeId == CrashedByAdbException.TYPE_ID) {
+ String[] packages = proc.getPackageList();
+ for (int i = 0; i < packages.length; i++) {
+ if (mService.mPackageManagerInt.isPackageStateProtected(packages[i], proc.userId)) {
+ Slog.w(TAG, "crashApplication: Can not crash protected package " + packages[i]);
+ return;
+ }
+ }
+ }
+
proc.scheduleCrashLocked(message, exceptionTypeId, extras);
if (force) {
// If the app is responsive, the scheduled crash will happen as expected
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index 0c1ab8178b38..f7abb117e3de 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -2086,6 +2086,9 @@ public final class AppRestrictionController {
int curLevel;
int prevReason;
final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal();
+ if (trackerInfo == null) {
+ trackerInfo = mEmptyTrackerInfo;
+ }
synchronized (mSettingsLock) {
curLevel = getRestrictionLevel(uid, pkgName);
if (curLevel == level) {
@@ -2138,14 +2141,21 @@ public final class AppRestrictionController {
// It's currently active, enqueue it.
final int localReason = reason;
final int localSubReason = subReason;
- mActiveUids.add(uid, pkgName, () -> appStandbyInternal.restrictApp(
- pkgName, UserHandle.getUserId(uid), localReason, localSubReason));
+ final TrackerInfo localTrackerInfo = trackerInfo;
+ mActiveUids.add(uid, pkgName, () -> {
+ appStandbyInternal.restrictApp(pkgName, UserHandle.getUserId(uid),
+ localReason, localSubReason);
+ logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level,
+ localTrackerInfo, localReason);
+ });
doIt = false;
}
}
if (doIt) {
appStandbyInternal.restrictApp(pkgName, UserHandle.getUserId(uid),
reason, subReason);
+ logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level, trackerInfo,
+ reason);
}
}
} else if (curLevel >= RESTRICTION_LEVEL_RESTRICTED_BUCKET
@@ -2160,11 +2170,14 @@ public final class AppRestrictionController {
appStandbyInternal.maybeUnrestrictApp(pkgName, UserHandle.getUserId(uid),
prevReason & REASON_MAIN_MASK, prevReason & REASON_SUB_MASK,
reason, subReason);
+ logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level, trackerInfo,
+ reason);
}
+ }
- if (trackerInfo == null) {
- trackerInfo = mEmptyTrackerInfo;
- }
+ private void logAppBackgroundRestrictionInfo(String pkgName, int uid,
+ @RestrictionLevel int prevLevel, @RestrictionLevel int level,
+ @NonNull TrackerInfo trackerInfo, int reason) {
FrameworkStatsLog.write(FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO, uid,
getRestrictionLevelStatsd(level),
getThresholdStatsd(reason),
@@ -2176,7 +2189,8 @@ public final class AppRestrictionController {
getExemptionReasonStatsd(uid, level),
getOptimizationLevelStatsd(level),
getTargetSdkStatsd(pkgName),
- ActivityManager.isLowRamDeviceStatic());
+ ActivityManager.isLowRamDeviceStatic(),
+ getRestrictionLevelStatsd(prevLevel));
}
private void handleBackgroundRestrictionChanged(int uid, String pkgName, boolean restricted) {
@@ -2449,7 +2463,8 @@ public final class AppRestrictionController {
mBgController.getBackgroundRestrictionExemptionReason(uid)),
AppBackgroundRestrictionsInfo.UNKNOWN, // OptimizationLevel
AppBackgroundRestrictionsInfo.SDK_UNKNOWN, // TargetSdk
- ActivityManager.isLowRamDeviceStatic());
+ ActivityManager.isLowRamDeviceStatic(),
+ mBgController.getRestrictionLevel(uid));
PendingIntent pendingIntent;
if (!mBgController.mConstantsObserver.mBgPromptFgsWithNotiOnLongRunning
&& mBgController.hasForegroundServiceNotifications(packageName, uid)) {
diff --git a/services/core/java/com/android/server/am/DropboxRateLimiter.java b/services/core/java/com/android/server/am/DropboxRateLimiter.java
index 672736df88f3..18fb6a480f29 100644
--- a/services/core/java/com/android/server/am/DropboxRateLimiter.java
+++ b/services/core/java/com/android/server/am/DropboxRateLimiter.java
@@ -64,9 +64,10 @@ public class DropboxRateLimiter {
}
if (now - errRecord.getStartTime() > RATE_LIMIT_BUFFER_DURATION) {
+ final int errCount = recentlyDroppedCount(errRecord);
errRecord.setStartTime(now);
errRecord.setCount(1);
- return new RateLimitResult(false, recentlyDroppedCount(errRecord));
+ return new RateLimitResult(false, errCount);
}
errRecord.incrementCount();
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index c48ff9f9f2cc..2dadcecc9f1f 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -97,6 +97,7 @@ public class SettingsToPropertiesMapper {
DeviceConfig.NAMESPACE_SURFACE_FLINGER_NATIVE_BOOT,
DeviceConfig.NAMESPACE_SWCODEC_NATIVE,
DeviceConfig.NAMESPACE_TETHERING,
+ DeviceConfig.NAMESPACE_VENDOR_SYSTEM_NATIVE,
DeviceConfig.NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE,
DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT,
};
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
index a76eb8f1e55d..90b1b634f2ee 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
@@ -20,9 +20,11 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
import android.content.Context;
import android.content.Intent;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.service.games.GameService;
import android.service.games.GameSessionService;
import android.service.games.IGameService;
@@ -47,14 +49,17 @@ final class GameServiceProviderInstanceFactoryImpl implements GameServiceProvide
@Override
public GameServiceProviderInstance create(
@NonNull GameServiceComponentConfiguration configuration) {
+ final UserHandle userHandle = configuration.getUserHandle();
+ final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService();
return new GameServiceProviderInstanceImpl(
- configuration.getUserHandle(),
+ userHandle,
BackgroundThread.getExecutor(),
mContext,
- new GameClassifierImpl(mContext.getPackageManager()),
+ new GameTaskInfoProvider(userHandle, activityTaskManager,
+ new GameClassifierImpl(mContext.getPackageManager())),
ActivityManager.getService(),
LocalServices.getService(ActivityManagerInternal.class),
- ActivityTaskManager.getService(),
+ activityTaskManager,
(WindowManagerService) ServiceManager.getService(Context.WINDOW_SERVICE),
LocalServices.getService(WindowManagerInternal.class),
new GameServiceConnector(mContext, configuration),
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index b38195aed250..a200067b8f3f 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -64,7 +64,6 @@ import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerService;
-import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -218,7 +217,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
private final UserHandle mUserHandle;
private final Executor mBackgroundExecutor;
private final Context mContext;
- private final GameClassifier mGameClassifier;
+ private final GameTaskInfoProvider mGameTaskInfoProvider;
private final IActivityManager mActivityManager;
private final ActivityManagerInternal mActivityManagerInternal;
private final IActivityTaskManager mActivityTaskManager;
@@ -244,7 +243,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
@NonNull UserHandle userHandle,
@NonNull Executor backgroundExecutor,
@NonNull Context context,
- @NonNull GameClassifier gameClassifier,
+ @NonNull GameTaskInfoProvider gameTaskInfoProvider,
@NonNull IActivityManager activityManager,
@NonNull ActivityManagerInternal activityManagerInternal,
@NonNull IActivityTaskManager activityTaskManager,
@@ -256,7 +255,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
mUserHandle = userHandle;
mBackgroundExecutor = backgroundExecutor;
mContext = context;
- mGameClassifier = gameClassifier;
+ mGameTaskInfoProvider = gameTaskInfoProvider;
mActivityManager = activityManager;
mActivityManagerInternal = activityManagerInternal;
mActivityTaskManager = activityTaskManager;
@@ -344,13 +343,14 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
}
private void onTaskCreated(int taskId, @NonNull ComponentName componentName) {
- String packageName = componentName.getPackageName();
- if (!mGameClassifier.isGame(packageName, mUserHandle)) {
+ final GameTaskInfo taskInfo = mGameTaskInfoProvider.get(taskId, componentName);
+
+ if (!taskInfo.mIsGameTask) {
return;
}
synchronized (mLock) {
- gameTaskStartedLocked(taskId, componentName);
+ gameTaskStartedLocked(taskInfo);
}
}
@@ -367,7 +367,17 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
}
final GameSessionRecord gameSessionRecord = mGameSessions.get(taskId);
- if (gameSessionRecord == null || gameSessionRecord.getGameSession() == null) {
+ if (gameSessionRecord == null) {
+ if (focused) {
+ // The game session for a game task may have been destroyed when the game task
+ // was put into the background by pressing the back button. If the task is restored
+ // via the Recents UI there will be no TaskStackListener#onCreated call for the
+ // restoration, so this focus event is the first opportunity to re-create the game
+ // session.
+ maybeCreateGameSessionForFocusedTaskLocked(taskId);
+ }
+ return;
+ } else if (gameSessionRecord.getGameSession() == null) {
return;
}
@@ -379,30 +389,50 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
}
@GuardedBy("mLock")
- private void gameTaskStartedLocked(int taskId, @NonNull ComponentName componentName) {
+ private void maybeCreateGameSessionForFocusedTaskLocked(int taskId) {
+ if (DEBUG) {
+ Slog.d(TAG, "maybeRecreateGameSessionForFocusedTaskLocked() id: " + taskId);
+ }
+
+ final GameTaskInfo taskInfo = mGameTaskInfoProvider.get(taskId);
+ if (taskInfo == null) {
+ Slog.w(TAG, "No task info for focused task: " + taskId);
+ return;
+ }
+
+ if (!taskInfo.mIsGameTask) {
+ return;
+ }
+
+ gameTaskStartedLocked(taskInfo);
+ }
+
+ @GuardedBy("mLock")
+ private void gameTaskStartedLocked(@NonNull GameTaskInfo gameTaskInfo) {
if (DEBUG) {
- Slog.i(TAG, "gameStartedLocked() id: " + taskId + " component: " + componentName);
+ Slog.i(TAG, "gameStartedLocked(): " + gameTaskInfo);
}
if (!mIsRunning) {
return;
}
- GameSessionRecord existingGameSessionRecord = mGameSessions.get(taskId);
+ GameSessionRecord existingGameSessionRecord = mGameSessions.get(gameTaskInfo.mTaskId);
if (existingGameSessionRecord != null) {
- Slog.w(TAG, "Existing game session found for task (id: " + taskId
+ Slog.w(TAG, "Existing game session found for task (id: " + gameTaskInfo.mTaskId
+ ") creation. Ignoring.");
return;
}
GameSessionRecord gameSessionRecord = GameSessionRecord.awaitingGameSessionRequest(
- taskId, componentName);
- mGameSessions.put(taskId, gameSessionRecord);
+ gameTaskInfo.mTaskId, gameTaskInfo.mComponentName);
+ mGameSessions.put(gameTaskInfo.mTaskId, gameSessionRecord);
AndroidFuture<Void> unusedPostGameStartedFuture = mGameServiceConnector.post(
gameService -> {
gameService.gameStarted(
- new GameStartedEvent(taskId, componentName.getPackageName()));
+ new GameStartedEvent(gameTaskInfo.mTaskId,
+ gameTaskInfo.mComponentName.getPackageName()));
});
}
@@ -769,7 +799,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
@Nullable
private GameSessionViewHostConfiguration createViewHostConfigurationForTask(int taskId) {
- RunningTaskInfo runningTaskInfo = getRunningTaskInfoForTask(taskId);
+ RunningTaskInfo runningTaskInfo = mGameTaskInfoProvider.getRunningTaskInfo(taskId);
if (runningTaskInfo == null) {
return null;
}
@@ -781,28 +811,6 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
bounds.height());
}
- @Nullable
- private RunningTaskInfo getRunningTaskInfoForTask(int taskId) {
- List<RunningTaskInfo> runningTaskInfos;
- try {
- runningTaskInfos = mActivityTaskManager.getTasks(
- /* maxNum= */ Integer.MAX_VALUE,
- /* filterOnlyVisibleRecents= */ true,
- /* keepIntentExtra= */ false);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to fetch running tasks");
- return null;
- }
-
- for (RunningTaskInfo taskInfo : runningTaskInfos) {
- if (taskInfo.taskId == taskId) {
- return taskInfo;
- }
- }
-
- return null;
- }
-
@VisibleForTesting
void takeScreenshot(int taskId, @NonNull AndroidFuture callback) {
GameSessionRecord gameSessionRecord;
@@ -834,7 +842,8 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
} else {
final Bundle bundle = ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(
bitmap);
- final RunningTaskInfo runningTaskInfo = getRunningTaskInfoForTask(taskId);
+ final RunningTaskInfo runningTaskInfo =
+ mGameTaskInfoProvider.getRunningTaskInfo(taskId);
if (runningTaskInfo == null) {
Slog.w(TAG, "Could not get running task info for id: " + taskId);
callback.complete(GameScreenshotResult.createInternalErrorResult());
diff --git a/services/core/java/com/android/server/app/GameTaskInfo.java b/services/core/java/com/android/server/app/GameTaskInfo.java
new file mode 100644
index 000000000000..7548dbd06c5c
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameTaskInfo.java
@@ -0,0 +1,66 @@
+/*
+ * 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.app;
+
+import android.content.ComponentName;
+
+import java.util.Objects;
+
+final class GameTaskInfo {
+ final int mTaskId;
+ final boolean mIsGameTask;
+ final ComponentName mComponentName;
+
+ GameTaskInfo(int taskId, boolean isGameTask, ComponentName componentName) {
+ mTaskId = taskId;
+ mIsGameTask = isGameTask;
+ mComponentName = componentName;
+ }
+
+ @Override
+ public String toString() {
+ return "GameTaskInfo{"
+ + "mTaskId="
+ + mTaskId
+ + ", mIsGameTask="
+ + mIsGameTask
+ + ", mComponentName="
+ + mComponentName
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof GameTaskInfo)) {
+ return false;
+ }
+
+ GameTaskInfo that = (GameTaskInfo) o;
+ return mTaskId == that.mTaskId
+ && mIsGameTask == that.mIsGameTask
+ && mComponentName.equals(that.mComponentName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTaskId, mIsGameTask, mComponentName);
+ }
+}
diff --git a/services/core/java/com/android/server/app/GameTaskInfoProvider.java b/services/core/java/com/android/server/app/GameTaskInfoProvider.java
new file mode 100644
index 000000000000..f078d98e5950
--- /dev/null
+++ b/services/core/java/com/android/server/app/GameTaskInfoProvider.java
@@ -0,0 +1,121 @@
+/*
+ * 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.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.IActivityTaskManager;
+import android.content.ComponentName;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.LruCache;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.List;
+
+final class GameTaskInfoProvider {
+ private static final String TAG = "GameTaskInfoProvider";
+ private static final int TASK_INFO_CACHE_MAX_SIZE = 50;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final LruCache<Integer, GameTaskInfo> mGameTaskInfoCache = new LruCache<>(
+ TASK_INFO_CACHE_MAX_SIZE);
+
+ private final UserHandle mUserHandle;
+ private final IActivityTaskManager mActivityTaskManager;
+ private final GameClassifier mGameClassifier;
+
+ GameTaskInfoProvider(@NonNull UserHandle userHandle,
+ @NonNull IActivityTaskManager activityTaskManager,
+ @NonNull GameClassifier gameClassifier) {
+ mUserHandle = userHandle;
+ mActivityTaskManager = activityTaskManager;
+ mGameClassifier = gameClassifier;
+ }
+
+ @Nullable
+ GameTaskInfo get(int taskId) {
+ synchronized (mLock) {
+ final GameTaskInfo cachedTaskInfo = mGameTaskInfoCache.get(taskId);
+ if (cachedTaskInfo != null) {
+ return cachedTaskInfo;
+ }
+ }
+
+ final RunningTaskInfo runningTaskInfo = getRunningTaskInfo(taskId);
+ if (runningTaskInfo == null || runningTaskInfo.baseActivity == null) {
+ return null;
+ }
+
+ return generateGameInfo(taskId, runningTaskInfo.baseActivity);
+ }
+
+ GameTaskInfo get(int taskId, @NonNull ComponentName componentName) {
+ synchronized (mLock) {
+ final GameTaskInfo cachedTaskInfo = mGameTaskInfoCache.get(taskId);
+ if (cachedTaskInfo != null) {
+ if (cachedTaskInfo.mComponentName.equals(componentName)) {
+ Slog.w(TAG, "Found cached task info for taskId " + taskId
+ + " but cached component name " + cachedTaskInfo.mComponentName
+ + " does not match " + componentName);
+ } else {
+ return cachedTaskInfo;
+ }
+ }
+ }
+
+ return generateGameInfo(taskId, componentName);
+ }
+
+ @Nullable
+ RunningTaskInfo getRunningTaskInfo(int taskId) {
+ List<RunningTaskInfo> runningTaskInfos;
+ try {
+ runningTaskInfos = mActivityTaskManager.getTasks(
+ /* maxNum= */ Integer.MAX_VALUE,
+ /* filterOnlyVisibleRecents= */ false,
+ /* keepIntentExtra= */ false);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to fetch running tasks");
+ return null;
+ }
+
+ for (RunningTaskInfo taskInfo : runningTaskInfos) {
+ if (taskInfo.taskId == taskId) {
+ return taskInfo;
+ }
+ }
+
+ return null;
+ }
+
+ private GameTaskInfo generateGameInfo(int taskId, @NonNull ComponentName componentName) {
+ final GameTaskInfo gameTaskInfo = new GameTaskInfo(taskId,
+ mGameClassifier.isGame(componentName.getPackageName(), mUserHandle), componentName);
+
+ synchronized (mLock) {
+ mGameTaskInfoCache.put(taskId, gameTaskInfo);
+ }
+
+ return gameTaskInfo;
+ }
+}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index e14527098a72..dbe4fb8c8795 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -862,8 +862,8 @@ public class AudioDeviceInventory {
}
/*package*/ void disconnectLeAudio(int device) {
- if (device != AudioSystem.DEVICE_OUT_BLE_HEADSET ||
- device != AudioSystem.DEVICE_OUT_BLE_BROADCAST) {
+ if (device != AudioSystem.DEVICE_OUT_BLE_HEADSET
+ && device != AudioSystem.DEVICE_OUT_BLE_BROADCAST) {
Log.e(TAG, "disconnectLeAudio: Can't disconnect not LE Audio device " + device);
return;
}
@@ -879,6 +879,8 @@ public class AudioDeviceInventory {
new MediaMetrics.Item(mMetricsId + "disconnectLeAudio")
.record();
if (toRemove.size() > 0) {
+ final int delay = checkSendBecomingNoisyIntentInt(device, 0,
+ AudioSystem.DEVICE_NONE);
toRemove.stream().forEach(deviceAddress ->
makeLeAudioDeviceUnavailable(deviceAddress, device)
);
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index d10ed55281ef..0aa9a2bc4990 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -462,6 +462,7 @@ public class BtHelper {
mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.HEADSET);
mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.HEARING_AID);
mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.LE_AUDIO);
+ mDeviceBroker.postBtProfileDisconnected(BluetoothProfile.LE_AUDIO_BROADCAST);
}
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
@@ -687,6 +688,7 @@ public class BtHelper {
case BluetoothProfile.HEADSET:
case BluetoothProfile.HEARING_AID:
case BluetoothProfile.LE_AUDIO:
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
mDeviceBroker.postBtProfileDisconnected(profile);
break;
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 19a93f30937f..63609f77dc75 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -46,6 +46,7 @@ import java.util.Date;
import java.util.Deque;
import java.util.List;
import java.util.Locale;
+import java.util.function.Consumer;
/**
* A scheduler for biometric HAL operations. Maintains a queue of {@link BaseClientMonitor}
@@ -457,22 +458,33 @@ public class BiometricScheduler {
}
/**
+ * Get current operation <code>BaseClientMonitor</code>
+ * @deprecated TODO: b/229994966, encapsulate client monitors
* @return the current operation
*/
+ @Deprecated
+ @Nullable
public BaseClientMonitor getCurrentClient() {
return mCurrentOperation != null ? mCurrentOperation.getClientMonitor() : null;
}
- /** The current operation if the requestId is set and matches. */
+ /**
+ * The current operation if the requestId is set and matches.
+ * @deprecated TODO: b/229994966, encapsulate client monitors
+ */
@Deprecated
@Nullable
- public BaseClientMonitor getCurrentClientIfMatches(long requestId) {
- if (mCurrentOperation != null) {
- if (mCurrentOperation.isMatchingRequestId(requestId)) {
- return mCurrentOperation.getClientMonitor();
+ public void getCurrentClientIfMatches(long requestId,
+ @NonNull Consumer<BaseClientMonitor> clientMonitorConsumer) {
+ mHandler.post(() -> {
+ if (mCurrentOperation != null) {
+ if (mCurrentOperation.isMatchingRequestId(requestId)) {
+ clientMonitorConsumer.accept(mCurrentOperation.getClientMonitor());
+ return;
+ }
}
- }
- return null;
+ clientMonitorConsumer.accept(null);
+ });
}
public int getCurrentPendingCount() {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 7d5b77c2d711..998a8e1e9f90 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -582,35 +582,35 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void onPointerDown(long requestId, int sensorId, int x, int y,
float minor, float major) {
- final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
- if (!(client instanceof Udfps)) {
- Slog.e(getTag(), "onPointerDown received during client: " + client);
- return;
- }
- ((Udfps) client).onPointerDown(x, y, minor, major);
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(), "onPointerDown received during client: " + client);
+ return;
+ }
+ ((Udfps) client).onPointerDown(x, y, minor, major);
+ });
}
@Override
public void onPointerUp(long requestId, int sensorId) {
- final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
- if (!(client instanceof Udfps)) {
- Slog.e(getTag(), "onPointerUp received during client: " + client);
- return;
- }
- ((Udfps) client).onPointerUp();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(), "onPointerUp received during client: " + client);
+ return;
+ }
+ ((Udfps) client).onPointerUp();
+ });
}
@Override
public void onUiReady(long requestId, int sensorId) {
- final BaseClientMonitor client =
- mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId);
- if (!(client instanceof Udfps)) {
- Slog.e(getTag(), "onUiReady received during client: " + client);
- return;
- }
- ((Udfps) client).onUiReady();
+ mSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(), "onUiReady received during client: " + client);
+ return;
+ }
+ ((Udfps) client).onUiReady();
+ });
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 52dbe2460e1c..78a30e820c80 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -794,32 +794,35 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@Override
public void onPointerDown(long requestId, int sensorId, int x, int y,
float minor, float major) {
- final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
- if (!(client instanceof Udfps)) {
- Slog.w(TAG, "onFingerDown received during client: " + client);
- return;
- }
- ((Udfps) client).onPointerDown(x, y, minor, major);
+ mScheduler.getCurrentClientIfMatches(requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.w(TAG, "onFingerDown received during client: " + client);
+ return;
+ }
+ ((Udfps) client).onPointerDown(x, y, minor, major);
+ });
}
@Override
public void onPointerUp(long requestId, int sensorId) {
- final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
- if (!(client instanceof Udfps)) {
- Slog.w(TAG, "onFingerDown received during client: " + client);
- return;
- }
- ((Udfps) client).onPointerUp();
+ mScheduler.getCurrentClientIfMatches(requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.w(TAG, "onFingerDown received during client: " + client);
+ return;
+ }
+ ((Udfps) client).onPointerUp();
+ });
}
@Override
public void onUiReady(long requestId, int sensorId) {
- final BaseClientMonitor client = mScheduler.getCurrentClientIfMatches(requestId);
- if (!(client instanceof Udfps)) {
- Slog.w(TAG, "onUiReady received during client: " + client);
- return;
- }
- ((Udfps) client).onUiReady();
+ mScheduler.getCurrentClientIfMatches(requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.w(TAG, "onUiReady received during client: " + client);
+ return;
+ }
+ ((Udfps) client).onUiReady();
+ });
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 698f41f23e98..80ff8349a153 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1389,12 +1389,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Brightness throttling is needed, so do so quickly.
// Later, when throttling is removed, we let other mechanisms decide on speed.
slowChange = false;
- updateScreenBrightnessSetting = true;
}
mAppliedThrottling = true;
} else if (mAppliedThrottling) {
mAppliedThrottling = false;
- updateScreenBrightnessSetting = true;
}
if (updateScreenBrightnessSetting) {
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index f68d22acd6ab..4e1d899b26a6 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -17,13 +17,21 @@
package com.android.server.dreams;
import static android.Manifest.permission.BIND_DREAM_SERVICE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static com.android.server.wm.ActivityInterceptorCallback.DREAM_MANAGER_ORDERED_ID;
+
+import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.TaskInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
@@ -54,6 +62,7 @@ import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.wm.ActivityInterceptorCallback;
import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
@@ -83,6 +92,7 @@ public final class DreamManagerService extends SystemService {
private final UiEventLogger mUiEventLogger;
private final DreamUiEventLogger mDreamUiEventLogger;
private final ComponentName mAmbientDisplayComponent;
+ private final boolean mDismissDreamOnActivityStart;
private Binder mCurrentDreamToken;
private ComponentName mCurrentDreamName;
@@ -99,6 +109,26 @@ public final class DreamManagerService extends SystemService {
private ComponentName mDreamOverlayServiceName;
private AmbientDisplayConfiguration mDozeConfig;
+ private final ActivityInterceptorCallback mActivityInterceptorCallback =
+ new ActivityInterceptorCallback() {
+ @Nullable
+ @Override
+ public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
+ return null;
+ }
+
+ @Override
+ public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo,
+ ActivityInterceptorInfo info) {
+ final int activityType = taskInfo.getActivityType();
+ final boolean activityAllowed = activityType == ACTIVITY_TYPE_HOME
+ || activityType == ACTIVITY_TYPE_DREAM
+ || activityType == ACTIVITY_TYPE_ASSISTANT;
+ if (mCurrentDreamToken != null && !mCurrentDreamIsWaking && !activityAllowed) {
+ stopDreamInternal(false, "activity starting: " + activityInfo.name);
+ }
+ }
+ };
public DreamManagerService(Context context) {
super(context);
@@ -118,6 +148,8 @@ public final class DreamManagerService extends SystemService {
mAmbientDisplayComponent = ComponentName.unflattenFromString(adc.ambientDisplayComponent());
mDreamsOnlyEnabledForSystemUser =
mContext.getResources().getBoolean(R.bool.config_dreamsOnlyEnabledForSystemUser);
+ mDismissDreamOnActivityStart = mContext.getResources().getBoolean(
+ R.bool.config_dismissDreamOnActivityStart);
}
@Override
@@ -145,6 +177,12 @@ public final class DreamManagerService extends SystemService {
Settings.Secure.getUriFor(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE), false,
mDozeEnabledObserver, UserHandle.USER_ALL);
writePulseGestureEnabled();
+
+ if (mDismissDreamOnActivityStart) {
+ mAtmInternal.registerActivityStartInterceptor(
+ DREAM_MANAGER_ORDERED_ID,
+ mActivityInterceptorCallback);
+ }
}
}
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index db2cb52d778e..5253d34a38f0 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -20,7 +20,11 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UserIdInt;
+import android.app.AppGlobals;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -34,7 +38,9 @@ import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* Gets the service name using a framework resources, temporarily changing the service if necessary
@@ -49,10 +55,14 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
/** Handler message to {@link #resetTemporaryService(int)} */
private static final int MSG_RESET_TEMPORARY_SERVICE = 0;
- @NonNull private final Context mContext;
- @NonNull private final Object mLock = new Object();
- @StringRes private final int mStringResourceId;
- @ArrayRes private final int mArrayResourceId;
+ @NonNull
+ private final Context mContext;
+ @NonNull
+ private final Object mLock = new Object();
+ @StringRes
+ private final int mStringResourceId;
+ @ArrayRes
+ private final int mArrayResourceId;
private final boolean mIsMultiple;
/**
* Map of temporary service name list set by {@link #setTemporaryServices(int, String[], int)},
@@ -71,7 +81,8 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
*/
@GuardedBy("mLock")
private final SparseBooleanArray mDefaultServicesDisabled = new SparseBooleanArray();
- @Nullable private NameResolverListener mOnSetCallback;
+ @Nullable
+ private NameResolverListener mOnSetCallback;
/**
* When the temporary service will expire (and reset back to the default).
*/
@@ -160,10 +171,33 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
public String[] getDefaultServiceNameList(int userId) {
synchronized (mLock) {
if (mIsMultiple) {
- return mContext.getResources().getStringArray(mArrayResourceId);
+ String[] serviceNameList = mContext.getResources().getStringArray(mArrayResourceId);
+ // Filter out unimplemented services
+ // Initialize the validated array as null because we do not know the final size.
+ List<String> validatedServiceNameList = new ArrayList<>();
+ try {
+ for (int i = 0; i < serviceNameList.length; i++) {
+ if (TextUtils.isEmpty(serviceNameList[i])) {
+ continue;
+ }
+ ComponentName serviceComponent = ComponentName.unflattenFromString(
+ serviceNameList[i]);
+ ServiceInfo serviceInfo = AppGlobals.getPackageManager().getServiceInfo(
+ serviceComponent,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+ if (serviceInfo != null) {
+ validatedServiceNameList.add(serviceNameList[i]);
+ }
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Could not validate provided services.", e);
+ }
+ String[] validatedServiceNameArray = new String[validatedServiceNameList.size()];
+ return validatedServiceNameList.toArray(validatedServiceNameArray);
} else {
final String name = mContext.getString(mStringResourceId);
- return TextUtils.isEmpty(name) ? new String[0] : new String[] { name };
+ return TextUtils.isEmpty(name) ? new String[0] : new String[]{name};
}
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index b978131e175c..57d89dae588e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -133,10 +133,13 @@ public abstract class InputMethodManagerInternal {
*
* @param windowToken the window token that is now in control, or {@code null} if no client
* window is in control of the IME.
- * @param imeParentChanged {@code true} when the window manager thoughts the IME surface parent
- * will end up to change later, or {@code false} otherwise.
*/
- public abstract void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged);
+ public abstract void reportImeControl(@Nullable IBinder windowToken);
+
+ /**
+ * Indicates that the IME window has re-parented to the new target when the IME control changed.
+ */
+ public abstract void onImeParentChanged();
/**
* Destroys the IME surface.
@@ -226,8 +229,11 @@ public abstract class InputMethodManagerInternal {
}
@Override
- public void reportImeControl(@Nullable IBinder windowToken,
- boolean imeParentChanged) {
+ public void reportImeControl(@Nullable IBinder windowToken) {
+ }
+
+ @Override
+ public void onImeParentChanged() {
}
@Override
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ce8b9fabd5a0..6af00b3fbeea 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5700,19 +5700,23 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
- public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
+ public void reportImeControl(@Nullable IBinder windowToken) {
synchronized (ImfLock.class) {
if (mCurFocusedWindow != windowToken) {
// mCurPerceptible was set by the focused window, but it is no longer in
// control, so we reset mCurPerceptible.
mCurPerceptible = true;
}
- if (imeParentChanged) {
- // Hide the IME method menu earlier when the IME surface parent will change in
- // case seeing the dialog dismiss flickering during the next focused window
- // starting the input connection.
- mMenuController.hideInputMethodMenu();
- }
+ }
+ }
+
+ @Override
+ public void onImeParentChanged() {
+ synchronized (ImfLock.class) {
+ // Hide the IME method menu when the IME surface parent will change in
+ // case seeing the dialog dismiss flickering during the next focused window
+ // starting the input connection.
+ mMenuController.hideInputMethodMenu();
}
}
diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
index 70a222fb09c5..dc5299077cc9 100644
--- a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
@@ -34,6 +34,8 @@ import java.util.Objects;
public class SystemEmergencyHelper extends EmergencyHelper {
private final Context mContext;
+ private final EmergencyCallTelephonyCallback mEmergencyCallTelephonyCallback =
+ new EmergencyCallTelephonyCallback();
TelephonyManager mTelephonyManager;
@@ -56,7 +58,7 @@ public class SystemEmergencyHelper extends EmergencyHelper {
// TODO: this doesn't account for multisim phones
mTelephonyManager.registerTelephonyCallback(FgThread.getExecutor(),
- new EmergencyCallTelephonyCallback());
+ mEmergencyCallTelephonyCallback);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/media/MediaShellCommand.java b/services/core/java/com/android/server/media/MediaShellCommand.java
index d175d87651de..a56380827f2c 100644
--- a/services/core/java/com/android/server/media/MediaShellCommand.java
+++ b/services/core/java/com/android/server/media/MediaShellCommand.java
@@ -107,7 +107,6 @@ public class MediaShellCommand extends ShellCommand {
public void onHelp() {
mWriter.println("usage: media_session [subcommand] [options]");
mWriter.println(" media_session dispatch KEY");
- mWriter.println(" media_session dispatch KEY");
mWriter.println(" media_session list-sessions");
mWriter.println(" media_session monitor <tag>");
mWriter.println(" media_session volume [options]");
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 21ee4c21ceeb..6078bfc95488 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -252,6 +252,7 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.StatsEvent;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -284,6 +285,7 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
+import com.android.internal.widget.LockPatternUtils;
import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
import com.android.server.IoThread;
@@ -1923,6 +1925,54 @@ public class NotificationManagerService extends SystemService {
private SettingsObserver mSettingsObserver;
protected ZenModeHelper mZenModeHelper;
+ protected class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+
+ SparseBooleanArray mUserInLockDownMode = new SparseBooleanArray();
+ boolean mIsInLockDownMode = false;
+
+ StrongAuthTracker(Context context) {
+ super(context);
+ }
+
+ private boolean containsFlag(int haystack, int needle) {
+ return (haystack & needle) != 0;
+ }
+
+ public boolean isInLockDownMode() {
+ return mIsInLockDownMode;
+ }
+
+ @Override
+ public synchronized void onStrongAuthRequiredChanged(int userId) {
+ boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId),
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ mUserInLockDownMode.put(userId, userInLockDownModeNext);
+ boolean isInLockDownModeNext = mUserInLockDownMode.indexOfValue(true) != -1;
+
+ if (mIsInLockDownMode == isInLockDownModeNext) {
+ return;
+ }
+
+ if (isInLockDownModeNext) {
+ cancelNotificationsWhenEnterLockDownMode();
+ }
+
+ // When the mIsInLockDownMode is true, both notifyPostedLocked and
+ // notifyRemovedLocked will be dismissed. So we shall call
+ // cancelNotificationsWhenEnterLockDownMode before we set mIsInLockDownMode
+ // as true and call postNotificationsWhenExitLockDownMode after we set
+ // mIsInLockDownMode as false.
+ mIsInLockDownMode = isInLockDownModeNext;
+
+ if (!isInLockDownModeNext) {
+ postNotificationsWhenExitLockDownMode();
+ }
+ }
+ }
+
+ private LockPatternUtils mLockPatternUtils;
+ private StrongAuthTracker mStrongAuthTracker;
+
public NotificationManagerService(Context context) {
this(context,
new NotificationRecordLoggerImpl(),
@@ -1952,6 +2002,11 @@ public class NotificationManagerService extends SystemService {
}
@VisibleForTesting
+ void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) {
+ mStrongAuthTracker = strongAuthTracker;
+ }
+
+ @VisibleForTesting
void setKeyguardManager(KeyguardManager keyguardManager) {
mKeyguardManager = keyguardManager;
}
@@ -2145,6 +2200,8 @@ public class NotificationManagerService extends SystemService {
mPlatformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ mLockPatternUtils = new LockPatternUtils(getContext());
+ mStrongAuthTracker = new StrongAuthTracker(getContext());
mUiHandler = new Handler(UiThread.get().getLooper());
String[] extractorNames;
try {
@@ -2641,6 +2698,7 @@ public class NotificationManagerService extends SystemService {
bubbsExtractor.setShortcutHelper(mShortcutHelper);
}
registerNotificationPreferencesPullers();
+ mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
// bind to listener services.
@@ -9537,6 +9595,29 @@ public class NotificationManagerService extends SystemService {
}
}
+ private void cancelNotificationsWhenEnterLockDownMode() {
+ synchronized (mNotificationLock) {
+ int numNotifications = mNotificationList.size();
+ for (int i = 0; i < numNotifications; i++) {
+ NotificationRecord rec = mNotificationList.get(i);
+ mListeners.notifyRemovedLocked(rec, REASON_CANCEL_ALL,
+ rec.getStats());
+ }
+
+ }
+ }
+
+ private void postNotificationsWhenExitLockDownMode() {
+ synchronized (mNotificationLock) {
+ int numNotifications = mNotificationList.size();
+ for (int i = 0; i < numNotifications; i++) {
+ NotificationRecord rec = mNotificationList.get(i);
+ mListeners.notifyPostedLocked(rec, rec);
+ }
+
+ }
+ }
+
private void updateNotificationPulse() {
synchronized (mNotificationLock) {
updateLightsLocked();
@@ -9753,6 +9834,10 @@ public class NotificationManagerService extends SystemService {
rankings.toArray(new NotificationListenerService.Ranking[0]));
}
+ boolean isInLockDownMode() {
+ return mStrongAuthTracker.isInLockDownMode();
+ }
+
boolean hasCompanionDevice(ManagedServiceInfo info) {
if (mCompanionManager == null) {
mCompanionManager = getCompanionManager();
@@ -10804,8 +10889,12 @@ public class NotificationManagerService extends SystemService {
* targetting <= O_MR1
*/
@GuardedBy("mNotificationLock")
- private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
+ void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
boolean notifyAllListeners) {
+ if (isInLockDownMode()) {
+ return;
+ }
+
try {
// Lazily initialized snapshots of the notification.
StatusBarNotification sbn = r.getSbn();
@@ -10903,6 +10992,10 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mNotificationLock")
public void notifyRemovedLocked(NotificationRecord r, int reason,
NotificationStats notificationStats) {
+ if (isInLockDownMode()) {
+ return;
+ }
+
final StatusBarNotification sbn = r.getSbn();
// make a copy in case changes are made to the underlying Notification object
@@ -10948,6 +11041,10 @@ public class NotificationManagerService extends SystemService {
*/
@GuardedBy("mNotificationLock")
public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
+ if (isInLockDownMode()) {
+ return;
+ }
+
boolean isHiddenRankingUpdate = changedHiddenNotifications != null
&& changedHiddenNotifications.size() > 0;
// TODO (b/73052211): if the ranking update changed the notification type,
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 8bd1da9fbe9b..57a1fe04b690 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -2545,7 +2545,6 @@ final class InstallPackageHelper {
ArrayList<String>[] components;
int size = 0;
int[] uids;
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPm.mLock) {
final SparseArray<ArrayMap<String, ArrayList<String>>> userIdToPackagesToComponents =
@@ -2584,7 +2583,6 @@ final class InstallPackageHelper {
mPm.sendPackageChangedBroadcast(snapshot, packages[i], true /* dontKillApp */,
components[i], uids[i], null /* reason */);
}
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
void handlePackagePostInstall(PackageInstalledInfo res, InstallArgs installArgs,
@@ -4189,8 +4187,8 @@ final class InstallPackageHelper {
assertOverlayIsValid(pkg, parseFlags, scanFlags);
}
- // If the package is not on a system partition ensure it is signed with at least the
- // minimum signature scheme version required for its target SDK.
+ // Ensure the package is signed with at least the minimum signature scheme version
+ // required for its target SDK.
ScanPackageUtils.assertMinSignatureSchemeIsValid(pkg, parseFlags);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
index e8faca9765f8..0dfa31c5f1fc 100644
--- a/services/core/java/com/android/server/pm/PackageHandler.java
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -75,7 +75,7 @@ final class PackageHandler extends Handler {
try {
doHandleMessage(msg);
} finally {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
}
}
@@ -136,19 +136,13 @@ final class PackageHandler extends Handler {
}
} break;
case WRITE_SETTINGS: {
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
mPm.writeSettings();
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
case WRITE_PACKAGE_RESTRICTIONS: {
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
mPm.writePendingRestrictions();
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
case WRITE_PACKAGE_LIST: {
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
mPm.writePackageList(msg.arg1);
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
case CHECK_PENDING_VERIFICATION: {
final int verificationId = msg.arg1;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 88564aa2e935..2cef35fcf0f6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1413,7 +1413,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
t.traceBegin("create package manager");
final PackageManagerTracedLock lock = new PackageManagerTracedLock();
final Object installLock = new Object();
- HandlerThread backgroundThread = new HandlerThread("PackageManagerBg");
+
+ HandlerThread backgroundThread = new ServiceThread("PackageManagerBg",
+ Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
backgroundThread.start();
Handler backgroundHandler = new Handler(backgroundThread.getLooper());
@@ -1467,7 +1469,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
(i, pm) -> domainVerificationService,
(i, pm) -> {
HandlerThread thread = new ServiceThread(TAG,
- Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
+ Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
thread.start();
return new PackageHandler(thread.getLooper(), pm);
},
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 78a600e34dae..6b10d4c17527 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -159,13 +159,14 @@ class PackageManagerShellCommand extends ShellCommand {
private static final Map<String, Integer> SUPPORTED_PERMISSION_FLAGS = new ArrayMap<>();
private static final List<String> SUPPORTED_PERMISSION_FLAGS_LIST;
static {
+ SUPPORTED_PERMISSION_FLAGS_LIST = List.of("review-required", "revoked-compat",
+ "revoke-when-requested", "user-fixed", "user-set");
SUPPORTED_PERMISSION_FLAGS.put("user-set", FLAG_PERMISSION_USER_SET);
SUPPORTED_PERMISSION_FLAGS.put("user-fixed", FLAG_PERMISSION_USER_FIXED);
SUPPORTED_PERMISSION_FLAGS.put("revoked-compat", FLAG_PERMISSION_REVOKED_COMPAT);
SUPPORTED_PERMISSION_FLAGS.put("review-required", FLAG_PERMISSION_REVIEW_REQUIRED);
SUPPORTED_PERMISSION_FLAGS.put("revoke-when-requested",
FLAG_PERMISSION_REVOKE_WHEN_REQUESTED);
- SUPPORTED_PERMISSION_FLAGS_LIST = new ArrayList<>(SUPPORTED_PERMISSION_FLAGS.keySet());
}
final IPackageManager mInterface;
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 4e8313bf1891..0dc188b75d5e 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -690,16 +690,14 @@ final class ScanPackageUtils {
public static void assertMinSignatureSchemeIsValid(AndroidPackage pkg,
@ParsingPackageUtils.ParseFlags int parseFlags) throws PackageManagerException {
- if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) {
- int minSignatureSchemeVersion =
- ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
- pkg.getTargetSdkVersion());
- if (pkg.getSigningDetails().getSignatureSchemeVersion()
- < minSignatureSchemeVersion) {
- throw new PackageManagerException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
- "No signature found in package of version " + minSignatureSchemeVersion
- + " or newer for package " + pkg.getPackageName());
- }
+ int minSignatureSchemeVersion =
+ ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
+ pkg.getTargetSdkVersion());
+ if (pkg.getSigningDetails().getSignatureSchemeVersion()
+ < minSignatureSchemeVersion) {
+ throw new PackageManagerException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "No signature found in package of version " + minSignatureSchemeVersion
+ + " or newer for package " + pkg.getPackageName());
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a1b4b30c18cd..ba4d09f28d05 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -164,6 +164,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
@@ -633,8 +634,8 @@ public final class Settings implements Watchable, Snappable {
runtimePermissionsPersistence, new Consumer<Integer>() {
@Override
public void accept(Integer userId) {
- mRuntimePermissionsPersistence.writeStateForUser(userId,
- mPermissionDataProvider, mPackages, mSharedUsers, mHandler, mLock);
+ mRuntimePermissionsPersistence.writeStateForUser(userId, mPermissionDataProvider,
+ mPackages, mSharedUsers, mHandler, mLock, /*sync=*/false);
}
});
mPermissionDataProvider = permissionDataProvider;
@@ -5292,7 +5293,7 @@ public final class Settings implements Watchable, Snappable {
public void writePermissionStateForUserLPr(int userId, boolean sync) {
if (sync) {
mRuntimePermissionsPersistence.writeStateForUser(userId, mPermissionDataProvider,
- mPackages, mSharedUsers, /*handler=*/null, mLock);
+ mPackages, mSharedUsers, /*handler=*/null, mLock, /*sync=*/true);
} else {
mRuntimePermissionsPersistence.writeStateForUserAsync(userId);
}
@@ -5370,12 +5371,17 @@ public final class Settings implements Watchable, Snappable {
}
private static final class RuntimePermissionPersistence {
- private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 200;
+ // 200-400ms delay to avoid monopolizing PMS lock when written for multiple users.
+ private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 300;
+ private static final double WRITE_PERMISSIONS_DELAY_JITTER = 0.3;
+
private static final long MAX_WRITE_PERMISSIONS_DELAY_MILLIS = 2000;
private static final int UPGRADE_VERSION = -1;
private static final int INITIAL_VERSION = 0;
+ private static final Random sRandom = new Random();
+
private String mExtendedFingerprint;
@GuardedBy("mPersistenceLock")
@@ -5397,6 +5403,11 @@ public final class Settings implements Watchable, Snappable {
private final SparseLongArray mLastNotWrittenMutationTimesMillis = new SparseLongArray();
@GuardedBy("mLock")
+ // Tracking the mutations that haven't yet been written to legacy state.
+ // This avoids unnecessary work when writing settings for multiple users.
+ private boolean mIsLegacyPermissionStateStale = false;
+
+ @GuardedBy("mLock")
// The mapping keys are user ids.
private final SparseIntArray mVersions = new SparseIntArray();
@@ -5472,9 +5483,22 @@ public final class Settings implements Watchable, Snappable {
return PackagePartitions.FINGERPRINT + "?pc_version=" + version;
}
+ private static long uniformRandom(double low, double high) {
+ double mag = high - low;
+ return (long) (sRandom.nextDouble() * mag + low);
+ }
+
+ private static long nextWritePermissionDelayMillis() {
+ final long delay = WRITE_PERMISSIONS_DELAY_MILLIS;
+ final double jitter = WRITE_PERMISSIONS_DELAY_JITTER;
+ return delay + uniformRandom(-jitter * delay, jitter * delay);
+ }
+
public void writeStateForUserAsync(int userId) {
synchronized (mLock) {
+ mIsLegacyPermissionStateStale = true;
final long currentTimeMillis = SystemClock.uptimeMillis();
+ final long writePermissionDelayMillis = nextWritePermissionDelayMillis();
if (mWriteScheduled.get(userId)) {
mAsyncHandler.removeMessages(userId);
@@ -5493,7 +5517,7 @@ public final class Settings implements Watchable, Snappable {
// Hold off a bit more as settings are frequently changing.
final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis
+ MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0);
- final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS,
+ final long writeDelayMillis = Math.min(writePermissionDelayMillis,
maxDelayMillis);
Message message = mAsyncHandler.obtainMessage(userId);
@@ -5501,7 +5525,7 @@ public final class Settings implements Watchable, Snappable {
} else {
mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);
Message message = mAsyncHandler.obtainMessage(userId);
- mAsyncHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);
+ mAsyncHandler.sendMessageDelayed(message, writePermissionDelayMillis);
mWriteScheduled.put(userId, true);
}
}
@@ -5511,21 +5535,27 @@ public final class Settings implements Watchable, Snappable {
legacyPermissionDataProvider,
@NonNull WatchedArrayMap<String, ? extends PackageStateInternal> packageStates,
@NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers,
- @Nullable Handler pmHandler, @NonNull Object pmLock) {
+ @Nullable Handler pmHandler, @NonNull Object pmLock,
+ boolean sync) {
final int version;
final String fingerprint;
+ final boolean isLegacyPermissionStateStale;
synchronized (mLock) {
mAsyncHandler.removeMessages(userId);
mWriteScheduled.delete(userId);
version = mVersions.get(userId, INITIAL_VERSION);
fingerprint = mFingerprints.get(userId);
+ isLegacyPermissionStateStale = mIsLegacyPermissionStateStale;
+ mIsLegacyPermissionStateStale = false;
}
Runnable writer = () -> {
final RuntimePermissionsState runtimePermissions;
synchronized (pmLock) {
- legacyPermissionDataProvider.writeLegacyPermissionStateTEMP();
+ if (sync || isLegacyPermissionStateStale) {
+ legacyPermissionDataProvider.writeLegacyPermissionStateTEMP();
+ }
Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
new ArrayMap<>();
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 2960bc9a3790..c0c234953297 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -420,4 +420,14 @@ class ShortcutLauncher extends ShortcutPackageItem {
ArraySet<String> getAllPinnedShortcutsForTest(String packageName, int packageUserId) {
return new ArraySet<>(mPinnedShortcuts.get(PackageWithUser.of(packageUserId, packageName)));
}
+
+ @Override
+ protected File getShortcutPackageItemFile() {
+ final File path = new File(mShortcutUser.mService.injectUserDataPath(
+ mShortcutUser.getUserId()), ShortcutUser.DIRECTORY_LUANCHERS);
+ // Package user id and owner id can have different values for ShortcutLaunchers. Adding
+ // user Id to the file name to create a unique path. Owner id is used in the root path.
+ final String fileName = getPackageName() + getPackageUserId() + ".xml";
+ return new File(path, fileName);
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index f57eaaef25a4..fef6ce1f67b3 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -160,8 +160,6 @@ class ShortcutPackage extends ShortcutPackageItem {
private static final String KEY_BITMAPS = "bitmaps";
private static final String KEY_BITMAP_BYTES = "bitmapBytes";
- private final Object mLock = new Object();
-
private final Executor mExecutor;
/**
@@ -779,7 +777,7 @@ class ShortcutPackage extends ShortcutPackageItem {
return false;
}
mApiCallCount++;
- s.scheduleSaveUser(getOwnerUserId());
+ scheduleSave();
return true;
}
@@ -789,7 +787,7 @@ class ShortcutPackage extends ShortcutPackageItem {
}
if (mApiCallCount > 0) {
mApiCallCount = 0;
- mShortcutUser.mService.scheduleSaveUser(getOwnerUserId());
+ scheduleSave();
}
}
@@ -1890,15 +1888,12 @@ class ShortcutPackage extends ShortcutPackageItem {
final ShortcutPackage ret = new ShortcutPackage(shortcutUser,
shortcutUser.getUserId(), packageName);
-
synchronized (ret.mLock) {
ret.mIsAppSearchSchemaUpToDate = ShortcutService.parseIntAttribute(
parser, ATTR_SCHEMA_VERSON, 0) == AppSearchShortcutInfo.SCHEMA_VERSION;
}
- ret.mApiCallCount =
- ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
- ret.mLastResetTime =
- ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
+ ret.mApiCallCount = ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
+ ret.mLastResetTime = ShortcutService.parseLongAttribute(parser, ATTR_LAST_RESET);
final int outerDepth = parser.getDepth();
@@ -2440,16 +2435,15 @@ class ShortcutPackage extends ShortcutPackageItem {
})));
}
- void persistsAllShortcutsAsync() {
- synchronized (mLock) {
- final Map<String, ShortcutInfo> copy = mShortcuts;
- if (!mTransientShortcuts.isEmpty()) {
- copy.putAll(mTransientShortcuts);
- mTransientShortcuts.clear();
- }
- saveShortcutsAsync(copy.values().stream().filter(ShortcutInfo::usesQuota).collect(
- Collectors.toList()));
+ @Override
+ void scheduleSaveToAppSearchLocked() {
+ final Map<String, ShortcutInfo> copy = new ArrayMap<>(mShortcuts);
+ if (!mTransientShortcuts.isEmpty()) {
+ copy.putAll(mTransientShortcuts);
+ mTransientShortcuts.clear();
}
+ saveShortcutsAsync(copy.values().stream().filter(ShortcutInfo::usesQuota).collect(
+ Collectors.toList()));
}
private void saveShortcutsAsync(
@@ -2548,4 +2542,12 @@ class ShortcutPackage extends ShortcutPackageItem {
Binder.restoreCallingIdentity(callingIdentity);
}
}
+
+ @Override
+ protected File getShortcutPackageItemFile() {
+ final File path = new File(mShortcutUser.mService.injectUserDataPath(
+ mShortcutUser.getUserId()), ShortcutUser.DIRECTORY_PACKAGES);
+ final String fileName = getPackageName() + ".xml";
+ return new File(path, fileName);
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 829133c9854a..6e0436f208e3 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -23,6 +23,7 @@ import android.util.Slog;
import android.util.TypedXmlSerializer;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import org.json.JSONException;
@@ -36,7 +37,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
- * All methods should be guarded by {@code #mShortcutUser.mService.mLock}.
+ * All methods should be either guarded by {@code #mShortcutUser.mService.mLock} or {@code #mLock}.
*/
abstract class ShortcutPackageItem {
private static final String TAG = ShortcutService.TAG;
@@ -49,6 +50,8 @@ abstract class ShortcutPackageItem {
protected ShortcutUser mShortcutUser;
+ protected final Object mLock = new Object();
+
protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser,
int packageUserId, @NonNull String packageName,
@NonNull ShortcutPackageInfo packageInfo) {
@@ -98,7 +101,7 @@ abstract class ShortcutPackageItem {
}
final ShortcutService s = mShortcutUser.mService;
mPackageInfo.refreshSignature(s, this);
- s.scheduleSaveUser(getOwnerUserId());
+ scheduleSave();
}
public void attemptToRestoreIfNeededAndSave() {
@@ -138,7 +141,7 @@ abstract class ShortcutPackageItem {
// Either way, it's no longer a shadow.
mPackageInfo.setShadow(false);
- s.scheduleSaveUser(mPackageUserId);
+ scheduleSave();
}
protected abstract boolean canRestoreAnyVersion();
@@ -148,7 +151,8 @@ abstract class ShortcutPackageItem {
public abstract void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
throws IOException, XmlPullParserException;
- public void saveToFile(File path, boolean forBackup) {
+ @GuardedBy("mLock")
+ public void saveToFileLocked(File path, boolean forBackup) {
final AtomicFile file = new AtomicFile(path);
FileOutputStream os = null;
try {
@@ -176,6 +180,11 @@ abstract class ShortcutPackageItem {
}
}
+ @GuardedBy("mLock")
+ void scheduleSaveToAppSearchLocked() {
+
+ }
+
public JSONObject dumpCheckin(boolean clear) throws JSONException {
final JSONObject result = new JSONObject();
result.put(KEY_NAME, mPackageName);
@@ -187,4 +196,36 @@ abstract class ShortcutPackageItem {
*/
public void verifyStates() {
}
+
+ public void scheduleSave() {
+ mShortcutUser.mService.injectPostToHandlerDebounced(
+ mSaveShortcutPackageRunner, mSaveShortcutPackageRunner);
+ }
+
+ private final Runnable mSaveShortcutPackageRunner = this::saveShortcutPackageItem;
+
+ void saveShortcutPackageItem() {
+ // Wait for bitmap saves to conclude before proceeding to saving shortcuts.
+ mShortcutUser.mService.waitForBitmapSaves();
+ // Save each ShortcutPackageItem in a separate Xml file.
+ final File path = getShortcutPackageItemFile();
+ if (ShortcutService.DEBUG || ShortcutService.DEBUG_REBOOT) {
+ Slog.d(TAG, "Saving package item " + getPackageName() + " to " + path);
+ }
+ synchronized (mLock) {
+ path.getParentFile().mkdirs();
+ // TODO: Since we are persisting shortcuts into AppSearch, we should read from/write to
+ // AppSearch as opposed to maintaining a separate XML file.
+ saveToFileLocked(path, false /*forBackup*/);
+ scheduleSaveToAppSearchLocked();
+ }
+ }
+
+ void removeShortcutPackageItem() {
+ synchronized (mLock) {
+ getShortcutPackageItemFile().delete();
+ }
+ }
+
+ protected abstract File getShortcutPackageItemFile();
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 9627c4394db7..780f976d2a40 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -748,7 +748,7 @@ public class ShortcutService extends IShortcutService.Stub {
getUserShortcutsLocked(userId).cancelAllInFlightTasks();
// Save all dirty information.
- saveDirtyInfo(false);
+ saveDirtyInfo();
// Unload
mUsers.delete(userId);
@@ -1203,10 +1203,6 @@ public class ShortcutService extends IShortcutService.Stub {
@VisibleForTesting
void saveDirtyInfo() {
- saveDirtyInfo(true);
- }
-
- private void saveDirtyInfo(boolean saveShortcutsInAppSearch) {
if (DEBUG || DEBUG_REBOOT) {
Slog.d(TAG, "saveDirtyInfo");
}
@@ -1221,10 +1217,6 @@ public class ShortcutService extends IShortcutService.Stub {
if (userId == UserHandle.USER_NULL) { // USER_NULL for base state.
saveBaseStateLocked();
} else {
- if (saveShortcutsInAppSearch) {
- getUserShortcutsLocked(userId).forAllPackages(
- ShortcutPackage::persistsAllShortcutsAsync);
- }
saveUserLocked(userId);
}
}
@@ -1816,7 +1808,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
injectPostToHandlerDebounced(sp, notifyListenerRunnable(packageName, userId));
notifyShortcutChangeCallbacks(packageName, userId, changedShortcuts, removedShortcuts);
- scheduleSaveUser(userId);
+ sp.scheduleSave();
}
private void notifyListeners(@NonNull final String packageName, @UserIdInt final int userId) {
@@ -2878,12 +2870,11 @@ public class ShortcutService extends IShortcutService.Stub {
final ShortcutUser user = getUserShortcutsLocked(owningUserId);
boolean doNotify = false;
-
// First, remove the package from the package list (if the package is a publisher).
- if (packageUserId == owningUserId) {
- if (user.removePackage(packageName) != null) {
- doNotify = true;
- }
+ final ShortcutPackage sp = (packageUserId == owningUserId)
+ ? user.removePackage(packageName) : null;
+ if (sp != null) {
+ doNotify = true;
}
// Also remove from the launcher list (if the package is a launcher).
@@ -2906,6 +2897,10 @@ public class ShortcutService extends IShortcutService.Stub {
// notifyListeners.
user.rescanPackageIfNeeded(packageName, /* forceRescan=*/ true);
}
+ if (!appStillExists && (packageUserId == owningUserId) && sp != null) {
+ // If the app is removed altogether, we can get rid of the xml as well
+ injectPostToHandler(() -> sp.removeShortcutPackageItem());
+ }
if (!wasUserLoaded) {
// Note this will execute the scheduled save.
@@ -3788,7 +3783,7 @@ public class ShortcutService extends IShortcutService.Stub {
if (mHandler.hasCallbacks(mSaveDirtyInfoRunner)) {
mHandler.removeCallbacks(mSaveDirtyInfoRunner);
forEachLoadedUserLocked(ShortcutUser::cancelAllInFlightTasks);
- saveDirtyInfo(false);
+ saveDirtyInfo();
}
mShutdown.set(true);
}
@@ -4457,7 +4452,7 @@ public class ShortcutService extends IShortcutService.Stub {
// Save to the filesystem.
scheduleSaveUser(userId);
- saveDirtyInfo(false);
+ saveDirtyInfo();
// Note, in case of backup, we don't have to wait on bitmap saving, because we don't
// back up bitmaps anyway.
@@ -5352,8 +5347,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
- @VisibleForTesting
- void waitForBitmapSavesForTest() {
+ void waitForBitmapSaves() {
synchronized (mLock) {
mShortcutBitmapSaver.waitForAllSavesLocked();
}
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 4bb5dcfa4b26..75e18b547c55 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -407,35 +407,10 @@ class ShortcutUser {
}
spi.saveToXml(out, forBackup);
} else {
- // Save each ShortcutPackageItem in a separate Xml file.
- final File path = getShortcutPackageItemFile(spi);
- if (ShortcutService.DEBUG || ShortcutService.DEBUG_REBOOT) {
- Slog.d(TAG, "Saving package item " + spi.getPackageName() + " to " + path);
- }
-
- path.getParentFile().mkdirs();
- spi.saveToFile(path, forBackup);
+ spi.saveShortcutPackageItem();
}
}
- private File getShortcutPackageItemFile(ShortcutPackageItem spi) {
- boolean isShortcutLauncher = spi instanceof ShortcutLauncher;
-
- final File path = new File(mService.injectUserDataPath(mUserId),
- isShortcutLauncher ? DIRECTORY_LUANCHERS : DIRECTORY_PACKAGES);
-
- final String fileName;
- if (isShortcutLauncher) {
- // Package user id and owner id can have different values for ShortcutLaunchers. Adding
- // user Id to the file name to create a unique path. Owner id is used in the root path.
- fileName = spi.getPackageName() + spi.getPackageUserId() + ".xml";
- } else {
- fileName = spi.getPackageName() + ".xml";
- }
-
- return new File(path, fileName);
- }
-
public static ShortcutUser loadFromXml(ShortcutService s, TypedXmlPullParser parser, int userId,
boolean fromBackup) throws IOException, XmlPullParserException, InvalidFileFormatException {
final ShortcutUser ret = new ShortcutUser(s, userId);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 358e71a70550..0dabff8370ba 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4291,7 +4291,7 @@ public class UserManagerService extends IUserManager.Stub {
for (int i = 0; i < userSize; i++) {
final UserData user = mUsers.valueAt(i);
if (DBG) Slog.d(LOG_TAG, i + ":" + user.info.toFullString());
- if (user.info.preCreated && user.info.userType.equals(userType)) {
+ if (user.info.preCreated && !user.info.partial && user.info.userType.equals(userType)) {
if (!user.info.isInitialized()) {
Slog.w(LOG_TAG, "found pre-created user of type " + userType
+ ", but it's not initialized yet: " + user.info.toFullString());
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 0311524cd768..a04f6d64ef8f 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -21,6 +21,7 @@ import static android.os.Process.FIRST_APPLICATION_UID;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.DownloadManager;
import android.app.SearchManager;
@@ -903,14 +904,6 @@ final class DefaultPermissionGrantPolicy {
COARSE_BACKGROUND_LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS);
}
- // Attention Service
- String attentionServicePackageName =
- mContext.getPackageManager().getAttentionServicePackageName();
- if (!TextUtils.isEmpty(attentionServicePackageName)) {
- grantPermissionsToSystemPackage(pm, attentionServicePackageName, userId,
- CAMERA_PERMISSIONS);
- }
-
// There is no real "marker" interface to identify the shared storage backup, it is
// hardcoded in BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE.
grantSystemFixedPermissionsToSystemPackage(pm, "com.android.sharedstoragebackup", userId,
@@ -1093,6 +1086,14 @@ final class DefaultPermissionGrantPolicy {
}
}
+ public void grantDefaultPermissionsToCarrierServiceApp(@NonNull String packageName,
+ @UserIdInt int userId) {
+ Log.i(TAG, "Grant permissions to Carrier Service app " + packageName + " for user:"
+ + userId);
+ grantPermissionsToPackage(NO_PM_CACHE, packageName, userId, /* ignoreSystemPackage */ false,
+ /* whitelistRestricted */ true, NOTIFICATION_PERMISSIONS);
+ }
+
private String getDefaultSystemHandlerActivityPackage(PackageManagerWrapper pm,
String intentAction, int userId) {
return getDefaultSystemHandlerActivityPackage(pm, new Intent(intentAction), userId);
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
index ea554d3d7996..360a04f7e9bc 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
@@ -18,6 +18,7 @@ package com.android.server.pm.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
@@ -248,6 +249,15 @@ public class LegacyPermissionManagerService extends ILegacyPermissionManager.Stu
}
@Override
+ public void grantDefaultPermissionsToCarrierServiceApp(@NonNull String packageName,
+ @UserIdInt int userId) {
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "grantDefaultPermissionsForCarrierServiceApp");
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .grantDefaultPermissionsToCarrierServiceApp(packageName, userId));
+ }
+
+ @Override
public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 092f3bec4012..d9e74f8a6afd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -767,8 +767,8 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
flagValues &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
flagValues &= ~FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
flagValues &= ~PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
- // REVIEW_REQUIRED can only be set by non-system apps for POST_NOTIFICATIONS, or by the
- // shell or root UID.
+ // REVIEW_REQUIRED can be set on any permission by the shell or the root uid, or by
+ // any app for the POST_NOTIFICATIONS permission specifically.
if (!POST_NOTIFICATIONS.equals(permName) && callingUid != Process.SHELL_UID
&& callingUid != Process.ROOT_UID) {
flagValues &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
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 9897c42e4cec..e1ff9ead6740 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
@@ -3105,11 +3105,9 @@ public class ParsingPackageUtils {
}
final ParseResult<SigningDetails> verified;
if (skipVerify) {
- // systemDir APKs are already trusted, save time by not verifying; since the
- // signature is not verified and some system apps can have their V2+ signatures
- // stripped allow pulling the certs from the jar signature.
+ // systemDir APKs are already trusted, save time by not verifying
verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(input, baseCodePath,
- SigningDetails.SignatureSchemeVersion.JAR);
+ minSignatureScheme);
} else {
verified = ApkSignatureVerifier.verify(input, baseCodePath, minSignatureScheme);
}
diff --git a/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING b/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
index ba4a62cdbbf1..8a1982a339ea 100644
--- a/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/verify/domain/TEST_MAPPING
@@ -12,9 +12,6 @@
"name": "CtsDomainVerificationDeviceStandaloneTestCases"
},
{
- "name": "CtsDomainVerificationDeviceMultiUserTestCases"
- },
- {
"name": "CtsDomainVerificationHostTestCases"
}
]
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
index 92b9944b74cf..77885c7ab8ba 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
@@ -74,10 +74,13 @@ public abstract class PermissionPolicyInternal {
*
* @param taskInfo The task to be checked
* @param currPkg The package of the current top visible activity
+ * @param callingPkg The package that started the top visible activity
* @param intent The intent of the current top visible activity
+ * @param activityName The name of the current top visible activity
*/
public abstract boolean shouldShowNotificationDialogForTask(@Nullable TaskInfo taskInfo,
- @Nullable String currPkg, @Nullable Intent intent);
+ @Nullable String currPkg, @Nullable String callingPkg, @Nullable Intent intent,
+ @NonNull String activityName);
/**
* @return true if an intent will resolve to a permission request dialog activity
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 89ac9e773906..7ba1cadc5c8b 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -35,6 +35,7 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
@@ -66,11 +67,13 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.permission.LegacyPermissionManager;
import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
import android.provider.Settings;
import android.provider.Telephony;
import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -106,6 +109,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
/**
@@ -163,6 +167,7 @@ public final class PermissionPolicyService extends SystemService {
private PackageManagerInternal mPackageManagerInternal;
private PermissionManagerServiceInternal mPermissionManagerInternal;
private NotificationManagerInternal mNotificationManager;
+ private TelephonyManager mTelephonyManager;
private final KeyguardManager mKeyguardManager;
private final PackageManager mPackageManager;
private final Handler mHandler;
@@ -384,6 +389,13 @@ public final class PermissionPolicyService extends SystemService {
public void onBootPhase(int phase) {
if (DEBUG) Slog.i(LOG_TAG, "onBootPhase(" + phase + ")");
+ if (phase == PHASE_DEVICE_SPECIFIC_SERVICES_READY) {
+ registerCarrierPrivilegesCallbacks();
+ IntentFilter filter =
+ new IntentFilter(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
+ mContext.registerReceiver(mSimConfigBroadcastReceiver, filter);
+ }
+
if (phase == PHASE_ACTIVITY_MANAGER_READY) {
final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
@@ -408,6 +420,94 @@ public final class PermissionPolicyService extends SystemService {
}
+ private void initTelephonyManagerIfNeeded() {
+ if (mTelephonyManager == null) {
+ mTelephonyManager = TelephonyManager.from(mContext);
+ }
+ }
+
+ private void registerCarrierPrivilegesCallbacks() {
+ initTelephonyManagerIfNeeded();
+ if (mTelephonyManager == null) {
+ return;
+ }
+
+ int numPhones = mTelephonyManager.getActiveModemCount();
+ for (int i = 0; i < numPhones; i++) {
+ PhoneCarrierPrivilegesCallback callback = new PhoneCarrierPrivilegesCallback(i);
+ mPhoneCarrierPrivilegesCallbacks.add(callback);
+ mTelephonyManager.registerCarrierPrivilegesCallback(i, mContext.getMainExecutor(),
+ callback);
+ }
+ }
+
+ private void unregisterCarrierPrivilegesCallback() {
+ initTelephonyManagerIfNeeded();
+ if (mTelephonyManager == null) {
+ return;
+ }
+
+ for (int i = 0; i < mPhoneCarrierPrivilegesCallbacks.size(); i++) {
+ PhoneCarrierPrivilegesCallback callback = mPhoneCarrierPrivilegesCallbacks.get(i);
+ if (callback != null) {
+ mTelephonyManager.unregisterCarrierPrivilegesCallback(callback);
+ }
+ }
+ mPhoneCarrierPrivilegesCallbacks.clear();
+ }
+
+ private final class PhoneCarrierPrivilegesCallback
+ implements TelephonyManager.CarrierPrivilegesCallback {
+ private int mPhoneId;
+
+ PhoneCarrierPrivilegesCallback(int phoneId) {
+ mPhoneId = phoneId;
+ }
+ @Override
+ public void onCarrierPrivilegesChanged(
+ @NonNull Set<String> privilegedPackageNames,
+ @NonNull Set<Integer> privilegedUids) {
+ initTelephonyManagerIfNeeded();
+ if (mTelephonyManager == null) {
+ Log.e(LOG_TAG, "Cannot grant default permissions to Carrier Service app. "
+ + "TelephonyManager is null");
+ return;
+ }
+
+ String servicePkg = mTelephonyManager.getCarrierServicePackageNameForLogicalSlot(
+ mPhoneId);
+ if (servicePkg == null) {
+ return;
+ }
+ int[] users = LocalServices.getService(UserManagerInternal.class).getUserIds();
+ LegacyPermissionManager legacyPermManager =
+ mContext.getSystemService(LegacyPermissionManager.class);
+ for (int i = 0; i < users.length; i++) {
+ try {
+ mPackageManager.getPackageInfoAsUser(servicePkg, 0, users[i]);
+ legacyPermManager.grantDefaultPermissionsToCarrierServiceApp(
+ servicePkg, users[i]);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Do nothing if the package does not exist for the specified user
+ }
+ }
+ }
+ }
+
+ private final ArrayList<PhoneCarrierPrivilegesCallback> mPhoneCarrierPrivilegesCallbacks =
+ new ArrayList<>();
+
+ private final BroadcastReceiver mSimConfigBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED.equals(intent.getAction())) {
+ return;
+ }
+ unregisterCarrierPrivilegesCallback();
+ registerCarrierPrivilegesCallbacks();
+ }
+ };
+
/**
* @return Whether the user is started but not yet stopped
*/
@@ -1067,7 +1167,8 @@ public final class PermissionPolicyService extends SystemService {
ActivityInterceptorInfo info) {
super.onActivityLaunched(taskInfo, activityInfo, info);
if (!shouldShowNotificationDialogOrClearFlags(taskInfo,
- activityInfo.packageName, info.intent, info.checkedOptions, true)
+ activityInfo.packageName, info.callingPackage, info.intent,
+ info.checkedOptions, activityInfo.name, true)
|| isNoDisplayActivity(activityInfo)) {
return;
}
@@ -1138,9 +1239,9 @@ public final class PermissionPolicyService extends SystemService {
@Override
public boolean shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg,
- Intent intent) {
- return shouldShowNotificationDialogOrClearFlags(
- taskInfo, currPkg, intent, null, false);
+ String callingPkg, Intent intent, String activityName) {
+ return shouldShowNotificationDialogOrClearFlags(taskInfo, currPkg, callingPkg, intent,
+ null, activityName, false);
}
private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo) {
@@ -1166,23 +1267,61 @@ public final class PermissionPolicyService extends SystemService {
* 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or
* 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER), or
* 3. The activity belongs to the same package as the one which launched the task
- * originally, and the task was started with a launcher intent
+ * originally, and the task was started with a launcher intent, or
+ * 4. The activity is the first activity in a new task, and was started by the app the
+ * activity belongs to, and that app has another task that is currently focused, which was
+ * started with a launcher intent. This case seeks to identify cases where an app launches,
+ * then immediately trampolines to a new activity and task.
* @param taskInfo The task to be checked
* @param currPkg The package of the current top visible activity
+ * @param callingPkg The package that initiated this dialog action
* @param intent The intent of the current top visible activity
+ * @param options The ActivityOptions of the newly started activity, if this is called due
+ * to an activity start
+ * @param startedActivity The ActivityInfo of the newly started activity, if this is called
+ * due to an activity start
*/
private boolean shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg,
- Intent intent, ActivityOptions options, boolean activityStart) {
- if (intent == null || currPkg == null || taskInfo == null
+ String callingPkg, Intent intent, ActivityOptions options,
+ String topActivityName, boolean startedActivity) {
+ if (intent == null || currPkg == null || taskInfo == null || topActivityName == null
|| (!(taskInfo.isFocused && taskInfo.isVisible && taskInfo.isRunning)
- && !activityStart)) {
+ && !startedActivity)) {
return false;
}
-
return isLauncherIntent(intent)
|| (options != null && options.isEligibleForLegacyPermissionPrompt())
- || (currPkg.equals(taskInfo.baseActivity.getPackageName())
- && isLauncherIntent(taskInfo.baseIntent));
+ || isTaskStartedFromLauncher(currPkg, taskInfo)
+ || (isTaskPotentialTrampoline(topActivityName, currPkg, callingPkg, taskInfo,
+ intent)
+ && (!startedActivity || pkgHasRunningLauncherTask(currPkg, taskInfo)));
+ }
+
+ private boolean isTaskPotentialTrampoline(String activityName, String currPkg,
+ String callingPkg, TaskInfo taskInfo, Intent intent) {
+ return currPkg.equals(callingPkg) && taskInfo.baseIntent.filterEquals(intent)
+ && taskInfo.numActivities == 1
+ && activityName.equals(taskInfo.topActivityInfo.name);
+ }
+
+ private boolean pkgHasRunningLauncherTask(String currPkg, TaskInfo taskInfo) {
+ ActivityTaskManagerInternal m =
+ LocalServices.getService(ActivityTaskManagerInternal.class);
+ try {
+ // TODO(b/230616478) Investigate alternatives like ActivityMetricsLaunchObserver
+ List<ActivityManager.AppTask> tasks =
+ m.getAppTasks(currPkg, mPackageManager.getPackageUid(currPkg, 0));
+ for (int i = 0; i < tasks.size(); i++) {
+ TaskInfo other = tasks.get(i).getTaskInfo();
+ if (other.taskId != taskInfo.taskId && other.isFocused && other.isRunning
+ && isTaskStartedFromLauncher(currPkg, other)) {
+ return true;
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // Fall through
+ }
+ return false;
}
private boolean isLauncherIntent(Intent intent) {
@@ -1193,6 +1332,11 @@ public final class PermissionPolicyService extends SystemService {
|| intent.getCategories().contains(Intent.CATEGORY_CAR_LAUNCHER));
}
+ private boolean isTaskStartedFromLauncher(String currPkg, TaskInfo taskInfo) {
+ return currPkg.equals(taskInfo.baseActivity.getPackageName())
+ && isLauncherIntent(taskInfo.baseIntent);
+ }
+
private void clearNotificationReviewFlagsIfNeeded(String packageName, UserHandle user) {
if ((mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, packageName, user)
& FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
index ae23b9e46d23..5db4a7b4a6f6 100644
--- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
@@ -268,9 +268,17 @@ final class SpeechRecognitionManagerServiceImpl extends
}
private boolean componentMapsToRecognitionService(@NonNull ComponentName serviceComponent) {
- List<ResolveInfo> resolveInfos =
- getContext().getPackageManager().queryIntentServicesAsUser(
- new Intent(RecognitionService.SERVICE_INTERFACE), 0, getUserId());
+ List<ResolveInfo> resolveInfos;
+
+ final long identityToken = Binder.clearCallingIdentity();
+ try {
+ resolveInfos =
+ getContext().getPackageManager().queryIntentServicesAsUser(
+ new Intent(RecognitionService.SERVICE_INTERFACE), 0, getUserId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (resolveInfos == null) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
index 400460a1e656..34483957ca12 100644
--- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
+++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
@@ -61,6 +61,7 @@ public abstract class ActivityInterceptorCallback {
PERMISSION_POLICY_ORDERED_ID,
INTENT_RESOLVER_ORDERED_ID,
VIRTUAL_DEVICE_SERVICE_ORDERED_ID,
+ DREAM_MANAGER_ORDERED_ID,
LAST_ORDERED_ID // Update this when adding new ids
})
@Retention(RetentionPolicy.SOURCE)
@@ -88,10 +89,15 @@ public abstract class ActivityInterceptorCallback {
public static final int VIRTUAL_DEVICE_SERVICE_ORDERED_ID = 3;
/**
+ * The identifier for {@link com.android.server.dreams.DreamManagerService} interceptor.
+ */
+ public static final int DREAM_MANAGER_ORDERED_ID = 4;
+
+ /**
* The final id, used by the framework to determine the valid range of ids. Update this when
* adding new ids.
*/
- static final int LAST_ORDERED_ID = VIRTUAL_DEVICE_SERVICE_ORDERED_ID;
+ static final int LAST_ORDERED_ID = DREAM_MANAGER_ORDERED_ID;
/**
* Data class for storing the various arguments needed for activity interception.
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
index c6b17e24b1de..81e5fbd564e0 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLaunchObserver.java
@@ -18,17 +18,19 @@ package com.android.server.wm;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Intent;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Observe activity manager launch sequences.
+ * Observe activity launch sequences.
*
- * The activity manager can have at most 1 concurrent launch sequences. Calls to this interface
- * are ordered by a happens-before relation for each defined state transition (see below).
+ * Multiple calls to the callback methods can occur without first terminating the current launch
+ * sequence because activity can be launched concurrently. So the implementation should associate
+ * the corresponding event according to the timestamp from {@link #onIntentStarted} which is also
+ * used as the identifier to indicate which launch sequence it belongs to.
*
* When a new launch sequence is made, that sequence is in the {@code INTENT_STARTED} state which
* is communicated by the {@link #onIntentStarted} callback. This is a transient state.
@@ -47,7 +49,7 @@ import java.lang.annotation.RetentionPolicy;
* Note this transition may not happen if the reportFullyDrawn event is not receivied,
* in which case {@code FINISHED} is terminal.
*
- * Note that the {@code ActivityRecordProto} provided as a parameter to some state transitions isn't
+ * Note that the {@code ComponentName} provided as a parameter to some state transitions isn't
* necessarily the same within a single launch sequence: it is only the top-most activity at the
* time (if any). Trampoline activities coalesce several activity starts into a single launch
* sequence.
@@ -67,7 +69,7 @@ import java.lang.annotation.RetentionPolicy;
* ╚════════════════╝ ╚═══════════════════════════╝ ╚═══════════════════════════╝
* </pre>
*/
-public interface ActivityMetricsLaunchObserver {
+public class ActivityMetricsLaunchObserver {
/**
* The 'temperature' at which a launch sequence had started.
*
@@ -99,40 +101,31 @@ public interface ActivityMetricsLaunchObserver {
public static final int TEMPERATURE_HOT = 3;
/**
- * Typedef marker that a {@code byte[]} actually contains an
- * <a href="proto/android/server/activitymanagerservice.proto">ActivityRecordProto</a>
- * in the protobuf format.
- */
- @Retention(RetentionPolicy.SOURCE)
- @interface ActivityRecordProto {}
-
- /**
* Notifies the observer that a new launch sequence has begun as a result of a new intent.
*
* Once a launch sequence begins, the resolved activity will either subsequently start with
* {@link #onActivityLaunched} or abort early (for example due to a resolution error or due to
* a security error) with {@link #onIntentFailed}.
*
- * Multiple calls to this method cannot occur without first terminating the current
- * launch sequence.
+ * @param timestampNanos The timestamp when receiving the intent. It is also use as an
+ * identifier for other callback methods to known which launch sequence
+ * it is associated with.
*/
- public void onIntentStarted(@NonNull Intent intent, long timestampNanos);
+ public void onIntentStarted(@NonNull Intent intent, long timestampNanos) {
+ }
/**
* Notifies the observer that the current launch sequence has failed to launch an activity.
*
- * This function call terminates the current launch sequence. The next method call, if any,
- * must be {@link #onIntentStarted}.
+ * This function call terminates the current launch sequence.
*
* Examples of this happening:
* - Failure to resolve to an activity
* - Calling package did not have the security permissions to call the requested activity
* - Resolved activity was already running and only needed to be brought to the top
- *
- * Multiple calls to this method cannot occur without first terminating the current
- * launch sequence.
*/
- public void onIntentFailed();
+ public void onIntentFailed(long id) {
+ }
/**
* Notifies the observer that the current launch sequence had begun starting an activity.
@@ -145,62 +138,58 @@ public interface ActivityMetricsLaunchObserver {
* necessarily the activity which will be considered as displayed when the activity
* finishes launching (e.g. {@code activity} in {@link #onActivityLaunchFinished}).
*
- * Multiple calls to this method cannot occur without first terminating the current
- * launch sequence.
+ * @param id The timestamp as an identifier from {@link #onIntentStarted}. It may be a new id
+ * if the launching activity is started from an existing launch sequence (trampoline)
+ * but cannot coalesce to the existing one, e.g. to a different display.
+ * @param name The launching activity name.
*/
- public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
- @Temperature int temperature);
+ public void onActivityLaunched(long id, ComponentName name, @Temperature int temperature) {
+ }
/**
* Notifies the observer that the current launch sequence has been aborted.
*
- * This function call terminates the current launch sequence. The next method call, if any,
- * must be {@link #onIntentStarted}.
+ * This function call terminates the current launch sequence.
*
* This can happen for many reasons, for example the user switches away to another app
* prior to the launch sequence completing, or the application being killed.
*
- * Multiple calls to this method cannot occur without first terminating the current
- * launch sequence.
- *
- * @param abortingActivity the last activity that had the top-most window during abort
- * (this can be {@code null} in rare situations its unknown).
+ * @param id The timestamp as an identifier from {@link #onIntentStarted}.
*
* @apiNote The aborting activity isn't necessarily the same as the starting activity;
* in the case of a trampoline, multiple activities could've been started
* and only the latest activity is reported here.
*/
- public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] abortingActivity);
+ public void onActivityLaunchCancelled(long id) {
+ }
/**
* Notifies the observer that the current launch sequence has been successfully finished.
*
- * This function call terminates the current launch sequence. The next method call, if any,
- * must be {@link #onIntentStarted}.
+ * This function call terminates the current launch sequence.
*
* A launch sequence is considered to be successfully finished when a frame is fully
* drawn for the first time: the top-most activity at the time is what's reported here.
*
- * @param finalActivity the top-most activity whose windows were first to fully draw
+ * @param id The timestamp as an identifier from {@link #onIntentStarted}.
+ * @param name The name of drawn activity. It can be different from {@link #onActivityLaunched}
+ * if the transition contains multiple launching activities (e.g. trampoline).
* @param timestampNanos the timestamp of ActivityLaunchFinished event in nanoseconds.
* To compute the TotalTime duration, deduct the timestamp {@link #onIntentStarted}
* from {@code timestampNanos}.
*
- * Multiple calls to this method cannot occur without first terminating the current
- * launch sequence.
- *
* @apiNote The finishing activity isn't necessarily the same as the starting activity;
* in the case of a trampoline, multiple activities could've been started
* and only the latest activity that was top-most during first-frame drawn
* is reported here.
*/
- public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] finalActivity,
- long timestampNanos);
+ public void onActivityLaunchFinished(long id, ComponentName name, long timestampNanos) {
+ }
/**
* Notifies the observer that the application self-reported itself as being fully drawn.
*
- * @param activity the activity that triggers the ReportFullyDrawn event.
+ * @param id The timestamp as an identifier from {@link #onIntentStarted}.
* @param timestampNanos the timestamp of ReportFullyDrawn event in nanoseconds.
* To compute the duration, deduct the deduct the timestamp {@link #onIntentStarted}
* from {@code timestampNanos}.
@@ -209,7 +198,7 @@ public interface ActivityMetricsLaunchObserver {
* It is used as an accurate estimate of meanfully app startup time.
* This event may be missing for many apps.
*/
- public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
- long timestampNanos);
+ public void onReportFullyDrawn(long id, long timestampNanos) {
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 7f84f61a91ff..1ea08f5cfea2 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -97,7 +97,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
-import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -176,7 +175,6 @@ class ActivityMetricsLogger {
* in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
*/
private final LaunchObserverRegistryImpl mLaunchObserver;
- @VisibleForTesting static final int LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE = 512;
private final ArrayMap<String, Boolean> mLastHibernationStates = new ArrayMap<>();
private AppHibernationManagerInternal mAppHibernationManagerInternal;
@@ -675,7 +673,7 @@ class ActivityMetricsLogger {
launchObserverNotifyActivityLaunched(newInfo);
} else {
// As abort for no process switch.
- launchObserverNotifyIntentFailed();
+ launchObserverNotifyIntentFailed(newInfo.mTransitionStartTimeNs);
}
scheduleCheckActivityToBeDrawnIfSleeping(launchedActivity);
@@ -910,7 +908,7 @@ class ActivityMetricsLogger {
}
if (DEBUG_METRICS) Slog.i(TAG, "abort launch cause=" + cause);
state.stopTrace(true /* abort */);
- launchObserverNotifyIntentFailed();
+ launchObserverNotifyIntentFailed(state.mCurrentTransitionStartTimeNs);
}
/** Aborts tracking of current launch metrics. */
@@ -1187,7 +1185,7 @@ class ActivityMetricsLogger {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Notify reportFullyDrawn event.
- launchObserverNotifyReportFullyDrawn(r, currentTimestampNs);
+ launchObserverNotifyReportFullyDrawn(info, currentTimestampNs);
return infoSnapshot;
}
@@ -1531,11 +1529,11 @@ class ActivityMetricsLogger {
* aborted due to intent failure (e.g. intent resolve failed or security error, etc) or
* intent being delivered to the top running activity.
*/
- private void launchObserverNotifyIntentFailed() {
+ private void launchObserverNotifyIntentFailed(long id) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"MetricsLogger:launchObserverNotifyIntentFailed");
- mLaunchObserver.onIntentFailed();
+ mLaunchObserver.onIntentFailed(id);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -1552,8 +1550,8 @@ class ActivityMetricsLogger {
convertTransitionTypeToLaunchObserverTemperature(info.mTransitionType);
// Beginning a launch is timing sensitive and so should be observed as soon as possible.
- mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.mLastLaunchedActivity),
- temperature);
+ mLaunchObserver.onActivityLaunched(info.mTransitionStartTimeNs,
+ info.mLastLaunchedActivity.mActivityComponent, temperature);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -1561,10 +1559,10 @@ class ActivityMetricsLogger {
/**
* Notifies the {@link ActivityMetricsLaunchObserver} the reportFullDrawn event.
*/
- private void launchObserverNotifyReportFullyDrawn(ActivityRecord r, long timestampNs) {
+ private void launchObserverNotifyReportFullyDrawn(TransitionInfo info, long timestampNs) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"MetricsLogger:launchObserverNotifyReportFullyDrawn");
- mLaunchObserver.onReportFullyDrawn(convertActivityRecordToProto(r), timestampNs);
+ mLaunchObserver.onReportFullyDrawn(info.mTransitionStartTimeNs, timestampNs);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -1576,10 +1574,7 @@ class ActivityMetricsLogger {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"MetricsLogger:launchObserverNotifyActivityLaunchCancelled");
- final @ActivityMetricsLaunchObserver.ActivityRecordProto byte[] activityRecordProto =
- info != null ? convertActivityRecordToProto(info.mLastLaunchedActivity) : null;
-
- mLaunchObserver.onActivityLaunchCancelled(activityRecordProto);
+ mLaunchObserver.onActivityLaunchCancelled(info.mTransitionStartTimeNs);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -1592,31 +1587,10 @@ class ActivityMetricsLogger {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"MetricsLogger:launchObserverNotifyActivityLaunchFinished");
- mLaunchObserver.onActivityLaunchFinished(
- convertActivityRecordToProto(info.mLastLaunchedActivity), timestampNs);
-
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- }
-
- @VisibleForTesting
- static @ActivityMetricsLaunchObserver.ActivityRecordProto byte[]
- convertActivityRecordToProto(ActivityRecord record) {
- // May take non-negligible amount of time to convert ActivityRecord into a proto,
- // so track the time.
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
- "MetricsLogger:convertActivityRecordToProto");
-
- // There does not appear to be a way to 'reset' a ProtoOutputBuffer stream,
- // so create a new one every time.
- final ProtoOutputStream protoOutputStream =
- new ProtoOutputStream(LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
- // Write this data out as the top-most ActivityRecordProto (i.e. it is not a sub-object).
- record.dumpDebug(protoOutputStream, WindowTraceLogLevel.ALL);
- final byte[] bytes = protoOutputStream.getBytes();
+ mLaunchObserver.onActivityLaunchFinished(info.mTransitionStartTimeNs,
+ info.mLastLaunchedActivity.mActivityComponent, timestampNs);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
- return bytes;
}
private static @ActivityMetricsLaunchObserver.Temperature int
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b6a1784839de..d00d8b8c9f8a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -661,10 +661,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/**
* The activity is opaque and fills the entire space of this task.
- * @see WindowContainer#fillsParent()
+ * @see #occludesParent()
*/
private boolean mOccludesParent;
+ /**
+ * Unlike {@link #mOccludesParent} which can be changed at runtime. This is a static attribute
+ * from the style of activity. Because we don't want {@link WindowContainer#getOrientation()}
+ * to be affected by the temporal state of {@link ActivityClientController#convertToTranslucent}
+ * when running ANIM_SCENE_TRANSITION.
+ * @see WindowContainer#fillsParent()
+ */
+ private final boolean mFillsParent;
+
// The input dispatching timeout for this application token in milliseconds.
long mInputDispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
@@ -1956,8 +1965,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// This style is propagated to the main window attributes with
// FLAG_SHOW_WALLPAPER from PhoneWindow#generateLayout.
|| ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
+ mFillsParent = mOccludesParent;
noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false);
} else {
+ mFillsParent = mOccludesParent = true;
noDisplay = false;
}
@@ -2436,6 +2447,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated, boolean activityAllDrawn,
TaskSnapshot snapshot) {
+ // A special case that a new activity is launching to an existing task which is moving to
+ // front. If the launching activity is the one that started the task, it could be a
+ // trampoline that will be always created and finished immediately. Then give a chance to
+ // see if the snapshot is usable for the current running activity so the transition will
+ // look smoother, instead of showing a splash screen on the second launch.
+ if (!newTask && taskSwitch && processRunning && !activityCreated && task.intent != null
+ && mActivityComponent.equals(task.intent.getComponent())) {
+ final ActivityRecord topAttached = task.getActivity(ActivityRecord::attachedToProcess);
+ if (topAttached != null && topAttached.isSnapshotCompatible(snapshot)) {
+ return STARTING_WINDOW_TYPE_SNAPSHOT;
+ }
+ }
final boolean isActivityHome = isActivityTypeHome();
if ((newTask || !processRunning || (taskSwitch && !activityCreated))
&& !isActivityHome) {
@@ -2852,7 +2875,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
boolean fillsParent() {
- return occludesParent(true /* includingFinishing */);
+ return mFillsParent;
}
/** Returns true if this activity is not finishing, is opaque and fills the entire space of
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index d254aaff1a1c..41b724f2596f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -64,6 +64,7 @@ import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS;
import static android.provider.Settings.System.FONT_SCALE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT;
import static android.view.WindowManager.TRANSIT_WAKE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
@@ -3398,6 +3399,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ // Keyguard asked us to clear the home task snapshot before going away, so do that.
+ if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT) != 0) {
+ mActivityClientController.invalidateHomeTaskSnapshot(null /* token */);
+ }
+
mRootWindowContainer.forAllDisplays(displayContent -> {
mKeyguardController.keyguardGoingAway(displayContent.getDisplayId(), flags);
});
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 6e46fa6b67d0..e80c2607a0ad 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -27,6 +27,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
+import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -48,8 +49,9 @@ class AppTaskImpl extends IAppTask.Stub {
mCallingUid = callingUid;
}
- private void checkCaller() {
- if (mCallingUid != Binder.getCallingUid()) {
+ private void checkCallerOrSystemOrRoot() {
+ if (mCallingUid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()
+ && Process.ROOT_UID != Binder.getCallingUid()) {
throw new SecurityException("Caller " + mCallingUid
+ " does not match caller of getAppTasks(): " + Binder.getCallingUid());
}
@@ -67,7 +69,7 @@ class AppTaskImpl extends IAppTask.Stub {
@Override
public void finishAndRemoveTask() {
- checkCaller();
+ checkCallerOrSystemOrRoot();
synchronized (mService.mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
@@ -85,7 +87,7 @@ class AppTaskImpl extends IAppTask.Stub {
@Override
public ActivityManager.RecentTaskInfo getTaskInfo() {
- checkCaller();
+ checkCallerOrSystemOrRoot();
synchronized (mService.mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
@@ -105,7 +107,7 @@ class AppTaskImpl extends IAppTask.Stub {
@Override
public void moveToFront(IApplicationThread appThread, String callingPackage) {
- checkCaller();
+ checkCallerOrSystemOrRoot();
// Will bring task to front if it already has a root activity.
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
@@ -136,7 +138,7 @@ class AppTaskImpl extends IAppTask.Stub {
@Override
public int startActivity(IBinder whoThread, String callingPackage, String callingFeatureId,
Intent intent, String resolvedType, Bundle bOptions) {
- checkCaller();
+ checkCallerOrSystemOrRoot();
mService.assertPackageMatchesCallingUid(callingPackage);
int callingUser = UserHandle.getCallingUserId();
@@ -167,7 +169,7 @@ class AppTaskImpl extends IAppTask.Stub {
@Override
public void setExcludeFromRecents(boolean exclude) {
- checkCaller();
+ checkCallerOrSystemOrRoot();
synchronized (mService.mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 68a09a6d4b9b..5410dd8508f1 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -22,6 +22,7 @@ import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
@@ -683,6 +684,9 @@ public class AppTransition implements Dump {
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
a = mTransitionAnimation.loadAppTransitionAnimation(mNextAppTransitionPackage,
enter ? mNextAppTransitionEnter : mNextAppTransitionExit);
+ if (mNextAppTransitionBackgroundColor != 0) {
+ a.setBackdropColor(mNextAppTransitionBackgroundColor);
+ }
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s "
+ "isEntrance=%b Callers=%s",
@@ -842,10 +846,6 @@ public class AppTransition implements Dump {
}
setAppTransitionFinishedCallbackIfNeeded(a);
- if (mNextAppTransitionBackgroundColor != 0) {
- a.setBackdropColor(mNextAppTransitionBackgroundColor);
- }
-
return a;
}
@@ -1259,6 +1259,9 @@ public class AppTransition implements Dump {
"TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER"));
sFlagToString.add(new Pair<>(TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION,
"TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION"));
+ sFlagToString.add(new Pair<>(
+ TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT,
+ "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_WITH_IN_WINDOW_ANIMATIONS"));
sFlagToString.add(new Pair<>(TRANSIT_FLAG_APP_CRASHED,
"TRANSIT_FLAG_APP_CRASHED"));
sFlagToString.add(new Pair<>(TRANSIT_FLAG_OPEN_BEHIND,
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 3bda2e60334a..701fc9441acb 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -912,6 +912,15 @@ public class AppTransitionController {
canPromote = false;
}
+ // If the current window container is task and it have adjacent task, it means
+ // both tasks will open or close app toghther but we want get their opening or
+ // closing animation target independently so do not promote.
+ if (current.asTask() != null
+ && current.asTask().getAdjacentTaskFragment() != null
+ && current.asTask().getAdjacentTaskFragment().asTask() != null) {
+ canPromote = false;
+ }
+
// Find all siblings of the current WindowContainer in "candidates", move them into
// a separate list "siblings", and checks if an animation target can be promoted
// to its parent.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index dc441860f7c8..ed1bbf8e4b74 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -60,6 +60,7 @@ import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
+import static android.view.WindowManager.LayoutParams;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
@@ -4291,18 +4292,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Update Ime parent when IME insets leash created or the new IME layering target might
// updated from setImeLayeringTarget, which is the best time that default IME visibility
// has been settled down after IME control target changed.
- final boolean imeParentChanged =
- prevImeControlTarget != mImeControlTarget || forceUpdateImeParent;
- if (imeParentChanged) {
+ final boolean imeControlChanged = prevImeControlTarget != mImeControlTarget;
+ if (imeControlChanged || forceUpdateImeParent) {
updateImeParent();
}
final WindowState win = InsetsControlTarget.asWindowOrNull(mImeControlTarget);
final IBinder token = win != null ? win.mClient.asBinder() : null;
// Note: not allowed to call into IMMS with the WM lock held, hence the post.
- mWmService.mH.post(() ->
- InputMethodManagerInternal.get().reportImeControl(token, imeParentChanged)
- );
+ mWmService.mH.post(() -> InputMethodManagerInternal.get().reportImeControl(token));
}
void updateImeParent() {
@@ -4324,6 +4322,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// do a force update to make sure there is a layer set for the new parent.
assignRelativeLayerForIme(getSyncTransaction(), true /* forceUpdate */);
scheduleAnimation();
+
+ mWmService.mH.post(() -> InputMethodManagerInternal.get().onImeParentChanged());
}
}
@@ -4347,10 +4347,24 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
@VisibleForTesting
SurfaceControl computeImeParent() {
- if (mImeLayeringTarget != null && mImeInputTarget != null
- && mImeLayeringTarget.mActivityRecord != mImeInputTarget.getActivityRecord()) {
- // Do not change parent if the window hasn't requested IME.
- return null;
+ if (mImeLayeringTarget != null) {
+ // Ensure changing the IME parent when the layering target that may use IME has
+ // became to the input target for preventing IME flickers.
+ // Note that:
+ // 1) For the imeLayeringTarget that may not use IME but requires IME on top
+ // of it (e.g. an overlay window with NOT_FOCUSABLE|ALT_FOCUSABLE_IM flags), we allow
+ // it to re-parent the IME on top the display to keep the legacy behavior.
+ // 2) Even though the starting window won't use IME, the associated activity
+ // behind the starting window may request the input. If so, then we should still hold
+ // the IME parent change until the activity started the input.
+ boolean imeLayeringTargetMayUseIme =
+ LayoutParams.mayUseInputMethod(mImeLayeringTarget.mAttrs.flags)
+ || mImeLayeringTarget.mAttrs.type == TYPE_APPLICATION_STARTING;
+ if (imeLayeringTargetMayUseIme && mImeInputTarget != null
+ && mImeLayeringTarget.mActivityRecord != mImeInputTarget.getActivityRecord()) {
+ // Do not change parent if the window hasn't requested IME.
+ return null;
+ }
}
// Attach it to app if the target is part of an app and such app is covering the entire
// screen. If it's not covering the entire screen the IME might extend beyond the apps
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 76aa7f963aa6..fd0631320520 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -83,7 +83,7 @@ public class DisplayFrames {
final Rect safe = mDisplayCutoutSafe;
final DisplayCutout cutout = displayCutout.getDisplayCutout();
if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight
- && mRotation != info.rotation
+ && mRotation == info.rotation
&& state.getDisplayCutout().equals(cutout)
&& state.getRoundedCorners().equals(roundedCorners)
&& state.getPrivacyIndicatorBounds().equals(indicatorBounds)) {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2d7d7055a03b..62998cb6bc40 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -138,8 +138,8 @@ import android.window.ClientWindowFrames;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.ForceShowNavBarSettingsObserver;
import com.android.internal.policy.GestureNavigationSettingsObserver;
-import com.android.internal.policy.KidsModeSettingsObserver;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.SystemBarUtils;
import com.android.internal.protolog.common.ProtoLog;
@@ -300,10 +300,6 @@ public class DisplayPolicy {
// needs to be opaque.
private WindowState mNavBarBackgroundWindow;
- // The window that draws fake rounded corners and should provide insets to calculate the correct
- // rounded corner insets.
- private WindowState mRoundedCornerWindow;
-
/**
* A collection of {@link AppearanceRegion} to indicate that which region of status bar applies
* which appearance.
@@ -378,7 +374,7 @@ public class DisplayPolicy {
private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
- private final KidsModeSettingsObserver mKidsModeSettingsObserver;
+ private final ForceShowNavBarSettingsObserver mForceShowNavBarSettingsObserver;
private boolean mForceShowNavigationBarEnabled;
private class PolicyHandler extends Handler {
@@ -653,17 +649,17 @@ public class DisplayPolicy {
});
mHandler.post(mGestureNavigationSettingsObserver::register);
- mKidsModeSettingsObserver = new KidsModeSettingsObserver(
+ mForceShowNavBarSettingsObserver = new ForceShowNavBarSettingsObserver(
mHandler, mContext);
- mKidsModeSettingsObserver.setOnChangeRunnable(() -> {
+ mForceShowNavBarSettingsObserver.setOnChangeRunnable(() -> {
synchronized (mLock) {
mForceShowNavigationBarEnabled =
- mKidsModeSettingsObserver.isEnabled();
+ mForceShowNavBarSettingsObserver.isEnabled();
updateSystemBarAttributes();
}
});
- mForceShowNavigationBarEnabled = mKidsModeSettingsObserver.isEnabled();
- mHandler.post(mKidsModeSettingsObserver::register);
+ mForceShowNavigationBarEnabled = mForceShowNavBarSettingsObserver.isEnabled();
+ mHandler.post(mForceShowNavBarSettingsObserver::register);
}
/**
@@ -970,16 +966,10 @@ public class DisplayPolicy {
mExtraNavBarAltPosition = getAltBarPosition(attrs);
}
- if (attrs.insetsRoundedCornerFrame) {
- // Currently, only support one rounded corner window which is the TaskBar.
- if (mRoundedCornerWindow != null && mRoundedCornerWindow != win) {
- throw new IllegalArgumentException("Found multiple rounded corner window :"
- + " current = " + mRoundedCornerWindow
- + " new = " + win);
- }
- mRoundedCornerWindow = win;
- } else if (mRoundedCornerWindow == win) {
- mRoundedCornerWindow = null;
+ final InsetsSourceProvider provider = win.getControllableInsetProvider();
+ if (provider != null && provider.getSource().getInsetsRoundedCornerFrame()
+ != attrs.insetsRoundedCornerFrame) {
+ provider.getSource().setInsetsRoundedCornerFrame(attrs.insetsRoundedCornerFrame);
}
}
@@ -1326,9 +1316,6 @@ public class DisplayPolicy {
if (mLastFocusedWindow == win) {
mLastFocusedWindow = null;
}
- if (mRoundedCornerWindow == win) {
- mRoundedCornerWindow = null;
- }
mInsetsSourceWindowsExceptIme.remove(win);
}
@@ -1360,10 +1347,6 @@ public class DisplayPolicy {
return mNavigationBar != null ? mNavigationBar : mNavigationBarAlt;
}
- WindowState getRoundedCornerWindow() {
- return mRoundedCornerWindow;
- }
-
/**
* Control the animation to run when a window's state changes. Return a positive number to
* force the animation to a specific resource ID, {@link #ANIMATION_STYLEABLE} to use the
@@ -2861,7 +2844,7 @@ public class DisplayPolicy {
void release() {
mDisplayContent.mTransitionController.unregisterLegacyListener(mAppTransitionListener);
mHandler.post(mGestureNavigationSettingsObserver::unregister);
- mHandler.post(mKidsModeSettingsObserver::unregister);
+ mHandler.post(mForceShowNavBarSettingsObserver::unregister);
mImmersiveModeConfirmation.release();
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 5aacb094207e..f833773cd5c6 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -702,17 +702,17 @@ public class DisplayRotation {
}
boolean canRotateSeamlessly(int oldRotation, int newRotation) {
+ // If the navigation bar can't change sides, then it will jump when we change orientations
+ // and we don't rotate seamlessly - unless that is allowed, eg. with gesture navigation
+ // where the navbar is low-profile enough that this isn't very noticeable.
+ if (mAllowSeamlessRotationDespiteNavBarMoving || mDisplayPolicy.navigationBarCanMove()) {
+ return true;
+ }
// For the upside down rotation we don't rotate seamlessly as the navigation bar moves
// position. Note most apps (using orientation:sensor or user as opposed to fullSensor)
// will not enter the reverse portrait orientation, so actually the orientation won't change
// at all.
- if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) {
- return false;
- }
- // If the navigation bar can't change sides, then it will jump when we change orientations
- // and we don't rotate seamlessly - unless that is allowed, eg. with gesture navigation
- // where the navbar is low-profile enough that this isn't very noticeable.
- return mAllowSeamlessRotationDespiteNavBarMoving || mDisplayPolicy.navigationBarCanMove();
+ return oldRotation != Surface.ROTATION_180 && newRotation != Surface.ROTATION_180;
}
void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) {
@@ -1224,16 +1224,8 @@ public class DisplayRotation {
|| orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
// Otherwise, use sensor only if requested by the application or enabled
// by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR.
- if (mAllowAllRotations == ALLOW_ALL_ROTATIONS_UNDEFINED) {
- // Can't read this during init() because the context doesn't have display metrics at
- // that time so we cannot determine tablet vs. phone then.
- mAllowAllRotations = mContext.getResources().getBoolean(
- R.bool.config_allowAllRotations)
- ? ALLOW_ALL_ROTATIONS_ENABLED
- : ALLOW_ALL_ROTATIONS_DISABLED;
- }
if (sensorRotation != Surface.ROTATION_180
- || mAllowAllRotations == ALLOW_ALL_ROTATIONS_ENABLED
+ || getAllowAllRotations() == ALLOW_ALL_ROTATIONS_ENABLED
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
|| orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
preferredRotation = sensorRotation;
@@ -1322,6 +1314,19 @@ public class DisplayRotation {
}
}
+ private int getAllowAllRotations() {
+ if (mAllowAllRotations == ALLOW_ALL_ROTATIONS_UNDEFINED) {
+ // Can't read this during init() because the context doesn't have display metrics at
+ // that time so we cannot determine tablet vs. phone then.
+ mAllowAllRotations = mContext.getResources().getBoolean(
+ R.bool.config_allowAllRotations)
+ ? ALLOW_ALL_ROTATIONS_ENABLED
+ : ALLOW_ALL_ROTATIONS_DISABLED;
+ }
+
+ return mAllowAllRotations;
+ }
+
private boolean isLandscapeOrSeascape(int rotation) {
return rotation == mLandscapeRotation || rotation == mSeascapeRotation;
}
@@ -1349,6 +1354,11 @@ public class DisplayRotation {
case ActivityInfo.SCREEN_ORIENTATION_USER:
case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
+ // When all rotations enabled it works with any of the 4 rotations
+ if (getAllowAllRotations() == ALLOW_ALL_ROTATIONS_ENABLED) {
+ return preferredRotation >= 0;
+ }
+
// Works with any rotation except upside down.
return (preferredRotation >= 0) && (preferredRotation != Surface.ROTATION_180);
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 6162f12b516e..5c8cfffdd3b3 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -46,7 +46,6 @@ import android.annotation.Nullable;
import android.app.ActivityTaskManager;
import android.app.StatusBarManager;
import android.app.WindowConfiguration;
-import android.graphics.Insets;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.IntArray;
@@ -461,22 +460,10 @@ class InsetsPolicy {
private InsetsState adjustInsetsForRoundedCorners(WindowState w, InsetsState originalState,
boolean copyState) {
- final WindowState roundedCornerWindow = mPolicy.getRoundedCornerWindow();
final Task task = w.getTask();
- if (task != null && !task.getWindowConfiguration().tasksAreFloating()
- && (roundedCornerWindow != null || task.inSplitScreen())) {
- // Instead of using display frame to calculating rounded corner, for the fake rounded
- // corners drawn by divider bar or task bar, we need to re-calculate rounded corners
- // based on task bounds and if the task bounds is intersected with task bar, we should
- // exclude the intersected part.
+ if (task != null && !task.getWindowConfiguration().tasksAreFloating()) {
+ // Use task bounds to calculating rounded corners if the task is not floating.
final Rect roundedCornerFrame = new Rect(task.getBounds());
- if (roundedCornerWindow != null
- && roundedCornerWindow.getControllableInsetProvider() != null) {
- final InsetsSource source =
- roundedCornerWindow.getControllableInsetProvider().getSource();
- final Insets insets = source.calculateInsets(roundedCornerFrame, false);
- roundedCornerFrame.inset(insets);
- }
final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
state.setRoundedCornerFrame(roundedCornerFrame);
return state;
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 8413c5442536..9853d1304b14 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -170,6 +170,7 @@ abstract class InsetsSourceProvider {
if (windowContainer == null) {
setServerVisible(false);
mSource.setVisibleFrame(null);
+ mSource.setInsetsRoundedCornerFrame(false);
mSourceFrame.setEmpty();
} else {
mWindowContainer.getProvidedInsetsSources().put(mSource.getType(), mSource);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 2ebb59751634..f36dbfa2316e 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -23,6 +23,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
@@ -32,6 +33,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS;
+import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -309,6 +311,10 @@ class KeyguardController {
if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_SUBTLE_WINDOW_ANIMATIONS) != 0) {
result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
}
+ if ((keyguardGoingAwayFlags
+ & KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT) != 0) {
+ result |= TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT;
+ }
return result;
}
diff --git a/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java b/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java
index 362ed3c380c5..9cbc1bdcbeeb 100644
--- a/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java
+++ b/services/core/java/com/android/server/wm/LaunchObserverRegistryImpl.java
@@ -16,12 +16,11 @@
package com.android.server.wm;
+import android.content.ComponentName;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
-import android.os.Message;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.util.function.pooled.PooledLambda;
import java.util.ArrayList;
@@ -39,8 +38,8 @@ import java.util.ArrayList;
*
* @see ActivityTaskManagerInternal#getLaunchObserverRegistry()
*/
-class LaunchObserverRegistryImpl implements
- ActivityMetricsLaunchObserverRegistry, ActivityMetricsLaunchObserver {
+class LaunchObserverRegistryImpl extends ActivityMetricsLaunchObserver implements
+ ActivityMetricsLaunchObserverRegistry {
private final ArrayList<ActivityMetricsLaunchObserver> mList = new ArrayList<>();
/**
@@ -79,45 +78,36 @@ class LaunchObserverRegistryImpl implements
}
@Override
- public void onIntentFailed() {
+ public void onIntentFailed(long id) {
mHandler.sendMessage(PooledLambda.obtainMessage(
- LaunchObserverRegistryImpl::handleOnIntentFailed, this));
+ LaunchObserverRegistryImpl::handleOnIntentFailed, this, id));
}
@Override
- public void onActivityLaunched(
- @ActivityRecordProto byte[] activity,
- int temperature) {
+ public void onActivityLaunched(long id, ComponentName name, int temperature) {
mHandler.sendMessage(PooledLambda.obtainMessage(
LaunchObserverRegistryImpl::handleOnActivityLaunched,
- this, activity, temperature));
+ this, id, name, temperature));
}
@Override
- public void onActivityLaunchCancelled(
- @ActivityRecordProto byte[] activity) {
+ public void onActivityLaunchCancelled(long id) {
mHandler.sendMessage(PooledLambda.obtainMessage(
- LaunchObserverRegistryImpl::handleOnActivityLaunchCancelled, this, activity));
+ LaunchObserverRegistryImpl::handleOnActivityLaunchCancelled, this, id));
}
@Override
- public void onActivityLaunchFinished(
- @ActivityRecordProto byte[] activity,
- long timestampNs) {
+ public void onActivityLaunchFinished(long id, ComponentName name, long timestampNs) {
mHandler.sendMessage(PooledLambda.obtainMessage(
- LaunchObserverRegistryImpl::handleOnActivityLaunchFinished,
- this,
- activity,
- timestampNs));
+ LaunchObserverRegistryImpl::handleOnActivityLaunchFinished,
+ this, id, name, timestampNs));
}
@Override
- public void onReportFullyDrawn(@ActivityRecordProto byte[] activity, long timestampNs) {
+ public void onReportFullyDrawn(long id, long timestampNs) {
mHandler.sendMessage(PooledLambda.obtainMessage(
- LaunchObserverRegistryImpl::handleOnReportFullyDrawn,
- this,
- activity,
- timestampNs));
+ LaunchObserverRegistryImpl::handleOnReportFullyDrawn,
+ this, id, timestampNs));
}
// Use PooledLambda.obtainMessage to invoke below methods. Every method reference must be
@@ -135,53 +125,43 @@ class LaunchObserverRegistryImpl implements
private void handleOnIntentStarted(Intent intent, long timestampNs) {
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
for (int i = 0; i < mList.size(); i++) {
- ActivityMetricsLaunchObserver o = mList.get(i);
- o.onIntentStarted(intent, timestampNs);
+ mList.get(i).onIntentStarted(intent, timestampNs);
}
}
- private void handleOnIntentFailed() {
+ private void handleOnIntentFailed(long id) {
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
for (int i = 0; i < mList.size(); i++) {
- ActivityMetricsLaunchObserver o = mList.get(i);
- o.onIntentFailed();
+ mList.get(i).onIntentFailed(id);
}
}
- private void handleOnActivityLaunched(
- @ActivityRecordProto byte[] activity,
+ private void handleOnActivityLaunched(long id, ComponentName name,
@Temperature int temperature) {
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
for (int i = 0; i < mList.size(); i++) {
- ActivityMetricsLaunchObserver o = mList.get(i);
- o.onActivityLaunched(activity, temperature);
+ mList.get(i).onActivityLaunched(id, name, temperature);
}
}
- private void handleOnActivityLaunchCancelled(
- @ActivityRecordProto byte[] activity) {
+ private void handleOnActivityLaunchCancelled(long id) {
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
for (int i = 0; i < mList.size(); i++) {
- ActivityMetricsLaunchObserver o = mList.get(i);
- o.onActivityLaunchCancelled(activity);
+ mList.get(i).onActivityLaunchCancelled(id);
}
}
- private void handleOnActivityLaunchFinished(
- @ActivityRecordProto byte[] activity, long timestampNs) {
+ private void handleOnActivityLaunchFinished(long id, ComponentName name, long timestampNs) {
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
for (int i = 0; i < mList.size(); i++) {
- ActivityMetricsLaunchObserver o = mList.get(i);
- o.onActivityLaunchFinished(activity, timestampNs);
+ mList.get(i).onActivityLaunchFinished(id, name, timestampNs);
}
}
- private void handleOnReportFullyDrawn(
- @ActivityRecordProto byte[] activity, long timestampNs) {
+ private void handleOnReportFullyDrawn(long id, long timestampNs) {
// Traverse start-to-end to meet the registerLaunchObserver multi-cast order guarantee.
for (int i = 0; i < mList.size(); i++) {
- ActivityMetricsLaunchObserver o = mList.get(i);
- o.onReportFullyDrawn(activity, timestampNs);
+ mList.get(i).onReportFullyDrawn(id, timestampNs);
}
}
}
diff --git a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java b/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
index 11a27c593d9e..3f6fb622481f 100644
--- a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
+++ b/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
@@ -16,15 +16,11 @@
package com.android.server.wm;
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_270;
-
import android.hardware.display.DisplayManagerInternal;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.view.DisplayInfo;
-import android.view.Surface;
import java.util.Set;
@@ -44,8 +40,7 @@ public class PossibleDisplayInfoMapper {
/**
* Map of all logical displays, indexed by logical display id.
- * Each logical display has multiple entries, one for each possible rotation and device
- * state.
+ * Each logical display has multiple entries, one for each device state.
*
* Emptied and re-calculated when a display is added, removed, or changed.
*/
@@ -57,8 +52,8 @@ public class PossibleDisplayInfoMapper {
/**
- * Returns, for the given displayId, a set of display infos. Set contains the possible rotations
- * for each supported device state.
+ * Returns, for the given displayId, a set of display infos. Set contains each supported device
+ * state.
*/
public Set<DisplayInfo> getPossibleDisplayInfos(int displayId) {
// Update display infos before returning, since any cached values would have been removed
@@ -73,13 +68,13 @@ public class PossibleDisplayInfoMapper {
}
/**
- * Updates the possible {@link DisplayInfo}s for the given display, by calculating the
- * DisplayInfo for each rotation across supported device states.
+ * Updates the possible {@link DisplayInfo}s for the given display, by saving the DisplayInfo
+ * across supported device states.
*/
public void updatePossibleDisplayInfos(int displayId) {
Set<DisplayInfo> displayInfos = mDisplayManagerInternal.getPossibleDisplayInfo(displayId);
if (DEBUG) {
- Slog.v(TAG, "updatePossibleDisplayInfos, calculate rotations for given DisplayInfo "
+ Slog.v(TAG, "updatePossibleDisplayInfos, given DisplayInfo "
+ displayInfos.size() + " on display " + displayId);
}
updateDisplayInfos(displayInfos);
@@ -99,40 +94,12 @@ public class PossibleDisplayInfoMapper {
private void updateDisplayInfos(Set<DisplayInfo> displayInfos) {
// Empty out cache before re-computing.
mDisplayInfos.clear();
- DisplayInfo[] originalDisplayInfos = new DisplayInfo[displayInfos.size()];
- displayInfos.toArray(originalDisplayInfos);
// Iterate over each logical display layout for the current state.
- Set<DisplayInfo> rotatedDisplayInfos;
- for (DisplayInfo di : originalDisplayInfos) {
- rotatedDisplayInfos = new ArraySet<>();
- // Calculate all possible rotations for each logical display.
- for (int rotation = ROTATION_0; rotation <= ROTATION_270; rotation++) {
- rotatedDisplayInfos.add(applyRotation(di, rotation));
- }
+ for (DisplayInfo di : displayInfos) {
// Combine all results under the logical display id.
Set<DisplayInfo> priorDisplayInfos = mDisplayInfos.get(di.displayId, new ArraySet<>());
- priorDisplayInfos.addAll(rotatedDisplayInfos);
+ priorDisplayInfos.add(di);
mDisplayInfos.put(di.displayId, priorDisplayInfos);
}
}
-
- private static DisplayInfo applyRotation(DisplayInfo displayInfo,
- @Surface.Rotation int rotation) {
- DisplayInfo updatedDisplayInfo = new DisplayInfo();
- updatedDisplayInfo.copyFrom(displayInfo);
- // Apply rotations before updating width and height
- updatedDisplayInfo.roundedCorners = updatedDisplayInfo.roundedCorners.rotate(rotation,
- updatedDisplayInfo.logicalWidth, updatedDisplayInfo.logicalHeight);
- updatedDisplayInfo.displayCutout =
- DisplayContent.calculateDisplayCutoutForRotationAndDisplaySizeUncached(
- updatedDisplayInfo.displayCutout, rotation, updatedDisplayInfo.logicalWidth,
- updatedDisplayInfo.logicalHeight).getDisplayCutout();
-
- updatedDisplayInfo.rotation = rotation;
- final int naturalWidth = updatedDisplayInfo.getNaturalWidth();
- final int naturalHeight = updatedDisplayInfo.getNaturalHeight();
- updatedDisplayInfo.logicalWidth = naturalWidth;
- updatedDisplayInfo.logicalHeight = naturalHeight;
- return updatedDisplayInfo;
- }
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ca4c450a4592..c0dff14e5de5 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3382,7 +3382,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
if (record != null && record.isUid(uid)
&& Objects.equals(pkgName, record.packageName)
&& pPi.shouldShowNotificationDialogForTask(record.getTask().getTaskInfo(),
- pkgName, record.intent)) {
+ pkgName, record.launchedFromPackage, record.intent, record.getName())) {
validTaskId[0] = record.getTask().mTaskId;
return true;
}
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 65ae3fcb4c90..b4029d185b9f 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -219,7 +219,7 @@ class ScreenRotationAnimation {
// If hdr layers are on-screen, e.g. picture-in-picture mode, the screenshot of
// rotation animation is an sdr image containing tone-mapping hdr content, then
// disable dimming effect to get avoid of hdr content being dimmed during animation.
- t.setDimmingEnabled(mScreenshotLayer, false);
+ t.setDimmingEnabled(mScreenshotLayer, !screenshotBuffer.containsHdrLayers());
t.setLayer(mBackColorSurface, -1);
t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
t.setAlpha(mBackColorSurface, 1);
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index 813e06fecf48..ccd018faf075 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -26,6 +26,7 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN;
+import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SNAPSHOT;
import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -114,7 +115,7 @@ public class StartingSurfaceController {
if (allowTaskSnapshot) {
parameter |= TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
}
- if (activityCreated) {
+ if (activityCreated || startingWindowType == STARTING_WINDOW_TYPE_SNAPSHOT) {
parameter |= TYPE_PARAMETER_ACTIVITY_CREATED;
}
if (isSolidColor) {
@@ -138,7 +139,6 @@ public class StartingSurfaceController {
final WindowState topFullscreenOpaqueWindow;
final Task task;
synchronized (mService.mGlobalLock) {
- final WindowState mainWindow = activity.findMainWindow();
task = activity.getTask();
if (task == null) {
Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity="
@@ -153,9 +153,9 @@ public class StartingSurfaceController {
return null;
}
topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow();
- if (mainWindow == null || topFullscreenOpaqueWindow == null) {
- Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity="
- + activity);
+ if (topFullscreenOpaqueWindow == null) {
+ Slog.w(TAG, "TaskSnapshotSurface.create: no opaque window in "
+ + topFullscreenActivity);
return null;
}
if (topFullscreenActivity.getWindowConfiguration().getRotation()
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f97f768872fd..00e61171cb68 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -56,6 +56,7 @@ import static android.view.SurfaceControl.METADATA_TASK_ID;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
@@ -1724,8 +1725,8 @@ class Task extends TaskFragment {
/** Returns {@code true} if this task is currently in split-screen. */
boolean inSplitScreen() {
return getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW
- && getRootTask() != null
- && getRootTask().getAdjacentTaskFragment() != null;
+ && getCreatedByOrganizerTask() != null
+ && getCreatedByOrganizerTask().getAdjacentTaskFragment() != null;
}
private boolean supportsSplitScreenWindowingModeInner(@Nullable TaskDisplayArea tda) {
@@ -3525,10 +3526,13 @@ class Task extends TaskFragment {
mAtmService.mKeyguardController.isDisplayOccluded(DEFAULT_DISPLAY);
info.startingWindowTypeParameter = activity.mStartingData.mTypeParams;
- final WindowState mainWindow = activity.findMainWindow();
- if (mainWindow != null) {
- info.mainWindowLayoutParams = mainWindow.getAttrs();
- info.requestedVisibilities.set(mainWindow.getRequestedVisibilities());
+ if ((info.startingWindowTypeParameter
+ & StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED) != 0) {
+ final WindowState topMainWin = getWindow(w -> w.mAttrs.type == TYPE_BASE_APPLICATION);
+ if (topMainWin != null) {
+ info.mainWindowLayoutParams = topMainWin.getAttrs();
+ info.requestedVisibilities.set(topMainWin.getRequestedVisibilities());
+ }
}
// If the developer has persist a different configuration, we need to override it to the
// starting window because persisted configuration does not effect to Task.
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 73a755dd3123..1176182ede50 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -963,7 +963,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
} else if (candidateTask != null) {
final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
final Task launchRootTask = getLaunchRootTask(resolvedWindowingMode, activityType,
- options, sourceTask, launchFlags);
+ options, sourceTask, launchFlags, candidateTask);
if (launchRootTask != null) {
if (candidateTask.getParent() == null) {
launchRootTask.addChild(candidateTask, position);
@@ -1117,6 +1117,13 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
@Nullable
Task getLaunchRootTask(int windowingMode, int activityType, @Nullable ActivityOptions options,
@Nullable Task sourceTask, int launchFlags) {
+ return getLaunchRootTask(windowingMode, activityType, options, sourceTask, launchFlags,
+ null /* candidateTask */);
+ }
+
+ @Nullable
+ Task getLaunchRootTask(int windowingMode, int activityType, @Nullable ActivityOptions options,
+ @Nullable Task sourceTask, int launchFlags, @Nullable Task candidateTask) {
// Try to use the launch root task in options if available.
if (options != null) {
final Task launchRootTask = Task.fromWindowContainerToken(options.getLaunchRootTask());
@@ -1157,9 +1164,19 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
}
// For a better split UX, If a task is launching from a created-by-organizer task, it should
- // be launched into the same created-by-organizer task as well.
- if (sourceTask != null) {
- return sourceTask.getCreatedByOrganizerTask();
+ // be launched into the same created-by-organizer task as well. Unless, the candidate task
+ // is already positioned in the split.
+ Task preferredRootInSplit = sourceTask != null && sourceTask.inSplitScreen()
+ ? sourceTask.getCreatedByOrganizerTask() : null;
+ if (preferredRootInSplit != null) {
+ if (candidateTask != null) {
+ final Task candidateRoot = candidateTask.getCreatedByOrganizerTask();
+ if (candidateRoot != null && candidateRoot != preferredRootInSplit
+ && preferredRootInSplit == candidateRoot.getAdjacentTaskFragment()) {
+ preferredRootInSplit = candidateRoot;
+ }
+ }
+ return preferredRootInSplit;
}
return null;
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 1beb32cfdd52..56e96fa1fe58 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -591,8 +591,9 @@ class TaskFragment extends WindowContainer<WindowContainer> {
* @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
*/
boolean isAllowedToBeEmbeddedInTrustedMode() {
- final Predicate<ActivityRecord> callback = this::isAllowedToEmbedActivityInTrustedMode;
- return forAllActivities(callback);
+ // Traverse all activities to see if any of them are not in the trusted mode.
+ final Predicate<ActivityRecord> callback = r -> !isAllowedToEmbedActivityInTrustedMode(r);
+ return !forAllActivities(callback);
}
/**
@@ -2155,7 +2156,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
return applicationType;
}
- return getTopChild().getActivityType();
+ final ActivityRecord activity = getTopNonFinishingActivity();
+ return activity != null ? activity.getActivityType() : getTopChild().getActivityType();
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index eff75bc0622b..48168a08a543 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -423,7 +423,7 @@ public class WindowManagerService extends IWindowManager.Stub
"persist.wm.enable_remote_keyguard_animation";
private static final int sEnableRemoteKeyguardAnimation =
- SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1);
+ SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2);
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
@@ -8755,8 +8755,7 @@ public class WindowManagerService extends IWindowManager.Stub
return new ArrayList<>();
}
- // Retrieve the DisplayInfo for all possible rotations across all possible display
- // layouts.
+ // Retrieve the DisplayInfo across all possible display layouts.
return List.copyOf(mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId));
}
} finally {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index efed92ded095..137a3ac81b9b 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -30,6 +30,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
@@ -775,6 +776,29 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
break;
}
+ case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT: {
+ final TaskFragment tf = mLaunchTaskFragments.get(hop.getContainer());
+ if (tf == null || !tf.isAttached()) {
+ Slog.e(TAG, "Attempt to operate on detached container: " + tf);
+ break;
+ }
+ final ActivityRecord curFocus = tf.getDisplayContent().mFocusedApp;
+ if (curFocus != null && curFocus.getTaskFragment() == tf) {
+ Slog.d(TAG, "The requested TaskFragment already has the focus.");
+ break;
+ }
+ if (curFocus != null && curFocus.getTask() != tf.getTask()) {
+ Slog.d(TAG, "The Task of the requested TaskFragment doesn't have focus.");
+ break;
+ }
+ final ActivityRecord targetFocus = tf.getTopResumedActivity();
+ if (targetFocus == null) {
+ Slog.d(TAG, "There is no resumed activity in the requested TaskFragment.");
+ break;
+ }
+ tf.getDisplayContent().setFocusedApp(targetFocus);
+ break;
+ }
default: {
// The other operations may change task order so they are skipped while in lock
// task mode. The above operations are still allowed because they don't move
@@ -1318,6 +1342,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
+ case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT:
// We are allowing organizer to start/reparent activity to a TaskFragment it
// created, or set two TaskFragments adjacent to each other. Nothing to check
// here because the TaskFragment may not be created yet, but will be created in
@@ -1413,7 +1438,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
final WindowConfiguration requestedWindowConfig = requestedConfig.windowConfiguration;
final WindowConfiguration parentWindowConfig = parentConfig.windowConfiguration;
- if (!parentWindowConfig.getBounds().contains(requestedWindowConfig.getBounds())) {
+ if (!requestedWindowConfig.getBounds().isEmpty()
+ && !parentWindowConfig.getBounds().contains(requestedWindowConfig.getBounds())) {
String msg = "Permission Denial: " + func + " from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ " trying to apply bounds outside of parent for non-trusted host,"
@@ -1422,6 +1448,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
throw new SecurityException(msg);
}
if (requestedWindowConfig.getAppBounds() != null
+ && !requestedWindowConfig.getAppBounds().isEmpty()
&& parentWindowConfig.getAppBounds() != null
&& !parentWindowConfig.getAppBounds().contains(
requestedWindowConfig.getAppBounds())) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c6288a7da26a..cd19f64ba12e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2464,7 +2464,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
dc.setImeLayeringTarget(null);
dc.computeImeTarget(true /* updateImeTarget */);
}
- if (dc.getImeInputTarget() == this) {
+ if (dc.getImeInputTarget() == this
+ && (mActivityRecord == null || !mActivityRecord.isRelaunching())) {
dc.updateImeInputAndControlTarget(null);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 9a0b5c7ef5ae..48a436f15803 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -69,6 +69,7 @@ class DevicePolicyData {
private static final String TAG_PASSWORD_VALIDITY = "password-validity";
private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token";
private static final String TAG_PROTECTED_PACKAGES = "protected-packages";
+ private static final String TAG_BYPASS_ROLE_QUALIFICATIONS = "bypass-role-qualifications";
private static final String ATTR_VALUE = "value";
private static final String ATTR_ALIAS = "alias";
private static final String ATTR_ID = "id";
@@ -107,6 +108,8 @@ class DevicePolicyData {
int mPasswordOwner = -1;
long mLastMaximumTimeToLock = -1;
boolean mUserSetupComplete = false;
+ boolean mBypassDevicePolicyManagementRoleQualifications = false;
+ String mCurrentRoleHolder;
boolean mPaired = false;
int mUserProvisioningState;
int mPermissionPolicy;
@@ -374,6 +377,12 @@ class DevicePolicyData {
out.endTag(null, TAG_APPS_SUSPENDED);
}
+ if (policyData.mBypassDevicePolicyManagementRoleQualifications) {
+ out.startTag(null, TAG_BYPASS_ROLE_QUALIFICATIONS);
+ out.attribute(null, ATTR_VALUE, policyData.mCurrentRoleHolder);
+ out.endTag(null, TAG_BYPASS_ROLE_QUALIFICATIONS);
+ }
+
out.endTag(null, "policies");
out.endDocument();
@@ -558,6 +567,9 @@ class DevicePolicyData {
} else if (TAG_APPS_SUSPENDED.equals(tag)) {
policy.mAppsSuspended =
parser.getAttributeBoolean(null, ATTR_VALUE, false);
+ } else if (TAG_BYPASS_ROLE_QUALIFICATIONS.equals(tag)) {
+ policy.mBypassDevicePolicyManagementRoleQualifications = true;
+ policy.mCurrentRoleHolder = parser.getAttributeValue(null, ATTR_VALUE);
} else {
Slogf.w(TAG, "Unknown tag: %s", tag);
XmlUtils.skipCurrentTag(parser);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e2d8a63fbfda..0a426eb80c54 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -138,7 +138,6 @@ import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.provider.Settings.Global.BYPASS_DEVICE_POLICY_MANAGEMENT_ROLE_QUALIFICATIONS;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static android.provider.Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
@@ -222,6 +221,7 @@ import android.app.admin.UnsafeStateException;
import android.app.admin.WifiSsidPolicy;
import android.app.backup.IBackupManager;
import android.app.compat.CompatChanges;
+import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
import android.app.trust.TrustManager;
import android.app.usage.UsageStatsManagerInternal;
@@ -255,6 +255,7 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.Signature;
import android.content.pm.StringParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Resources;
@@ -409,6 +410,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -756,6 +758,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private @UserIdInt int mNetworkLoggingNotificationUserId = UserHandle.USER_NULL;
private final DeviceManagementResourcesProvider mDeviceManagementResourcesProvider;
+ private final DevicePolicyManagementRoleObserver mDevicePolicyManagementRoleObserver;
private static final boolean ENABLE_LOCK_GUARD = true;
@@ -1823,6 +1826,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mBugreportCollectionManager = new RemoteBugreportManager(this, mInjector);
mDeviceManagementResourcesProvider = mInjector.getDeviceManagementResourcesProvider();
+ mDevicePolicyManagementRoleObserver = new DevicePolicyManagementRoleObserver(mContext);
+ mDevicePolicyManagementRoleObserver.register();
// "Lite" interface is available even when the device doesn't have the feature
LocalServices.addService(DevicePolicyManagerLiteInternal.class, mLocalService);
@@ -13052,9 +13057,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (callerPackage == null) {
return false;
}
+
+ CallerIdentity caller = new CallerIdentity(callerUid, null, null);
if (isUserAffiliatedWithDevice(UserHandle.getUserId(callerUid))
&& (isActiveProfileOwner(callerUid)
- || isActiveDeviceOwner(callerUid))) {
+ || isDefaultDeviceOwner(caller) || isFinancedDeviceOwner(caller))) {
// device owner or a profile owner affiliated with the device owner
return true;
}
@@ -18663,16 +18670,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
android.Manifest.permission.MANAGE_ROLE_HOLDERS));
return mInjector.binderWithCleanCallingIdentity(() -> {
- if (mInjector.settingsGlobalGetInt(
- BYPASS_DEVICE_POLICY_MANAGEMENT_ROLE_QUALIFICATIONS, /* def= */ 0) == 1) {
- return true;
- }
- if (shouldAllowBypassingDevicePolicyManagementRoleQualificationInternal()) {
- mInjector.settingsGlobalPutInt(
- BYPASS_DEVICE_POLICY_MANAGEMENT_ROLE_QUALIFICATIONS, /* value= */ 1);
+ if (getUserData(
+ UserHandle.USER_SYSTEM).mBypassDevicePolicyManagementRoleQualifications) {
return true;
}
- return false;
+ return shouldAllowBypassingDevicePolicyManagementRoleQualificationInternal();
});
}
@@ -18685,6 +18687,142 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return accounts.length == 0;
}
+ private void setBypassDevicePolicyManagementRoleQualificationStateInternal(
+ String currentRoleHolder, boolean allowBypass) {
+ boolean stateChanged = false;
+ DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
+ if (policy.mBypassDevicePolicyManagementRoleQualifications != allowBypass) {
+ policy.mBypassDevicePolicyManagementRoleQualifications = allowBypass;
+ stateChanged = true;
+ }
+ if (!Objects.equals(currentRoleHolder, policy.mCurrentRoleHolder)) {
+ policy.mCurrentRoleHolder = currentRoleHolder;
+ stateChanged = true;
+ }
+ if (stateChanged) {
+ synchronized (getLockObject()) {
+ saveSettingsLocked(UserHandle.USER_SYSTEM);
+ }
+ }
+ }
+
+ private final class DevicePolicyManagementRoleObserver implements OnRoleHoldersChangedListener {
+ private RoleManager mRm;
+ private final Executor mExecutor;
+ private final Context mContext;
+
+ DevicePolicyManagementRoleObserver(@NonNull Context context) {
+ mContext = context;
+ mExecutor = mContext.getMainExecutor();
+ mRm = mContext.getSystemService(RoleManager.class);
+ }
+
+ public void register() {
+ mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.SYSTEM);
+ }
+
+ @Override
+ public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
+ if (!RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT.equals(roleName)) {
+ return;
+ }
+ String newRoleHolder = getRoleHolder();
+ if (isDefaultRoleHolder(newRoleHolder)) {
+ Slogf.i(LOG_TAG,
+ "onRoleHoldersChanged: Default role holder is set, returning early");
+ return;
+ }
+ if (newRoleHolder == null) {
+ Slogf.i(LOG_TAG,
+ "onRoleHoldersChanged: New role holder is null, returning early");
+ return;
+ }
+ if (shouldAllowBypassingDevicePolicyManagementRoleQualificationInternal()) {
+ Slogf.w(LOG_TAG,
+ "onRoleHoldersChanged: Updating current role holder to " + newRoleHolder);
+ setBypassDevicePolicyManagementRoleQualificationStateInternal(
+ newRoleHolder, /* allowBypass= */ true);
+ return;
+ }
+ DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
+ if (!newRoleHolder.equals(policy.mCurrentRoleHolder)) {
+ Slogf.w(LOG_TAG,
+ "onRoleHoldersChanged: You can't set a different role holder, role "
+ + "is getting revoked from " + newRoleHolder);
+ setBypassDevicePolicyManagementRoleQualificationStateInternal(
+ /* currentRoleHolder= */ null, /* allowBypass= */ false);
+ mRm.removeRoleHolderAsUser(
+ RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT,
+ newRoleHolder,
+ /* flags= */ 0,
+ user,
+ mExecutor,
+ successful -> {});
+ }
+ }
+
+ private String getRoleHolder() {
+ return DevicePolicyManagerService.this.getDevicePolicyManagementRoleHolderPackageName(
+ mContext);
+ }
+
+ private boolean isDefaultRoleHolder(String packageName) {
+ String defaultRoleHolder = getDefaultRoleHolderPackageName();
+ if (packageName == null || defaultRoleHolder == null) {
+ return false;
+ }
+ if (!defaultRoleHolder.equals(packageName)) {
+ return false;
+ }
+ return hasSigningCertificate(
+ packageName, getDefaultRoleHolderPackageSignature());
+ }
+
+ private boolean hasSigningCertificate(String packageName, String certificateString) {
+ if (packageName == null || certificateString == null) {
+ return false;
+ }
+ byte[] certificate;
+ try {
+ certificate = new Signature(certificateString).toByteArray();
+ } catch (IllegalArgumentException e) {
+ Slogf.w(LOG_TAG, "Cannot parse signing certificate: " + certificateString, e);
+ return false;
+ }
+ PackageManager pm = mInjector.getPackageManager();
+ return pm.hasSigningCertificate(
+ packageName, certificate, PackageManager.CERT_INPUT_SHA256);
+ }
+
+ private String getDefaultRoleHolderPackageName() {
+ String[] info = getDefaultRoleHolderPackageNameAndSignature();
+ if (info == null) {
+ return null;
+ }
+ return info[0];
+ }
+
+ private String getDefaultRoleHolderPackageSignature() {
+ String[] info = getDefaultRoleHolderPackageNameAndSignature();
+ if (info == null || info.length < 2) {
+ return null;
+ }
+ return info[1];
+ }
+
+ private String[] getDefaultRoleHolderPackageNameAndSignature() {
+ String packageNameAndSignature = mContext.getString(
+ com.android.internal.R.string.config_devicePolicyManagement);
+ if (TextUtils.isEmpty(packageNameAndSignature)) {
+ return null;
+ }
+ if (packageNameAndSignature.contains(":")) {
+ return packageNameAndSignature.split(":");
+ }
+ return new String[]{packageNameAndSignature};
+ }
+ }
+
@Override
public List<UserHandle> getPolicyManagedProfiles(@NonNull UserHandle user) {
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index bbc28d78d6f2..d3222901db1e 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -274,36 +274,11 @@ public final class ProfcollectForwardingService extends SystemService {
}
}
- private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
+ private class AppLaunchObserver extends ActivityMetricsLaunchObserver {
@Override
public void onIntentStarted(Intent intent, long timestampNanos) {
traceOnAppStart(intent.getPackage());
}
-
- @Override
- public void onIntentFailed() {
- // Ignored
- }
-
- @Override
- public void onActivityLaunched(byte[] activity, int temperature) {
- // Ignored
- }
-
- @Override
- public void onActivityLaunchCancelled(byte[] abortingActivity) {
- // Ignored
- }
-
- @Override
- public void onActivityLaunchFinished(byte[] finalActivity, long timestampNanos) {
- // Ignored
- }
-
- @Override
- public void onReportFullyDrawn(byte[] activity, long timestampNanos) {
- // Ignored
- }
}
private void registerOTAObserver() {
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 670c1596e15e..08c68b9a469e 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -42,6 +42,8 @@ android_test {
static_libs: [
"androidx.test.core",
"androidx.test.runner",
+ "androidx.test.espresso.core",
+ "androidx.test.espresso.contrib",
"androidx.test.ext.truth",
"frameworks-base-testutils",
"hamcrest-library",
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 7714cf0ca094..07b763dcd85b 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -32,6 +32,8 @@
<uses-permission
android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
+ <uses-permission android:name="android.permission.MANAGE_GAME_ACTIVITY" />
+ <uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
<!-- needed by MasterClearReceiverTest to display a system dialog -->
<uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
@@ -39,6 +41,8 @@
<application android:testOnly="true"
android:debuggable="true">
<uses-library android:name="android.test.runner" />
+ <activity
+ android:name="android.service.games.GameSessionTrampolineActivityTest$TestActivity" />
</application>
<instrumentation
diff --git a/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java b/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
new file mode 100644
index 000000000000..d68b517ca8cd
--- /dev/null
+++ b/services/tests/mockingservicestests/src/android/service/games/GameSessionTrampolineActivityTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.ext.truth.content.IntentSubject.assertThat;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.hamcrest.Matchers.allOf;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.testing.AndroidTestingRunner;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.test.espresso.NoActivityResumedException;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.infra.AndroidFuture;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Unit tests for the {@link GameSessionTrampolineActivity}.
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+@Presubmit
+public class GameSessionTrampolineActivityTest {
+
+ @Before
+ public void setUp() {
+ setAlwaysFinishActivities(false);
+ }
+
+ @After
+ public void tearDown() {
+ setAlwaysFinishActivities(false);
+ }
+
+ @Test
+ public void launch_launchesTargetActivity() {
+ AndroidFuture<GameSessionActivityResult> unusedResultFuture =
+ startTestActivityViaGameSessionTrampolineActivity();
+
+ TestActivityPage.assertPageIsLaunched();
+ }
+
+ @Test
+ public void launch_targetActivityFinishesSuccessfully_futureCompletedWithSameResults() {
+ AndroidFuture<GameSessionActivityResult> resultFuture =
+ startTestActivityViaGameSessionTrampolineActivity();
+
+ TestActivityPage.assertPageIsLaunched();
+ TestActivityPage.clickFinish();
+
+ GameSessionActivityResult expectedResult =
+ new GameSessionActivityResult(Activity.RESULT_OK, TestActivity.RESULT_INTENT);
+
+ assertEquals(resultFuture, expectedResult);
+
+ TestActivityPage.assertPageIsNotLaunched();
+ }
+
+ @Test
+ public void launch_trampolineActivityProcessDeath_futureCompletedWithSameResults() {
+ setAlwaysFinishActivities(true);
+
+ AndroidFuture<GameSessionActivityResult> resultFuture =
+ startTestActivityViaGameSessionTrampolineActivity();
+
+ TestActivityPage.assertPageIsLaunched();
+ TestActivityPage.clickFinish();
+
+ GameSessionActivityResult expectedResult =
+ new GameSessionActivityResult(Activity.RESULT_OK, TestActivity.RESULT_INTENT);
+
+ assertEquals(resultFuture, expectedResult);
+
+ TestActivityPage.assertPageIsNotLaunched();
+ }
+
+ private static void assertEquals(
+ AndroidFuture<GameSessionActivityResult> actualFuture,
+ GameSessionActivityResult expected) {
+ try {
+ assertEquals(actualFuture.get(20, TimeUnit.SECONDS), expected);
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ private static void assertEquals(
+ GameSessionActivityResult actual,
+ GameSessionActivityResult expected) {
+ assertThat(actual.getResultCode()).isEqualTo(expected.getResultCode());
+ assertThat(actual.getData()).filtersEquallyTo(actual.getData());
+ }
+
+ private static void setAlwaysFinishActivities(boolean isEnabled) {
+ try {
+ ActivityManager.getService().setAlwaysFinish(isEnabled);
+ } catch (RemoteException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ private static AndroidFuture<GameSessionActivityResult>
+ startTestActivityViaGameSessionTrampolineActivity() {
+ Intent testActivityIntent = new Intent();
+ testActivityIntent.setClass(getInstrumentation().getTargetContext(), TestActivity.class);
+
+ return startGameSessionTrampolineActivity(testActivityIntent);
+ }
+
+ private static AndroidFuture<GameSessionActivityResult> startGameSessionTrampolineActivity(
+ Intent targetIntent) {
+ AndroidFuture<GameSessionActivityResult> resultFuture = new AndroidFuture<>();
+ Intent trampolineActivityIntent = GameSessionTrampolineActivity.createIntent(targetIntent,
+ null, resultFuture);
+ trampolineActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ getInstrumentation().getTargetContext().startActivity(trampolineActivityIntent);
+ getInstrumentation().waitForIdleSync();
+
+ return resultFuture;
+ }
+
+
+ private static class TestActivityPage {
+ private TestActivityPage() {}
+
+ public static void assertPageIsLaunched() {
+ onView(withText(TestActivity.PAGE_TITLE_TEXT)).check(matches(isDisplayed()));
+ }
+
+ public static void assertPageIsNotLaunched() {
+ try {
+ onView(withText(TestActivity.PAGE_TITLE_TEXT)).check(doesNotExist());
+ } catch (NoActivityResumedException ex) {
+ // Do nothing
+ }
+ }
+
+ public static void clickFinish() {
+ onView(allOf(withText(TestActivity.FINISH_BUTTON_TEXT), isClickable())).perform(
+ click());
+ getInstrumentation().waitForIdleSync();
+ }
+ }
+
+ public static class TestActivity extends Activity {
+ private static final String PAGE_TITLE_TEXT = "GameSessionTestActivity";
+ private static final String FINISH_BUTTON_TEXT = "Finish Test Activity";
+ private static final Intent RESULT_INTENT = new Intent("com.test.action.VIEW");
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout contentLayout = new LinearLayout(this);
+ contentLayout.setOrientation(LinearLayout.VERTICAL);
+
+ TextView titleTextView = new TextView(this);
+ titleTextView.setText(PAGE_TITLE_TEXT);
+ contentLayout.addView(titleTextView);
+
+ Button finishActivityButton = new Button(this);
+ finishActivityButton.setText(FINISH_BUTTON_TEXT);
+ finishActivityButton.setOnClickListener((unused) -> {
+ setResult(Activity.RESULT_OK, RESULT_INTENT);
+ finish();
+ });
+
+
+ contentLayout.addView(finishActivityButton);
+ setContentView(contentLayout);
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 529def3697cd..8461b39f8899 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -2758,7 +2758,7 @@ public class AlarmManagerServiceTest {
mService.handleChangesToExactAlarmDenyList(new ArraySet<>(packages), false);
// No permission revoked.
- verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(anyInt(), anyString(),
+ verify(mService, never()).removeExactAlarmsOnPermissionRevoked(anyInt(), anyString(),
anyBoolean());
// Permission got granted only for (appId1, userId2).
@@ -2813,14 +2813,14 @@ public class AlarmManagerServiceTest {
mService.handleChangesToExactAlarmDenyList(new ArraySet<>(packages), true);
// Permission got revoked only for (appId1, userId2)
- verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
+ verify(mService, never()).removeExactAlarmsOnPermissionRevoked(
eq(UserHandle.getUid(userId1, appId1)), eq(packages[0]), eq(true));
- verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
+ verify(mService, never()).removeExactAlarmsOnPermissionRevoked(
eq(UserHandle.getUid(userId1, appId2)), eq(packages[1]), eq(true));
- verify(mService, never()).removeExactAlarmsOnPermissionRevokedLocked(
+ verify(mService, never()).removeExactAlarmsOnPermissionRevoked(
eq(UserHandle.getUid(userId2, appId2)), eq(packages[1]), eq(true));
- verify(mService).removeExactAlarmsOnPermissionRevokedLocked(
+ verify(mService).removeExactAlarmsOnPermissionRevoked(
eq(UserHandle.getUid(userId2, appId1)), eq(packages[0]), eq(true));
}
@@ -2833,7 +2833,7 @@ public class AlarmManagerServiceTest {
mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
assertAndHandleMessageSync(REMOVE_EXACT_ALARMS);
- verify(mService).removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID,
+ verify(mService).removeExactAlarmsOnPermissionRevoked(TEST_CALLING_UID,
TEST_CALLING_PACKAGE, true);
}
@@ -2919,7 +2919,7 @@ public class AlarmManagerServiceTest {
null);
assertEquals(6, mService.mAlarmStore.size());
- mService.removeExactAlarmsOnPermissionRevokedLocked(TEST_CALLING_UID, TEST_CALLING_PACKAGE,
+ mService.removeExactAlarmsOnPermissionRevoked(TEST_CALLING_UID, TEST_CALLING_PACKAGE,
true);
final ArrayList<Alarm> remaining = mService.mAlarmStore.asList();
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index c747a5fd982b..2f68306e9ba1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -191,6 +191,8 @@ public class MockingOomAdjusterTests {
mock(ActivityManagerService.LocalService.class));
setFieldValue(ActivityManagerService.class, sService, "mBatteryStatsService",
mock(BatteryStatsService.class));
+ setFieldValue(ActivityManagerService.class, sService, "mInjector",
+ new ActivityManagerService.Injector(sContext));
doReturn(mock(AppOpsManager.class)).when(sService).getAppOpsManager();
doCallRealMethod().when(sService).enqueueOomAdjTargetLocked(any(ProcessRecord.class));
doCallRealMethod().when(sService).updateOomAdjPendingTargetsLocked(any(String.class));
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index 319a769bb1de..5b551b1c183c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -216,11 +216,12 @@ public final class GameServiceProviderInstanceImplTest {
mRunningTaskInfos);
+ final UserHandle userHandle = new UserHandle(USER_ID);
mGameServiceProviderInstance = new GameServiceProviderInstanceImpl(
- new UserHandle(USER_ID),
+ userHandle,
ConcurrentUtils.DIRECT_EXECUTOR,
mMockContext,
- mFakeGameClassifier,
+ new GameTaskInfoProvider(userHandle, mMockActivityTaskManager, mFakeGameClassifier),
mMockActivityManager,
mMockActivityManagerInternal,
mMockActivityTaskManager,
@@ -788,6 +789,36 @@ public final class GameServiceProviderInstanceImplTest {
}
@Test
+ public void gameTaskFocusedWithCreateAfterRemoved_gameSessionRecreated() throws Exception {
+ mGameServiceProviderInstance.start();
+
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+
+ stopTask(10);
+
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+
+ // If the game task is restored via the Recents UI, the task will be running again but
+ // we would not expect any call to TaskStackListener#onTaskCreated.
+ addRunningTaskInfo(10, GAME_A_MAIN_ACTIVITY);
+
+ // We now receive a task focused event for the task. This will occur if the game task is
+ // restored via the Recents UI.
+ dispatchTaskFocused(10, /*focused=*/ true);
+ mFakeGameService.requestCreateGameSession(10);
+
+ // Verify that a new pending game session is created for the game's taskId.
+ assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10));
+ }
+
+ @Test
public void gameTaskRemoved_removesTaskOverlay() throws Exception {
mGameServiceProviderInstance.start();
@@ -1144,13 +1175,18 @@ public final class GameServiceProviderInstanceImplTest {
}
private void startTask(int taskId, ComponentName componentName) {
+ addRunningTaskInfo(taskId, componentName);
+
+ dispatchTaskCreated(taskId, componentName);
+ }
+
+ private void addRunningTaskInfo(int taskId, ComponentName componentName) {
RunningTaskInfo runningTaskInfo = new RunningTaskInfo();
runningTaskInfo.taskId = taskId;
+ runningTaskInfo.baseActivity = componentName;
runningTaskInfo.displayId = 1;
runningTaskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 0, 500, 800));
mRunningTaskInfos.add(runningTaskInfo);
-
- dispatchTaskCreated(taskId, componentName);
}
private void stopTask(int taskId) {
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index e3be3a792549..16df5deb2e5c 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -19,9 +19,6 @@ android_test {
"src/**/*.java",
"src/**/*.kt",
- "aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl",
- "aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl",
-
"test-apps/JobTestApp/src/**/*.java",
"test-apps/SuspendTestApp/src/**/*.java",
@@ -67,10 +64,6 @@ android_test {
"ActivityContext",
],
- aidl: {
- local_include_dirs: ["aidl"],
- },
-
libs: [
"android.hardware.power-V1-java",
"android.hardware.tv.cec-V1.0-java",
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 449177ef9b7d..0afb1829f9d4 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -102,6 +102,7 @@
<uses-permission android:name="android.permission.READ_NEARBY_STREAMING_POLICY" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
<uses-permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT" />
+ <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
<queries>
<package android:name="com.android.servicestests.apps.suspendtestapp" />
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index bb3eb81df6ed..158bd39a4fd0 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -28,7 +28,6 @@
<option name="install-arg" value="-t" />
<option name="test-file-name" value="FrameworksServicesTests.apk" />
<option name="test-file-name" value="JobTestApp.apk" />
- <option name="test-file-name" value="ConnTestApp.apk" />
<option name="test-file-name" value="SuspendTestApp.apk" />
<option name="test-file-name" value="SimpleServiceTestApp1.apk" />
<option name="test-file-name" value="SimpleServiceTestApp2.apk" />
diff --git a/services/tests/servicestests/aidl/Android.bp b/services/tests/servicestests/aidl/Android.bp
deleted file mode 100644
index 678053192e82..000000000000
--- a/services/tests/servicestests/aidl/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-java_library {
- name: "servicestests-aidl",
- sdk_version: "current",
- srcs: [
- "com/android/servicestests/aidl/INetworkStateObserver.aidl",
- "com/android/servicestests/aidl/ICmdReceiverService.aidl",
- ],
-}
diff --git a/services/tests/servicestests/aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl b/services/tests/servicestests/aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
deleted file mode 100644
index d96450478f90..000000000000
--- a/services/tests/servicestests/aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.servicestests.aidl;
-
-interface ICmdReceiverService {
- void finishActivity();
-} \ No newline at end of file
diff --git a/services/tests/servicestests/aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl b/services/tests/servicestests/aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl
deleted file mode 100644
index ca9fc4c439d2..000000000000
--- a/services/tests/servicestests/aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.servicestests.aidl;
-
-oneway interface INetworkStateObserver {
- /**
- * {@param resultData} will be in the format
- * NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo.
- * For detailed info, see
- * servicestests/test-apps/ConnTestApp/.../ConnTestActivity#checkNetworkStatus
- */
- void onNetworkStateChecked(String resultData);
-} \ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
index 0e84e044e44b..42c4129513d0 100644
--- a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
@@ -16,6 +16,10 @@
package com.android.server;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.app.job.JobScheduler;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -43,13 +47,15 @@ public class BinaryTransparencyServiceTest {
@Before
public void setUp() {
- mContext = ApplicationProvider.getApplicationContext();
+ mContext = spy(ApplicationProvider.getApplicationContext());
mBinaryTransparencyService = new BinaryTransparencyService(mContext);
mTestInterface = mBinaryTransparencyService.new BinaryTransparencyServiceImpl();
}
private void prepSignedInfo() {
// simulate what happens on boot completed phase
+ // but we avoid calling JobScheduler.schedule by returning a null.
+ doReturn(null).when(mContext).getSystemService(JobScheduler.class);
mBinaryTransparencyService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
}
diff --git a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
index 5c91b8b4717f..d1390c68e130 100644
--- a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
@@ -90,6 +90,16 @@ public class DropboxRateLimiterTest {
mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
assertEquals(2,
mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
+
+ // After 11 seconds the rate limiting buffer will be cleared and rate limiting will stop.
+ mClock.setOffsetMillis(11000);
+
+ // The first call after rate limiting stops will still return the number of dropped events.
+ assertEquals(2,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
+ // The next call should show that the dropped event counter was reset.
+ assertEquals(0,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
}
private static class TestClock implements DropboxRateLimiter.Clock {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 2cf67f83578b..e991ec6879ae 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -237,6 +237,8 @@ public class DpmMockContext extends MockContext {
return mMockSystemServices.devicePolicyManager;
case Context.LOCATION_SERVICE:
return mMockSystemServices.locationManager;
+ case Context.ROLE_SERVICE:
+ return mMockSystemServices.roleManager;
}
throw new UnsupportedOperationException();
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 34c9f7c2ef87..884ffce155d7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -33,6 +33,7 @@ import android.app.IActivityTaskManager;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.app.backup.IBackupManager;
+import android.app.role.RoleManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -131,6 +132,7 @@ public class MockSystemServices {
public final VpnManager vpnManager;
public final DevicePolicyManager devicePolicyManager;
public final LocationManager locationManager;
+ public final RoleManager roleManager;
/** Note this is a partial mock, not a real mock. */
public final PackageManager packageManager;
public final BuildMock buildMock = new BuildMock();
@@ -181,6 +183,7 @@ public class MockSystemServices {
vpnManager = mock(VpnManager.class);
devicePolicyManager = mock(DevicePolicyManager.class);
locationManager = mock(LocationManager.class);
+ roleManager = realContext.getSystemService(RoleManager.class);
// Package manager is huge, so we use a partial mock instead.
packageManager = spy(realContext.getPackageManager());
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 bf3c7c3e05fb..d5612e7a27b2 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -38,6 +39,7 @@ import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Rect;
import android.hardware.display.BrightnessConfiguration;
@@ -72,6 +74,7 @@ import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
@@ -93,6 +96,7 @@ import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.time.Duration;
@@ -203,6 +207,10 @@ public class DisplayManagerServiceTest {
@Test
public void testCreateVirtualDisplay_sentToInputManager() {
+ // This is to update the display device config such that DisplayManagerService can ignore
+ // the usage of SensorManager, which is available only after the PowerManagerService
+ // is ready.
+ resetConfigToIgnoreSensorManager(mContext);
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
@@ -275,6 +283,10 @@ public class DisplayManagerServiceTest {
@Test
public void testPhysicalViewports() {
+ // This is to update the display device config such that DisplayManagerService can ignore
+ // the usage of SensorManager, which is available only after the PowerManagerService
+ // is ready.
+ resetConfigToIgnoreSensorManager(mContext);
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
@@ -1343,6 +1355,20 @@ public class DisplayManagerServiceTest {
}
}
+ private void resetConfigToIgnoreSensorManager(Context context) {
+ final Resources res = Mockito.spy(context.getResources());
+ doReturn(new int[]{-1}).when(res).getIntArray(R.array
+ .config_ambientThresholdsOfPeakRefreshRate);
+ doReturn(new int[]{-1}).when(res).getIntArray(R.array
+ .config_brightnessThresholdsOfPeakRefreshRate);
+ doReturn(new int[]{-1}).when(res).getIntArray(R.array
+ .config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
+ doReturn(new int[]{-1}).when(res).getIntArray(R.array
+ .config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+
+ when(context.getResources()).thenReturn(res);
+ }
+
private class FakeDisplayManagerCallback extends IDisplayManagerCallback.Stub {
int mDisplayId;
boolean mDisplayAddedCalled = false;
diff --git a/services/tests/servicestests/src/com/android/server/display/TEST_MAPPING b/services/tests/servicestests/src/com/android/server/display/TEST_MAPPING
new file mode 100644
index 000000000000..9f1a209d2ee1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/TEST_MAPPING
@@ -0,0 +1,21 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.display."
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
deleted file mode 100644
index 25b41db1aea3..000000000000
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.os.BatteryManager;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.SystemClock;
-import android.support.test.uiautomator.UiDevice;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.servicestests.aidl.ICmdReceiverService;
-import com.android.servicestests.aidl.INetworkStateObserver;
-
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Tests for verifying network availability on activity start.
- *
- * To run the tests, use
- *
- * runtest -c com.android.server.net.ConnOnActivityStartTest frameworks-services
- *
- * or the following steps:
- *
- * Build: m FrameworksServicesTests
- * Install: adb install -r \
- * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
- * Run: adb shell am instrument -e class com.android.server.net.ConnOnActivityStartTest -w \
- * com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class ConnOnActivityStartTest {
- private static final String TAG = ConnOnActivityStartTest.class.getSimpleName();
-
- private static final String TEST_PKG = "com.android.servicestests.apps.conntestapp";
- private static final String TEST_ACTIVITY_CLASS = TEST_PKG + ".ConnTestActivity";
- private static final String TEST_SERVICE_CLASS = TEST_PKG + ".CmdReceiverService";
-
- private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
-
- private static final long BATTERY_OFF_TIMEOUT_MS = 2000; // 2 sec
- private static final long BATTERY_OFF_CHECK_INTERVAL_MS = 200; // 0.2 sec
-
- private static final long NETWORK_CHECK_TIMEOUT_MS = 4000; // 4 sec
-
- private static final long SCREEN_ON_DELAY_MS = 2000; // 2 sec
-
- private static final long BIND_SERVICE_TIMEOUT_SEC = 4;
-
- private static final int REPEAT_TEST_COUNT = 5;
-
- private static Context mContext;
- private static UiDevice mUiDevice;
- private static int mTestPkgUid;
- private static BatteryManager mBatteryManager;
-
- private static ServiceConnection mServiceConnection;
- private static ICmdReceiverService mCmdReceiverService;
-
- @BeforeClass
- public static void setUpOnce() throws Exception {
- mContext = InstrumentationRegistry.getContext();
- mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-
- mContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG,
- PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
- mTestPkgUid = mContext.getPackageManager().getPackageUid(TEST_PKG, 0);
-
- mBatteryManager = (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE);
- bindService();
- }
-
- @AfterClass
- public static void tearDownOnce() throws Exception {
- batteryReset();
- unbindService();
- }
-
- private static void bindService() throws Exception {
- final CountDownLatch bindLatch = new CountDownLatch(1);
- mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.i(TAG, "Service connected");
- mCmdReceiverService = ICmdReceiverService.Stub.asInterface(service);
- bindLatch.countDown();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.i(TAG, "Service disconnected");
- }
- };
- final Intent intent = new Intent()
- .setComponent(new ComponentName(TEST_PKG, TEST_SERVICE_CLASS));
- // Needs to use BIND_ALLOW_OOM_MANAGEMENT and BIND_NOT_FOREGROUND so that the test app
- // does not run in the same process state as this app.
- mContext.bindService(intent, mServiceConnection,
- Context.BIND_AUTO_CREATE
- | Context.BIND_ALLOW_OOM_MANAGEMENT
- | Context.BIND_NOT_FOREGROUND);
- if (!bindLatch.await(BIND_SERVICE_TIMEOUT_SEC, TimeUnit.SECONDS)) {
- fail("Timed out waiting for the service to bind in " + mTestPkgUid);
- }
- }
-
- private static void unbindService() {
- if (mCmdReceiverService != null) {
- mContext.unbindService(mServiceConnection);
- }
- }
-
- @Test
- public void testStartActivity_batterySaver() throws Exception {
- setBatterySaverMode(true);
- try {
- testConnOnActivityStart("testStartActivity_batterySaver");
- } finally {
- setBatterySaverMode(false);
- }
- }
-
- @Test
- public void testStartActivity_dataSaver() throws Exception {
- setDataSaverMode(true);
- try {
- testConnOnActivityStart("testStartActivity_dataSaver");
- } finally {
- setDataSaverMode(false);
- }
- }
-
- @Test
- public void testStartActivity_dozeMode() throws Exception {
- setDozeMode(true);
- try {
- testConnOnActivityStart("testStartActivity_dozeMode");
- } finally {
- setDozeMode(false);
- }
- }
-
- @Test
- public void testStartActivity_appStandby() throws Exception {
- try{
- turnBatteryOn();
- setAppIdle(true);
- turnScreenOn();
- startActivityAndCheckNetworkAccess();
- } finally {
- turnBatteryOff();
- finishActivity();
- setAppIdle(false);
- }
- }
-
- @Test
- public void testStartActivity_backgroundRestrict() throws Exception {
- updateRestrictBackgroundBlacklist(true);
- try {
- testConnOnActivityStart("testStartActivity_backgroundRestrict");
- } finally {
- updateRestrictBackgroundBlacklist(false);
- }
- }
-
- private void testConnOnActivityStart(String testName) throws Exception {
- for (int i = 1; i <= REPEAT_TEST_COUNT; ++i) {
- try {
- Log.d(TAG, testName + " Start #" + i);
- turnScreenOn();
- startActivityAndCheckNetworkAccess();
- } finally {
- finishActivity();
- Log.d(TAG, testName + " end #" + i);
- }
- }
- }
-
- // TODO: Some of these methods are also used in CTS, so instead of duplicating code,
- // create a static library which can be used by both servicestests and cts.
- private void setBatterySaverMode(boolean enabled) throws Exception {
- if (enabled) {
- turnBatteryOn();
- executeCommand("settings put global low_power 1");
- } else {
- executeCommand("settings put global low_power 0");
- turnBatteryOff();
- }
- final String result = executeCommand("settings get global low_power");
- assertEquals(enabled ? "1" : "0", result);
- }
-
- private void setDataSaverMode(boolean enabled) throws Exception {
- executeCommand("cmd netpolicy set restrict-background " + enabled);
- final String output = executeCommand("cmd netpolicy get restrict-background");
- final String expectedSuffix = enabled ? "enabled" : "disabled";
- assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'",
- output.endsWith(expectedSuffix));
- }
-
- private void setDozeMode(boolean enabled) throws Exception {
- if (enabled) {
- turnBatteryOn();
- turnScreenOff();
- executeCommand("dumpsys deviceidle force-idle deep");
- } else {
- turnScreenOn();
- turnBatteryOff();
- executeCommand("dumpsys deviceidle unforce");
- }
- assertDelayedCommandResult("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE",
- 5 /* maxTries */, 500 /* napTimeMs */);
- }
-
- private void setAppIdle(boolean enabled) throws Exception {
- executeCommand("am set-inactive " + TEST_PKG + " " + enabled);
- assertDelayedCommandResult("am get-inactive " + TEST_PKG, "Idle=" + enabled,
- 15 /* maxTries */, 2000 /* napTimeMs */);
- }
-
- private void updateRestrictBackgroundBlacklist(boolean add) throws Exception {
- if (add) {
- executeCommand("cmd netpolicy add restrict-background-blacklist " + mTestPkgUid);
- } else {
- executeCommand("cmd netpolicy remove restrict-background-blacklist " + mTestPkgUid);
- }
- assertRestrictBackground("restrict-background-blacklist", mTestPkgUid, add);
- }
-
- private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception {
- final int maxTries = 5;
- boolean actual = false;
- final String expectedUid = Integer.toString(uid);
- String uids = "";
- for (int i = 1; i <= maxTries; i++) {
- final String output = executeCommand("cmd netpolicy list " + list);
- uids = output.split(":")[1];
- for (String candidate : uids.split(" ")) {
- actual = candidate.trim().equals(expectedUid);
- if (expected == actual) {
- return;
- }
- }
- Log.v(TAG, list + " check for uid " + uid + " doesn't match yet (expected "
- + expected + ", got " + actual + "); sleeping 1s before polling again");
- SystemClock.sleep(1000);
- }
- fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual
- + ". Full list: " + uids);
- }
-
- private void turnBatteryOn() throws Exception {
- executeCommand("cmd battery unplug");
- executeCommand("cmd battery set status " + BatteryManager.BATTERY_STATUS_NOT_CHARGING);
- assertBatteryOn();
- }
-
- private void assertBatteryOn() throws Exception {
- final long endTime = SystemClock.uptimeMillis() + BATTERY_OFF_TIMEOUT_MS;
- while (mBatteryManager.isCharging() && SystemClock.uptimeMillis() < endTime) {
- SystemClock.sleep(BATTERY_OFF_CHECK_INTERVAL_MS);
- }
- assertFalse("Power should be disconnected", mBatteryManager.isCharging());
- }
-
- private void turnBatteryOff() throws Exception {
- executeCommand("cmd battery set ac " + BatteryManager.BATTERY_PLUGGED_AC);
- executeCommand("cmd battery set status " + BatteryManager.BATTERY_STATUS_CHARGING);
- }
-
- private static void batteryReset() throws Exception {
- executeCommand("cmd battery reset");
- }
-
- private void turnScreenOff() throws Exception {
- executeCommand("input keyevent KEYCODE_SLEEP");
- }
-
- private void turnScreenOn() throws Exception {
- executeCommand("input keyevent KEYCODE_WAKEUP");
- executeCommand("wm dismiss-keyguard");
- // Wait for screen-on state to propagate through the system.
- SystemClock.sleep(SCREEN_ON_DELAY_MS);
- }
-
- private static String executeCommand(String cmd) throws IOException {
- final String result = executeSilentCommand(cmd);
- Log.d(TAG, String.format("Result for '%s': %s", cmd, result));
- return result;
- }
-
- private static String executeSilentCommand(String cmd) throws IOException {
- return mUiDevice.executeShellCommand(cmd).trim();
- }
-
- private void assertDelayedCommandResult(String cmd, String expectedResult,
- int maxTries, int napTimeMs) throws Exception {
- String result = "";
- for (int i = 1; i <= maxTries; ++i) {
- result = executeCommand(cmd);
- if (expectedResult.equals(result)) {
- return;
- }
- Log.v(TAG, "Command '" + cmd + "' returned '" + result + " instead of '"
- + expectedResult + "' on attempt #" + i
- + "; sleeping " + napTimeMs + "ms before trying again");
- SystemClock.sleep(napTimeMs);
- }
- fail("Command '" + cmd + "' did not return '" + expectedResult + "' after "
- + maxTries + " attempts. Last result: '" + result + "'");
- }
-
- private void startActivityAndCheckNetworkAccess() throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- final Intent launchIntent = new Intent().setComponent(
- new ComponentName(TEST_PKG, TEST_ACTIVITY_CLASS));
- final Bundle extras = new Bundle();
- final String[] errors = new String[] {null};
- extras.putBinder(EXTRA_NETWORK_STATE_OBSERVER, new INetworkStateObserver.Stub() {
- @Override
- public void onNetworkStateChecked(String resultData) {
- errors[0] = resultData;
- latch.countDown();
- }
- });
- launchIntent.putExtras(extras)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(launchIntent);
- if (latch.await(NETWORK_CHECK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- if (errors[0] != null) {
- fail("Network not available for test app " + mTestPkgUid + ". " + errors[0]);
- }
- } else {
- fail("Timed out waiting for network availability status from test app " + mTestPkgUid);
- }
- }
-
- private static void fail(String msg) throws Exception {
- dumpOnFailure();
- Assert.fail(msg);
- }
-
- private static void dumpOnFailure() throws Exception {
- dump("network_management");
- dump("netpolicy");
- dumpUsageStats();
- }
-
- private static void dumpUsageStats() throws Exception {
- final String output = executeSilentCommand("dumpsys usagestats");
- final StringBuilder sb = new StringBuilder();
- final TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter('\n');
- splitter.setString(output);
- String str;
- while (splitter.hasNext()) {
- str = splitter.next();
- if (str.contains("package=") && !str.contains(TEST_PKG)) {
- continue;
- }
- if (str.trim().startsWith("config=") || str.trim().startsWith("time=")) {
- continue;
- }
- sb.append(str).append('\n');
- }
- dump("usagestats", sb.toString());
- }
-
- private static void dump(String service) throws Exception {
- dump(service, executeSilentCommand("dumpsys " + service));
- }
-
- private static void dump(String service, String dump) throws Exception {
- Log.d(TAG, ">>> Begin dump " + service);
- Log.printlns(Log.LOG_ID_MAIN, Log.DEBUG, TAG, dump, null);
- Log.d(TAG, "<<< End dump " + service);
- }
-
- private void finishActivity() throws Exception {
- mCmdReceiverService.finishActivity();
- }
-} \ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index fdf9354747a0..40943774c0af 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -1975,7 +1975,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
if (si == null) {
return null;
}
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
return new File(si.getBitmapPath()).getName();
}
@@ -1984,7 +1984,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
if (si == null) {
return null;
}
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
return new File(si.getBitmapPath()).getAbsolutePath();
}
@@ -2139,7 +2139,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
}
protected boolean bitmapDirectoryExists(String packageName, int userId) {
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
final File path = new File(mService.getUserBitmapFilePath(userId), packageName);
return path.isDirectory();
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 867890f938ba..411b52155abb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -1040,7 +1040,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
dumpsysOnLogcat();
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
// Check files and directories.
// Package 3 has no bitmaps, so we don't create a directory.
assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2);
@@ -1096,7 +1096,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "3").createNewFile();
makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "4").createNewFile();
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
"a.b.c", "d.e.f");
@@ -1111,7 +1111,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// The below check is the same as above, except this time USER_0 use the CALLING_PACKAGE_3
// directory.
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3);
assertBitmapDirectories(USER_10, CALLING_PACKAGE_1, CALLING_PACKAGE_2);
@@ -1390,7 +1390,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
.setIcon(Icon.createWithContentUri("test_uri"))
.build()
)));
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
assertWith(getCallerShortcuts())
.forShortcutWithId("s1", si -> {
assertTrue(si.hasIconUri());
@@ -1402,13 +1402,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
.setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32))
.build()
)));
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
assertWith(getCallerShortcuts())
.forShortcutWithId("s1", si -> {
assertTrue(si.hasIconResource());
assertEquals(R.drawable.black_32x32, si.getIconResourceId());
});
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
mInjectedCurrentTimeMillis += INTERVAL; // reset throttling
@@ -1419,7 +1419,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
getTestContext().getResources(), R.drawable.black_64x64)))
.build()
)));
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
assertWith(getCallerShortcuts())
.forShortcutWithId("s1", si -> {
assertTrue(si.hasIconFile());
@@ -1437,7 +1437,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
getTestContext().getResources(), R.drawable.black_64x64)))
.build()
)));
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
assertWith(getCallerShortcuts())
.forShortcutWithId("s1", si -> {
assertTrue(si.hasIconFile());
@@ -1451,7 +1451,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
.setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32))
.build()
)));
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
assertWith(getCallerShortcuts())
.forShortcutWithId("s1", si -> {
assertTrue(si.hasIconResource());
@@ -1463,7 +1463,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
.setIcon(Icon.createWithContentUri("test_uri"))
.build()
)));
- mService.waitForBitmapSavesForTest();
+ mService.waitForBitmapSaves();
assertWith(getCallerShortcuts())
.forShortcutWithId("s1", si -> {
assertTrue(si.hasIconUri());
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.bp b/services/tests/servicestests/test-apps/ConnTestApp/Android.bp
deleted file mode 100644
index 0731e2ca1f41..000000000000
--- a/services/tests/servicestests/test-apps/ConnTestApp/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test_helper_app {
- name: "ConnTestApp",
-
- test_suites: ["device-tests"],
-
- static_libs: ["servicestests-aidl"],
- srcs: ["**/*.java"],
-
- platform_apis: true,
- certificate: "platform",
- dex_preopt: {
- enabled: false,
- },
- optimize: {
- enabled: false,
- },
-}
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
deleted file mode 100644
index 201cd05052ea..000000000000
--- a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.servicestests.apps.conntestapp">
-
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
-
- <application>
- <activity android:name=".ConnTestActivity"
- android:exported="true" />
- <service android:name=".CmdReceiverService"
- android:exported="true" />
- </application>
-
-</manifest> \ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/OWNERS b/services/tests/servicestests/test-apps/ConnTestApp/OWNERS
deleted file mode 100644
index aa87958f1d53..000000000000
--- a/services/tests/servicestests/test-apps/ConnTestApp/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /services/core/java/com/android/server/net/OWNERS
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/CmdReceiverService.java b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/CmdReceiverService.java
deleted file mode 100644
index 6130f3a3fc76..000000000000
--- a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/CmdReceiverService.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.servicestests.apps.conntestapp;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-import com.android.servicestests.aidl.ICmdReceiverService;
-
-public class CmdReceiverService extends Service {
- private ICmdReceiverService.Stub mBinder = new ICmdReceiverService.Stub() {
- @Override
- public void finishActivity() {
- ConnTestActivity.finishSelf();
- }
- };
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-} \ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
deleted file mode 100644
index f8d1d03cd7a6..000000000000
--- a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.servicestests.apps.conntestapp;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.INetworkPolicyManager;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.INetworkManagementService;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.servicestests.aidl.INetworkStateObserver;
-
-public class ConnTestActivity extends Activity {
- private static final String TAG = ConnTestActivity.class.getSimpleName();
-
- private static final String TEST_PKG = ConnTestActivity.class.getPackage().getName();
- private static final String ACTION_FINISH_ACTIVITY = TEST_PKG + ".FINISH";
- private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
-
- private static final Object INSTANCE_LOCK = new Object();
- @GuardedBy("instanceLock")
- private static Activity sInstance;
-
- private BroadcastReceiver finishCommandReceiver = null;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- synchronized (INSTANCE_LOCK) {
- sInstance = this;
- }
- Log.i(TAG, "onCreate called");
-
- notifyNetworkStateObserver();
-
- finishCommandReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.i(TAG, "finish command received");
- ConnTestActivity.this.finish();
- }
- };
- registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY));
- }
-
- @Override
- public void onResume() {
- super.onResume();
- Log.i(TAG, "onResume called");
- }
-
- @Override
- public void onStop() {
- Log.i(TAG, "onStop called");
- if (finishCommandReceiver != null) {
- unregisterReceiver(finishCommandReceiver);
- finishCommandReceiver = null;
- }
- super.onStop();
- }
-
- @Override
- public void finish() {
- synchronized (INSTANCE_LOCK) {
- sInstance = null;
- }
- Log.i(TAG, "finish called");
- super.finish();
- }
-
- public static void finishSelf() {
- synchronized (INSTANCE_LOCK) {
- if (sInstance != null) {
- sInstance.finish();
- }
- }
- }
-
- private void notifyNetworkStateObserver() {
- if (getIntent() == null) {
- return;
- }
-
- final Bundle extras = getIntent().getExtras();
- if (extras == null) {
- return;
- }
- final INetworkStateObserver observer = INetworkStateObserver.Stub.asInterface(
- extras.getBinder(EXTRA_NETWORK_STATE_OBSERVER));
- if (observer != null) {
- AsyncTask.execute(() -> {
- try {
- observer.onNetworkStateChecked(checkNetworkStatus());
- } catch (RemoteException e) {
- Log.e(TAG, "Error occured while notifying the observer: " + e);
- }
- });
- }
- }
-
- /**
- * Checks whether the network is restricted.
- *
- * @return null if network is not restricted, otherwise an error message.
- */
- private String checkNetworkStatus() {
- final INetworkManagementService nms = INetworkManagementService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
- final INetworkPolicyManager npms = INetworkPolicyManager.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
- try {
- final boolean restrictedByFwRules = nms.isNetworkRestricted(Process.myUid());
- final boolean restrictedByUidRules = npms.isUidNetworkingBlocked(Process.myUid(), true);
- if (restrictedByFwRules || restrictedByUidRules) {
- return "Network is restricted by fwRules: " + restrictedByFwRules
- + " and uidRules: " + restrictedByUidRules;
- }
- return null;
- } catch (RemoteException e) {
- return "Error talking to system server: " + e;
- }
- }
-} \ No newline at end of file
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index 767857bf2de8..e8e3a8f84f21 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -33,6 +33,7 @@
<uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/>
<uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
+ <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index f4b9e258f7e0..76d4059eb436 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -30,8 +30,11 @@ import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -46,6 +49,8 @@ import android.os.Bundle;
import android.os.UserHandle;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
+import android.service.notification.StatusBarNotification;
import android.testing.TestableContext;
import android.util.ArraySet;
import android.util.Pair;
@@ -59,11 +64,13 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.internal.util.reflection.FieldSetter;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.util.List;
public class NotificationListenersTest extends UiServiceTestCase {
@@ -388,4 +395,66 @@ public class NotificationListenersTest extends UiServiceTestCase {
verify(mContext).sendBroadcastAsUser(
any(), eq(UserHandle.of(userId)), nullable(String.class));
}
+
+ @Test
+ public void testNotifyPostedLockedInLockdownMode() {
+ NotificationRecord r = mock(NotificationRecord.class);
+ NotificationRecord old = mock(NotificationRecord.class);
+
+ // before the lockdown mode
+ when(mNm.isInLockDownMode()).thenReturn(false);
+ mListeners.notifyPostedLocked(r, old, true);
+ mListeners.notifyPostedLocked(r, old, false);
+ verify(r, atLeast(2)).getSbn();
+
+ // in the lockdown mode
+ reset(r);
+ reset(old);
+ when(mNm.isInLockDownMode()).thenReturn(true);
+ mListeners.notifyPostedLocked(r, old, true);
+ mListeners.notifyPostedLocked(r, old, false);
+ verify(r, never()).getSbn();
+ }
+
+ @Test
+ public void testnotifyRankingUpdateLockedInLockdownMode() {
+ List chn = mock(List.class);
+
+ // before the lockdown mode
+ when(mNm.isInLockDownMode()).thenReturn(false);
+ mListeners.notifyRankingUpdateLocked(chn);
+ verify(chn, atLeast(1)).size();
+
+ // in the lockdown mode
+ reset(chn);
+ when(mNm.isInLockDownMode()).thenReturn(true);
+ mListeners.notifyRankingUpdateLocked(chn);
+ verify(chn, never()).size();
+ }
+
+ @Test
+ public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException {
+ NotificationRecord r = mock(NotificationRecord.class);
+ NotificationStats rs = mock(NotificationStats.class);
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ FieldSetter.setField(mNm,
+ NotificationManagerService.class.getDeclaredField("mHandler"),
+ mock(NotificationManagerService.WorkerHandler.class));
+
+ // before the lockdown mode
+ when(mNm.isInLockDownMode()).thenReturn(false);
+ when(r.getSbn()).thenReturn(sbn);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ verify(r, atLeast(2)).getSbn();
+
+ // in the lockdown mode
+ reset(r);
+ reset(rs);
+ when(mNm.isInLockDownMode()).thenReturn(true);
+ when(r.getSbn()).thenReturn(sbn);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ verify(r, never()).getSbn();
+ }
}
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 b987c692bddb..348e015500fe 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -63,10 +63,13 @@ import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
@@ -352,6 +355,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
MultiRateLimiter mToastRateLimiter;
BroadcastReceiver mPackageIntentReceiver;
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
+ TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
@Mock
@@ -508,6 +512,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setAudioManager(mAudioManager);
+ mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext);
+ mService.setStrongAuthTracker(mStrongAuthTracker);
+
mShortcutHelper = mService.getShortcutHelper();
mShortcutHelper.setLauncherApps(mLauncherApps);
mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
@@ -9247,4 +9254,44 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// make sure the summary was removed and not re-posted
assertThat(mService.getNotificationRecordCount()).isEqualTo(0);
}
+
+ @Test
+ public void testStrongAuthTracker_isInLockDownMode() {
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+ assertTrue(mStrongAuthTracker.isInLockDownMode());
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+ assertFalse(mStrongAuthTracker.isInLockDownMode());
+ }
+
+ @Test
+ public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() {
+ // post 2 notifications from 2 packages
+ NotificationRecord pkgA = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgA);
+ NotificationRecord pkgB = new NotificationRecord(mContext,
+ generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgB);
+
+ // when entering the lockdown mode, cancel the 2 notifications.
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+ assertTrue(mStrongAuthTracker.isInLockDownMode());
+
+ // the notifyRemovedLocked function is called twice due to REASON_CANCEL_ALL.
+ ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
+ verify(mListeners, times(2)).notifyRemovedLocked(any(), captor.capture(), any());
+ assertEquals(REASON_CANCEL_ALL, captor.getValue().intValue());
+
+ // exit lockdown mode.
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+
+ // the notifyPostedLocked function is called twice.
+ verify(mListeners, times(2)).notifyPostedLocked(any(), any());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
index bde048569e53..4ed7d35a097f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java
@@ -113,4 +113,20 @@ public class TestableNotificationManagerService extends NotificationManagerServi
protected void doChannelWarningToast(int uid, CharSequence toastText) {
mChannelToastsSent.add(uid);
}
+
+ public class StrongAuthTrackerFake extends NotificationManagerService.StrongAuthTracker {
+ private int mGetStrongAuthForUserReturnValue = 0;
+ StrongAuthTrackerFake(Context context) {
+ super(context);
+ }
+
+ public void setGetStrongAuthForUserReturnValue(int val) {
+ mGetStrongAuthForUserReturnValue = val;
+ }
+
+ @Override
+ public int getStrongAuthForUser(int userId) {
+ return mGetStrongAuthForUserReturnValue;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 7689e08bc3f3..2fea2284ff2a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -27,10 +27,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMor
import static com.google.common.truth.Truth.assertWithMessage;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
@@ -40,24 +38,22 @@ import android.app.ActivityOptions;
import android.app.ActivityOptions.SourceInfo;
import android.app.WaitResult;
import android.app.WindowConfiguration;
+import android.content.ComponentName;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.ArrayMap;
+import android.util.Log;
import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
-import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
-
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
+import org.mockito.ArgumentCaptor;
-import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.function.ToIntFunction;
@@ -75,13 +71,14 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
private ActivityMetricsLogger mActivityMetricsLogger;
private ActivityMetricsLogger.LaunchingState mLaunchingState;
private ActivityMetricsLaunchObserver mLaunchObserver;
- private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry;
private ActivityRecord mTrampolineActivity;
private ActivityRecord mTopActivity;
private ActivityOptions mActivityOptions;
private boolean mLaunchTopByTrampoline;
private boolean mNewActivityCreated = true;
+ private long mExpectedStartedId;
+ private final ArrayMap<ComponentName, Long> mLastLaunchedIds = new ArrayMap<>();
@Before
public void setUpAMLO() {
@@ -89,9 +86,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
// ActivityTaskSupervisor always creates its own instance of ActivityMetricsLogger.
mActivityMetricsLogger = mSupervisor.getActivityMetricsLogger();
-
- mLaunchObserverRegistry = mActivityMetricsLogger.getLaunchObserverRegistry();
- mLaunchObserverRegistry.registerLaunchObserver(mLaunchObserver);
+ mActivityMetricsLogger.getLaunchObserverRegistry().registerLaunchObserver(mLaunchObserver);
// Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
// This seems to be the easiest way to create an ActivityRecord.
@@ -107,65 +102,70 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
mTrampolineActivity.mVisibleRequested = false;
}
- @After
- public void tearDownAMLO() {
- if (mLaunchObserverRegistry != null) { // Don't NPE if setUp failed.
- mLaunchObserverRegistry.unregisterLaunchObserver(mLaunchObserver);
- }
+ private <T> T verifyAsync(T mock) {
+ // With WindowTestRunner, all test methods are inside WM lock, so we have to unblock any
+ // messages that are waiting for the lock.
+ waitHandlerIdle(mAtm.mH);
+ // AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout.
+ return verify(mock, timeout(TIMEOUT_MS));
}
- static class ActivityRecordMatcher implements ArgumentMatcher</*@ActivityRecordProto*/ byte[]> {
- private final @ActivityRecordProto byte[] mExpected;
-
- public ActivityRecordMatcher(ActivityRecord activityRecord) {
- mExpected = activityRecordToProto(activityRecord);
- }
+ private void verifyOnActivityLaunched(ActivityRecord activity) {
+ final ArgumentCaptor<Long> idCaptor = ArgumentCaptor.forClass(Long.class);
+ verifyAsync(mLaunchObserver).onActivityLaunched(idCaptor.capture(),
+ eq(activity.mActivityComponent), anyInt());
+ final long id = idCaptor.getValue();
+ setExpectedStartedId(id, activity);
+ mLastLaunchedIds.put(activity.mActivityComponent, id);
+ }
- public boolean matches(@ActivityRecordProto byte[] actual) {
- return Arrays.equals(mExpected, actual);
- }
+ private void verifyOnActivityLaunchFinished(ActivityRecord activity) {
+ verifyAsync(mLaunchObserver).onActivityLaunchFinished(eq(mExpectedStartedId),
+ eq(activity.mActivityComponent), anyLong());
}
- static @ActivityRecordProto byte[] activityRecordToProto(ActivityRecord record) {
- return ActivityMetricsLogger.convertActivityRecordToProto(record);
+ private void setExpectedStartedId(long id, Object reason) {
+ mExpectedStartedId = id;
+ Log.i("AMLTest", "setExpectedStartedId=" + id + " from " + reason);
}
- static @ActivityRecordProto byte[] eqProto(ActivityRecord record) {
- return argThat(new ActivityRecordMatcher(record));
+ private void setLastExpectedStartedId(ActivityRecord r) {
+ setExpectedStartedId(getLastStartedId(r), r);
}
- private <T> T verifyAsync(T mock) {
- // With WindowTestRunner, all test methods are inside WM lock, so we have to unblock any
- // messages that are waiting for the lock.
- waitHandlerIdle(mAtm.mH);
- // AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout.
- return verify(mock, timeout(TIMEOUT_MS));
+ private long getLastStartedId(ActivityRecord r) {
+ final Long id = mLastLaunchedIds.get(r.mActivityComponent);
+ return id != null ? id : -1;
}
- private void verifyOnActivityLaunchFinished(ActivityRecord activity) {
- verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(activity), anyLong());
+ private long eqLastStartedId(ActivityRecord r) {
+ return eq(getLastStartedId(r));
}
- private void onIntentStarted(Intent intent) {
+ private long onIntentStarted(Intent intent) {
notifyActivityLaunching(intent);
+ long timestamp = -1;
// If it is launching top activity from trampoline activity, the observer shouldn't receive
// onActivityLaunched because the activities should belong to the same transition.
if (!mLaunchTopByTrampoline) {
- verifyAsync(mLaunchObserver).onIntentStarted(eq(intent), anyLong());
+ final ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class);
+ verifyAsync(mLaunchObserver).onIntentStarted(eq(intent), captor.capture());
+ timestamp = captor.getValue();
}
verifyNoMoreInteractions(mLaunchObserver);
+ return timestamp;
}
@Test
public void testOnIntentFailed() {
- onIntentStarted(new Intent("testOnIntentFailed"));
+ final long id = onIntentStarted(new Intent("testOnIntentFailed"));
// Bringing an intent that's already running 'to front' is not considered
// as an ACTIVITY_LAUNCHED state transition.
notifyActivityLaunched(START_TASK_TO_FRONT, null /* launchedActivity */);
- verifyAsync(mLaunchObserver).onIntentFailed();
+ verifyAsync(mLaunchObserver).onIntentFailed(eq(id));
verifyNoMoreInteractions(mLaunchObserver);
}
@@ -208,9 +208,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
private void onActivityLaunched(ActivityRecord activity) {
onIntentStarted(activity.intent);
- notifyActivityLaunched(START_SUCCESS, activity);
+ notifyAndVerifyActivityLaunched(activity);
- verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(activity), anyInt());
verifyNoMoreInteractions(mLaunchObserver);
}
@@ -235,7 +234,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
// Cannot time already-visible activities.
notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
- verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqLastStartedId(mTopActivity));
verifyNoMoreInteractions(mLaunchObserver);
}
@@ -250,33 +249,33 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
.build();
notifyActivityLaunching(noDrawnActivity.intent);
- notifyActivityLaunched(START_SUCCESS, noDrawnActivity);
+ notifyAndVerifyActivityLaunched(noDrawnActivity);
noDrawnActivity.mVisibleRequested = false;
mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
- verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity));
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqLastStartedId(noDrawnActivity));
// If an activity is removed immediately before visibility update, it should cancel too.
final ActivityRecord removedImm = new ActivityBuilder(mAtm).setCreateTask(true).build();
clearInvocations(mLaunchObserver);
onActivityLaunched(removedImm);
removedImm.removeImmediately();
- // Verify any() instead of proto because the field of record may be changed.
- verifyAsync(mLaunchObserver).onActivityLaunchCancelled(any());
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqLastStartedId(removedImm));
}
@Test
public void testOnActivityLaunchWhileSleeping() {
notifyActivityLaunching(mTrampolineActivity.intent);
- notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
+ notifyAndVerifyActivityLaunched(mTrampolineActivity);
doReturn(true).when(mTrampolineActivity.mDisplayContent).isSleeping();
mTrampolineActivity.setState(ActivityRecord.State.RESUMED, "test");
mTrampolineActivity.setVisibility(false);
waitHandlerIdle(mAtm.mH);
// Not cancel immediately because in one of real cases, the keyguard may be going away or
// occluded later, then the activity can be drawn.
- verify(mLaunchObserver, never()).onActivityLaunchCancelled(eqProto(mTrampolineActivity));
+ verify(mLaunchObserver, never()).onActivityLaunchCancelled(
+ eqLastStartedId(mTrampolineActivity));
clearInvocations(mLaunchObserver);
mLaunchTopByTrampoline = true;
@@ -289,9 +288,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
// The posted message will acquire wm lock, so the test needs to release the lock to verify.
final Throwable error = awaitInWmLock(() -> {
try {
- // Though the aborting target should be eqProto(mTopActivity), use any() to avoid
- // any changes in proto that may cause failure by different arguments.
- verify(mLaunchObserver, timeout(TIMEOUT_MS)).onActivityLaunchCancelled(any());
+ verify(mLaunchObserver, timeout(TIMEOUT_MS)).onActivityLaunchCancelled(
+ mExpectedStartedId);
} catch (Throwable e) {
// Catch any errors including assertion because this runs in another thread.
return e;
@@ -314,9 +312,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
mActivityOptions = ActivityOptions.makeBasic();
mActivityOptions.setSourceInfo(SourceInfo.TYPE_LAUNCHER, SystemClock.uptimeMillis() - 10);
onIntentStarted(mTopActivity.intent);
- notifyActivityLaunched(START_SUCCESS, mTopActivity);
- verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
- verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(prev));
+ notifyAndVerifyActivityLaunched(mTopActivity);
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eq(getLastStartedId(prev)));
// The activity reports fully drawn before windows drawn, then the fully drawn event will
// be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}).
@@ -328,7 +325,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
.isEqualTo(SourceInfo.TYPE_LAUNCHER);
assertWithMessage("Record event time").that(info.sourceEventDelayMs).isAtLeast(10);
- verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong());
+ verifyAsync(mLaunchObserver).onReportFullyDrawn(eq(mExpectedStartedId), anyLong());
verifyOnActivityLaunchFinished(mTopActivity);
verifyNoMoreInteractions(mLaunchObserver);
@@ -339,9 +336,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
private void onActivityLaunchedTrampoline() {
onIntentStarted(mTrampolineActivity.intent);
- notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
-
- verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTrampolineActivity), anyInt());
+ notifyAndVerifyActivityLaunched(mTrampolineActivity);
// A second, distinct, activity launch is coalesced into the current app launch sequence.
mLaunchTopByTrampoline = true;
@@ -370,6 +365,11 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
mNewActivityCreated, activity, mActivityOptions);
}
+ private void notifyAndVerifyActivityLaunched(ActivityRecord activity) {
+ notifyActivityLaunched(START_SUCCESS, activity);
+ verifyOnActivityLaunched(activity);
+ }
+
private void notifyTransitionStarting(ActivityRecord activity) {
final ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>();
reasons.put(activity, ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN);
@@ -430,7 +430,7 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
// Cannot time already-visible activities.
notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
- verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(mExpectedStartedId);
verifyNoMoreInteractions(mLaunchObserver);
}
@@ -447,25 +447,14 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
// be reported successfully.
notifyTransitionStarting(mTopActivity);
+ verifyOnActivityLaunched(mTopActivity);
verifyOnActivityLaunchFinished(mTopActivity);
}
@Test
- public void testActivityRecordProtoIsNotTooBig() {
- // The ActivityRecordProto must not be too big, otherwise converting it at runtime
- // will become prohibitively expensive.
- assertWithMessage("mTopActivity: %s", mTopActivity)
- .that(activityRecordToProto(mTopActivity).length)
- .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
-
- assertWithMessage("mTrampolineActivity: %s", mTrampolineActivity)
- .that(activityRecordToProto(mTrampolineActivity).length)
- .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
- }
-
- @Test
public void testConcurrentLaunches() {
onActivityLaunched(mTopActivity);
+ clearInvocations(mLaunchObserver);
final ActivityMetricsLogger.LaunchingState previousState = mLaunchingState;
final ActivityRecord otherActivity = new ActivityBuilder(mAtm)
@@ -476,11 +465,13 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
// state should be created here.
onActivityLaunched(otherActivity);
- assertWithMessage("Different callers should get 2 indepedent launching states")
+ assertWithMessage("Different callers should get 2 independent launching states")
.that(previousState).isNotEqualTo(mLaunchingState);
+ setLastExpectedStartedId(otherActivity);
transitToDrawnAndVerifyOnLaunchFinished(otherActivity);
// The first transition should still be valid.
+ setLastExpectedStartedId(mTopActivity);
transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
}
@@ -534,10 +525,12 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
// Before TopActivity is drawn, it launches another activity on a different display.
mActivityMetricsLogger.notifyActivityLaunching(activityOnNewDisplay.intent,
mTopActivity /* caller */, mTopActivity.getUid());
- notifyActivityLaunched(START_SUCCESS, activityOnNewDisplay);
+ notifyAndVerifyActivityLaunched(activityOnNewDisplay);
// There should be 2 events instead of coalescing as one event.
+ setLastExpectedStartedId(mTopActivity);
transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
+ setLastExpectedStartedId(activityOnNewDisplay);
transitToDrawnAndVerifyOnLaunchFinished(activityOnNewDisplay);
}
@@ -548,9 +541,11 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
onActivityLaunched(mTrampolineActivity);
mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent,
mTrampolineActivity /* caller */, mTrampolineActivity.getUid());
- notifyActivityLaunched(START_SUCCESS, mTopActivity);
+ notifyAndVerifyActivityLaunched(mTopActivity);
// Different windowing modes should be independent launch events.
+ setLastExpectedStartedId(mTrampolineActivity);
transitToDrawnAndVerifyOnLaunchFinished(mTrampolineActivity);
+ setLastExpectedStartedId(mTopActivity);
transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index d65e27d0f642..533540e2568d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -757,6 +757,8 @@ public class ActivityRecordTests extends WindowTestsBase {
final ActivityRecord activity = createActivityWithTask();
ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(activity.getTask()).build();
topActivity.setOccludesParent(false);
+ // The requested occluding state doesn't affect whether it fills parent.
+ assertTrue(topActivity.fillsParent());
activity.setState(STOPPED, "Testing");
activity.setVisibility(true);
activity.makeActiveIfNeeded(null /* activeActivity */);
@@ -1218,7 +1220,7 @@ public class ActivityRecordTests extends WindowTestsBase {
task.setPausingActivity(currentTop);
currentTop.finishing = true;
currentTop.setState(PAUSED, "test");
- currentTop.completeFinishing("completePauseLocked");
+ currentTop.completeFinishing(false /* updateVisibility */, "completePause");
// Current top becomes stopping because it is visible and the next is invisible.
assertEquals(STOPPING, currentTop.getState());
@@ -3139,7 +3141,7 @@ public class ActivityRecordTests extends WindowTestsBase {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
InsetsSource imeSource = new InsetsSource(ITYPE_IME);
- app.getInsetsState().addSource(imeSource);
+ app.mAboveInsetsState.addSource(imeSource);
mDisplayContent.setImeLayeringTarget(app);
mDisplayContent.updateImeInputAndControlTarget(app);
@@ -3156,10 +3158,12 @@ public class ActivityRecordTests extends WindowTestsBase {
// Simulate app re-start input or turning screen off/on then unlocked by un-secure
// keyguard to back to the app, expect IME insets is not frozen
mDisplayContent.updateImeInputAndControlTarget(app);
+ app.mActivityRecord.commitVisibility(true, false);
assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ imeSource.setVisible(true);
imeSource.setFrame(new Rect(100, 400, 500, 500));
- app.getInsetsState().addSource(imeSource);
- app.getInsetsState().setSourceVisible(ITYPE_IME, true);
+ app.mAboveInsetsState.addSource(imeSource);
// Verify when IME is visible and the app can receive the right IME insets from policy.
makeWindowVisibleAndDrawn(app, mImeWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 33b70249dabe..8474a36dc681 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CHANGE;
@@ -46,7 +47,6 @@ import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -89,14 +89,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
mAppTransitionController = new AppTransitionController(mWm, mDisplayContent);
}
- @Override
- ActivityRecord createActivityRecord(DisplayContent dc, int windowingMode, int activityType) {
- final ActivityRecord r = super.createActivityRecord(dc, windowingMode, activityType);
- // Ensure that ActivityRecord#setOccludesParent takes effect.
- doCallRealMethod().when(r).fillsParent();
- return r;
- }
-
@Test
public void testSkipOccludedActivityCloseTransition() {
final ActivityRecord behind = createActivityRecord(mDisplayContent,
@@ -135,7 +127,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- translucentOpening.setOccludesParent(false);
+ doReturn(false).when(translucentOpening).fillsParent();
translucentOpening.setVisible(false);
mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
mDisplayContent.mOpeningApps.add(behind);
@@ -153,7 +145,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final ActivityRecord translucentClosing = createActivityRecord(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
- translucentClosing.setOccludesParent(false);
+ doReturn(false).when(translucentClosing).fillsParent();
mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
mDisplayContent.mClosingApps.add(translucentClosing);
assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE,
@@ -562,6 +554,37 @@ public class AppTransitionControllerTest extends WindowTestsBase {
}
@Test
+ public void testGetAnimationTargets_splitScreenOpening() {
+ // [DisplayContent] - [Task] -+- [split task 1] -+- [Task1] - [AR1] (opening, invisible)
+ // +- [split task 2] -+- [Task2] - [AR2] (opening, invisible)
+ final Task singleTopRoot = createTask(mDisplayContent);
+ final TaskBuilder builder = new TaskBuilder(mSupervisor)
+ .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
+ .setParentTaskFragment(singleTopRoot)
+ .setCreatedByOrganizer(true);
+ final Task splitRoot1 = builder.build();
+ final Task splitRoot2 = builder.build();
+ splitRoot1.setAdjacentTaskFragment(splitRoot2, false /* moveTogether */);
+ final ActivityRecord activity1 = createActivityRecordWithParentTask(splitRoot1);
+ activity1.setVisible(false);
+ activity1.mVisibleRequested = true;
+ final ActivityRecord activity2 = createActivityRecordWithParentTask(splitRoot2);
+ activity2.setVisible(false);
+ activity2.mVisibleRequested = true;
+
+ final ArraySet<ActivityRecord> opening = new ArraySet<>();
+ opening.add(activity1);
+ opening.add(activity2);
+ final ArraySet<ActivityRecord> closing = new ArraySet<>();
+
+ // Promote animation targets up to Task level, not beyond.
+ assertEquals(
+ new ArraySet<>(new WindowContainer[]{splitRoot1, splitRoot2}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, true /* visible */));
+ }
+
+ @Test
public void testGetAnimationTargets_openingClosingTaskFragment() {
// [DefaultTDA] - [Task] -+- [TaskFragment1] - [ActivityRecord1] (opening, invisible)
// +- [TaskFragment2] - [ActivityRecord2] (closing, visible)
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 32d201fafcfb..263c9364c965 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -41,8 +41,10 @@ import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
@@ -1167,6 +1169,20 @@ public class DisplayContentTests extends WindowTestsBase {
assertNull(mDisplayContent.computeImeParent());
}
+ @UseTestDisplay(addWindows = W_ACTIVITY)
+ @Test
+ public void testComputeImeParent_updateParentWhenTargetNotUseIme() throws Exception {
+ WindowState overlay = createWindow(null, TYPE_APPLICATION_OVERLAY, "overlay");
+ overlay.setBounds(100, 100, 200, 200);
+ overlay.mAttrs.flags = FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM;
+ WindowState app = createWindow(null, TYPE_BASE_APPLICATION, "app");
+ mDisplayContent.setImeLayeringTarget(overlay);
+ mDisplayContent.setImeInputTarget(app);
+ assertFalse(mDisplayContent.shouldImeAttachedToApp());
+ assertEquals(mDisplayContent.getImeContainer().getParentSurfaceControl(),
+ mDisplayContent.computeImeParent());
+ }
+
@Test
public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception {
final DisplayContent dc = createNewDisplay();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 25cff61c3b78..e4eb98e79576 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -40,7 +40,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.clearInvocations;
+import android.app.WindowConfiguration;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -515,6 +517,69 @@ public class DisplayRotationTests {
}
@Test
+ public void testAllowAllRotations_allowsUpsideDownSuggestion()
+ throws Exception {
+ mBuilder.build();
+ mTarget.updateOrientation(SCREEN_ORIENTATION_UNSPECIFIED, true);
+ configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
+ when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
+ .thenReturn(true);
+ freezeRotation(Surface.ROTATION_0);
+ enableOrientationSensor();
+
+ mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
+ assertTrue(waitForUiHandler());
+
+ verify(mMockStatusBarManagerInternal)
+ .onProposedRotationChanged(Surface.ROTATION_180, true);
+ }
+
+ @Test
+ public void testDoNotAllowAllRotations_doesNotAllowUpsideDownSuggestion()
+ throws Exception {
+ mBuilder.build();
+ mTarget.updateOrientation(SCREEN_ORIENTATION_UNSPECIFIED, true);
+ configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
+ when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
+ .thenReturn(false);
+ freezeRotation(Surface.ROTATION_0);
+ enableOrientationSensor();
+
+ mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
+ assertTrue(waitForUiHandler());
+
+ verify(mMockStatusBarManagerInternal)
+ .onProposedRotationChanged(Surface.ROTATION_180, false);
+ }
+
+ @Test
+ public void testAllowAllRotations_allowAllRotationsBecomesDisabled_forbidsUpsideDownSuggestion()
+ throws Exception {
+ mBuilder.build();
+ mTarget.updateOrientation(SCREEN_ORIENTATION_UNSPECIFIED, true);
+ configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
+ when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
+ .thenReturn(true);
+ freezeRotation(Surface.ROTATION_0);
+ enableOrientationSensor();
+ mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
+ assertTrue(waitForUiHandler());
+
+ // Change resource to disallow all rotations.
+ // Reset "allowAllRotations".
+ mTarget.applyCurrentRotation(Surface.ROTATION_0);
+ clearInvocations(mMockStatusBarManagerInternal);
+ when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
+ .thenReturn(false);
+ mTarget.resetAllowAllRotations();
+ mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
+ assertTrue(waitForUiHandler());
+
+ verify(mMockStatusBarManagerInternal)
+ .onProposedRotationChanged(Surface.ROTATION_180, false);
+ }
+
+ @Test
public void testReturnsCompatibleRotation_SensorEnabled_RotationThawed() throws Exception {
mBuilder.build();
configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
@@ -721,14 +786,20 @@ public class DisplayRotationTests {
doReturn(true).when(mMockDisplayPolicy).navigationBarCanMove();
doReturn(win).when(mMockDisplayPolicy).getTopFullscreenOpaqueWindow();
mMockDisplayContent.mCurrentFocus = win;
- mTarget.mUpsideDownRotation = Surface.ROTATION_180;
+ // This should not affect the condition of shouldRotateSeamlessly.
+ mTarget.mUpsideDownRotation = Surface.ROTATION_90;
doReturn(true).when(win.mActivityRecord).matchParentBounds();
// The focused fullscreen opaque window without override bounds should be able to be
// rotated seamlessly.
assertTrue(mTarget.shouldRotateSeamlessly(
Surface.ROTATION_0, Surface.ROTATION_90, false /* forceUpdate */));
+ // Reject any 180 degree because non-movable navbar will be placed in a different position.
+ doReturn(false).when(mMockDisplayPolicy).navigationBarCanMove();
+ assertFalse(mTarget.shouldRotateSeamlessly(
+ Surface.ROTATION_90, Surface.ROTATION_180, false /* forceUpdate */));
+ doReturn(true).when(mMockDisplayPolicy).navigationBarCanMove();
doReturn(false).when(win.mActivityRecord).matchParentBounds();
// No seamless rotation if the window may be positioned with offset after rotation.
assertFalse(mTarget.shouldRotateSeamlessly(
@@ -935,6 +1006,8 @@ public class DisplayRotationTests {
.thenReturn(WmDisplayCutout.NO_CUTOUT);
when(mMockDisplayContent.getDefaultTaskDisplayArea())
.thenReturn(mock(TaskDisplayArea.class));
+ when(mMockDisplayContent.getWindowConfiguration())
+ .thenReturn(new WindowConfiguration());
mMockDisplayPolicy = mock(DisplayPolicy.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java b/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java
index 6e0056821aab..8b0a54050c3c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java
@@ -19,7 +19,6 @@ package com.android.server.wm;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRESENTATION;
import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
import static com.google.common.truth.Truth.assertThat;
@@ -90,8 +89,8 @@ public class PossibleDisplayInfoMapperTests extends WindowTestsBase {
mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
- // An entry for each possible rotation, for a display that can be in a single state.
- assertThat(displayInfos.size()).isEqualTo(4);
+ // An entry for rotation 0, for a display that can be in a single state.
+ assertThat(displayInfos.size()).isEqualTo(1);
assertPossibleDisplayInfoEntries(displayInfos, mDefaultDisplayInfo);
}
@@ -100,7 +99,7 @@ public class PossibleDisplayInfoMapperTests extends WindowTestsBase {
mPossibleDisplayInfo.add(mDefaultDisplayInfo);
mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
- assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY).size()).isEqualTo(4);
+ assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY).size()).isEqualTo(1);
// Add another display layout to the set of supported states.
mPossibleDisplayInfo.add(mSecondDisplayInfo);
@@ -116,12 +115,12 @@ public class PossibleDisplayInfoMapperTests extends WindowTestsBase {
defaultDisplayInfos.add(di);
}
}
- // An entry for each possible rotation, for the default display.
- assertThat(defaultDisplayInfos).hasSize(4);
+ // An entry for rotation 0, for the default display.
+ assertThat(defaultDisplayInfos).hasSize(1);
assertPossibleDisplayInfoEntries(defaultDisplayInfos, mDefaultDisplayInfo);
- // An entry for each possible rotation, for the second display.
- assertThat(secondDisplayInfos).hasSize(4);
+ // An entry for rotation 0, for the second display.
+ assertThat(secondDisplayInfos).hasSize(1);
assertPossibleDisplayInfoEntries(secondDisplayInfos, mSecondDisplayInfo);
}
@@ -130,7 +129,7 @@ public class PossibleDisplayInfoMapperTests extends WindowTestsBase {
mPossibleDisplayInfo.add(mDefaultDisplayInfo);
mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
- assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY).size()).isEqualTo(4);
+ assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY).size()).isEqualTo(1);
// Add another display to a different group.
mSecondDisplayInfo.displayId = DEFAULT_DISPLAY + 1;
@@ -139,14 +138,14 @@ public class PossibleDisplayInfoMapperTests extends WindowTestsBase {
mDisplayInfoMapper.updatePossibleDisplayInfos(mSecondDisplayInfo.displayId);
Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
- // An entry for each possible rotation, for the default display.
- assertThat(displayInfos).hasSize(4);
+ // An entry for rotation 0, for the default display.
+ assertThat(displayInfos).hasSize(1);
assertPossibleDisplayInfoEntries(displayInfos, mDefaultDisplayInfo);
Set<DisplayInfo> secondStateEntries =
mDisplayInfoMapper.getPossibleDisplayInfos(mSecondDisplayInfo.displayId);
- // An entry for each possible rotation, for the second display.
- assertThat(secondStateEntries).hasSize(4);
+ // An entry for rotation 0, for the second display.
+ assertThat(secondStateEntries).hasSize(1);
assertPossibleDisplayInfoEntries(secondStateEntries, mSecondDisplayInfo);
}
@@ -160,23 +159,10 @@ public class PossibleDisplayInfoMapperTests extends WindowTestsBase {
private static void assertPossibleDisplayInfoEntries(Set<DisplayInfo> displayInfos,
DisplayInfo expectedDisplayInfo) {
- boolean[] seenEveryRotation = new boolean[4];
for (DisplayInfo displayInfo : displayInfos) {
- final int rotation = displayInfo.rotation;
- seenEveryRotation[rotation] = true;
assertThat(displayInfo.displayId).isEqualTo(expectedDisplayInfo.displayId);
- assertEqualsRotatedDisplayInfo(displayInfo, expectedDisplayInfo);
- }
- assertThat(seenEveryRotation).isEqualTo(new boolean[]{true, true, true, true});
- }
-
- private static void assertEqualsRotatedDisplayInfo(DisplayInfo actual, DisplayInfo expected) {
- if (actual.rotation == ROTATION_0 || actual.rotation == ROTATION_180) {
- assertThat(actual.logicalWidth).isEqualTo(expected.logicalWidth);
- assertThat(actual.logicalHeight).isEqualTo(expected.logicalHeight);
- } else {
- assertThat(actual.logicalWidth).isEqualTo(expected.logicalHeight);
- assertThat(actual.logicalHeight).isEqualTo(expected.logicalWidth);
+ assertThat(displayInfo.logicalWidth).isEqualTo(expectedDisplayInfo.logicalWidth);
+ assertThat(displayInfo.logicalHeight).isEqualTo(expectedDisplayInfo.logicalHeight);
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index 80f6bceb884c..e5e0145095c1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -741,4 +741,35 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
assertEquals(isAssistantOnTop ? topPosition : topPosition - 4,
getTaskIndexOf(taskDisplayArea, assistRootTask));
}
+
+ /**
+ * This test verifies proper launch root based on source and candidate task for split screen.
+ * If a task is launching from a created-by-organizer task, it should be launched into the
+ * same created-by-organizer task as well. Unless, the candidate task is already positioned in
+ * the split.
+ */
+ @Test
+ public void getLaunchRootTaskInSplit() {
+ final Task rootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+ rootTask.mCreatedByOrganizer = true;
+ final Task adjacentRootTask = createTask(
+ mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+ adjacentRootTask.mCreatedByOrganizer = true;
+ final Task candidateTask = createTaskInRootTask(rootTask, 0 /* userId*/);
+ final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
+ adjacentRootTask.setAdjacentTaskFragment(rootTask, false /* moveTogether */);
+
+ // Verify the launch root with candidate task
+ Task actualRootTask = taskDisplayArea.getLaunchRootTask(WINDOWING_MODE_UNDEFINED,
+ ACTIVITY_TYPE_STANDARD, null /* options */, adjacentRootTask /* sourceTask */,
+ 0 /* launchFlags */, candidateTask);
+ assertSame(rootTask, actualRootTask.getRootTask());
+
+ // Verify the launch root task without candidate task
+ actualRootTask = taskDisplayArea.getLaunchRootTask(WINDOWING_MODE_UNDEFINED,
+ ACTIVITY_TYPE_STANDARD, null /* options */, adjacentRootTask /* sourceTask */,
+ 0 /* launchFlags */);
+ assertSame(adjacentRootTask, actualRootTask.getRootTask());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 4425962eb8eb..7a704742fba2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -522,6 +522,55 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
}
@Test
+ public void testApplyTransaction_requestFocusOnTaskFragment() {
+ mOrganizer.applyTransaction(mTransaction);
+ mController.registerOrganizer(mIOrganizer);
+ final Task task = createTask(mDisplayContent);
+ final IBinder token0 = new Binder();
+ final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(token0)
+ .setOrganizer(mOrganizer)
+ .createActivityCount(1)
+ .build();
+ final IBinder token1 = new Binder();
+ final TaskFragment tf1 = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(token1)
+ .setOrganizer(mOrganizer)
+ .createActivityCount(1)
+ .build();
+ mAtm.mWindowOrganizerController.mLaunchTaskFragments.put(token0, tf0);
+ mAtm.mWindowOrganizerController.mLaunchTaskFragments.put(token1, tf1);
+ final ActivityRecord activity0 = tf0.getTopMostActivity();
+ final ActivityRecord activity1 = tf1.getTopMostActivity();
+
+ // No effect if the current focus is in a different Task.
+ final ActivityRecord activityInOtherTask = createActivityRecord(mDefaultDisplay);
+ mDisplayContent.setFocusedApp(activityInOtherTask);
+ mTransaction.requestFocusOnTaskFragment(token0);
+ mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+
+ assertEquals(activityInOtherTask, mDisplayContent.mFocusedApp);
+
+ // No effect if there is no resumed activity in the request TaskFragment.
+ activity0.setState(ActivityRecord.State.PAUSED, "test");
+ activity1.setState(ActivityRecord.State.RESUMED, "test");
+ mDisplayContent.setFocusedApp(activity1);
+ mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+
+ assertEquals(activity1, mDisplayContent.mFocusedApp);
+
+ // Set focus to the request TaskFragment when the current focus is in the same Task, and it
+ // has a resumed activity.
+ activity0.setState(ActivityRecord.State.RESUMED, "test");
+ mDisplayContent.setFocusedApp(activity1);
+ mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+
+ assertEquals(activity0, mDisplayContent.mFocusedApp);
+ }
+
+ @Test
public void testTaskFragmentInPip_startActivityInTaskFragment() {
setupTaskFragmentInPip();
final ActivityRecord activity = mTaskFragment.getTopMostActivity();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 3c14777cd7d1..b2043c38d00a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -403,4 +403,29 @@ public class TaskFragmentTest extends WindowTestsBase {
assertFalse(activity0.hasOverlayOverUntrustedModeEmbedded());
assertFalse(activity1.hasOverlayOverUntrustedModeEmbedded());
}
+
+ @Test
+ public void testIsAllowedToBeEmbeddedInTrustedMode() {
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setCreateParentTask()
+ .createActivityCount(2)
+ .build();
+ final ActivityRecord activity0 = taskFragment.getBottomMostActivity();
+ final ActivityRecord activity1 = taskFragment.getTopMostActivity();
+
+ // Allowed if all children activities are allowed.
+ doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity0);
+ doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity1);
+
+ assertTrue(taskFragment.isAllowedToBeEmbeddedInTrustedMode());
+
+ // Disallowed if any child activity is not allowed.
+ doReturn(false).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity0);
+
+ assertFalse(taskFragment.isAllowedToBeEmbeddedInTrustedMode());
+
+ doReturn(false).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity1);
+
+ assertFalse(taskFragment.isAllowedToBeEmbeddedInTrustedMode());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index c672b9173570..9957d05d0a52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1156,10 +1156,6 @@ class WindowTestsBase extends SystemServiceTestsBase {
spyOn(activity);
if (mTask != null) {
- // fullscreen value is normally read from resources in ctor, so for testing we need
- // to set it somewhere else since we can't mock resources.
- doReturn(true).when(activity).occludesParent();
- doReturn(true).when(activity).fillsParent();
mTask.addChild(activity);
if (mOnTop) {
// Move the task to front after activity is added.
@@ -1294,6 +1290,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
private TaskFragment mParentTaskFragment;
private boolean mCreateActivity = false;
+ private boolean mCreatedByOrganizer = false;
TaskBuilder(ActivityTaskSupervisor supervisor) {
mSupervisor = supervisor;
@@ -1385,6 +1382,11 @@ class WindowTestsBase extends SystemServiceTestsBase {
return this;
}
+ TaskBuilder setCreatedByOrganizer(boolean createdByOrganizer) {
+ mCreatedByOrganizer = createdByOrganizer;
+ return this;
+ }
+
Task build() {
SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock);
@@ -1420,7 +1422,8 @@ class WindowTestsBase extends SystemServiceTestsBase {
.setActivityInfo(mActivityInfo)
.setIntent(mIntent)
.setOnTop(mOnTop)
- .setVoiceSession(mVoiceSession);
+ .setVoiceSession(mVoiceSession)
+ .setCreatedByOrganizer(mCreatedByOrganizer);
final Task task;
if (mParentTaskFragment == null) {
task = builder.setActivityType(mActivityType)
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 8cbbe947d32d..f31cdcba5830 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1824,6 +1824,32 @@ public class VoiceInteractionManagerService extends SystemService {
}
}
+ public void setSessionWindowVisible(IBinder token, boolean visible) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "setSessionWindowVisible called without running voice interaction "
+ + "service");
+ return;
+ }
+ if (mImpl.mActiveSession == null || token != mImpl.mActiveSession.mToken) {
+ Slog.w(TAG, "setSessionWindowVisible does not match active session");
+ return;
+ }
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mVoiceInteractionSessionListeners.broadcast(listener -> {
+ try {
+ listener.onVoiceSessionWindowVisibilityChanged(visible);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error delivering window visibility event to listener.", e);
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/telephony/java/Android.bp b/telephony/java/Android.bp
index 3941b300206f..76a420c430d1 100644
--- a/telephony/java/Android.bp
+++ b/telephony/java/Android.bp
@@ -13,6 +13,15 @@ filegroup {
srcs: [
"**/*.java",
"**/*.aidl",
+ ":statslog-telephony-java-gen",
],
visibility: ["//frameworks/base"],
}
+
+genrule {
+ name: "statslog-telephony-java-gen",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --java $(out) --module telephony" +
+ " --javaPackage com.android.internal.telephony --javaClass TelephonyStatsLog",
+ out: ["com/android/internal/telephony/TelephonyStatsLog.java"],
+}
diff --git a/telephony/java/android/telephony/AnomalyReporter.java b/telephony/java/android/telephony/AnomalyReporter.java
index ffdb23f98fb8..f47cf3384791 100644
--- a/telephony/java/android/telephony/AnomalyReporter.java
+++ b/telephony/java/android/telephony/AnomalyReporter.java
@@ -16,6 +16,8 @@
package android.telephony;
+import static com.android.internal.telephony.TelephonyStatsLog.TELEPHONY_ANOMALY_DETECTED;
+
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.content.Context;
@@ -24,6 +26,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.ParcelUuid;
+import com.android.internal.telephony.TelephonyStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.telephony.Rlog;
@@ -83,6 +86,12 @@ public final class AnomalyReporter {
return;
}
+ TelephonyStatsLog.write(
+ TELEPHONY_ANOMALY_DETECTED,
+ 0, // TODO: carrier id needs to be populated
+ eventId.getLeastSignificantBits(),
+ eventId.getMostSignificantBits());
+
// If this event has already occurred, skip sending intents for it; regardless log its
// invocation here.
Integer count = sEvents.containsKey(eventId) ? sEvents.get(eventId) + 1 : 1;
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index c56cc62abe44..235ed842b749 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1293,8 +1293,8 @@ public class ApnSetting implements Parcelable {
&& Objects.equals(this.mOperatorNumeric, other.mOperatorNumeric)
&& Objects.equals(this.mProtocol, other.mProtocol)
&& Objects.equals(this.mRoamingProtocol, other.mRoamingProtocol)
- && xorEqualsInt(this.mMtuV4, other.mMtuV4)
- && xorEqualsInt(this.mMtuV6, other.mMtuV6)
+ && mtuUnsetOrEquals(this.mMtuV4, other.mMtuV4)
+ && mtuUnsetOrEquals(this.mMtuV6, other.mMtuV6)
&& Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
&& Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask)
&& Objects.equals(this.mLingeringNetworkTypeBitmask,
@@ -1322,7 +1322,12 @@ public class ApnSetting implements Parcelable {
// Equal or one is not specified.
private boolean xorEqualsInt(int first, int second) {
return first == UNSPECIFIED_INT || second == UNSPECIFIED_INT
- || Objects.equals(first, second);
+ || first == second;
+ }
+
+ // Equal or one is not specified. Specific to MTU where <= 0 indicates unset.
+ private boolean mtuUnsetOrEquals(int first, int second) {
+ return first <= 0 || second <= 0 || first == second;
}
private String nullToEmpty(String stringValue) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
index 93b987ea8787..aacc17a49a24 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
@@ -16,6 +16,10 @@
package com.android.server.wm.flicker.helpers
+import android.view.WindowInsets.Type.ime
+import android.view.WindowInsets.Type.navigationBars
+import android.view.WindowInsets.Type.statusBars
+
import android.app.Instrumentation
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
@@ -25,6 +29,8 @@ import com.android.server.wm.traces.common.FlickerComponentName
import com.android.server.wm.traces.parser.toFlickerComponent
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import java.util.regex.Pattern
+
class ImeAppAutoFocusHelper @JvmOverloads constructor(
instr: Instrumentation,
private val rotation: Int,
@@ -72,6 +78,7 @@ class ImeAppAutoFocusHelper @JvmOverloads constructor(
wmHelper.waitForAppTransitionIdle()
wmHelper.waitForFullScreenApp(
ActivityOptions.DIALOG_THEMED_ACTIVITY_COMPONENT_NAME.toFlickerComponent())
+ mInstrumentation.waitForIdleSync()
}
fun dismissDialog(wmHelper: WindowManagerStateHelper) {
val dialog = uiDevice.wait(
@@ -83,4 +90,27 @@ class ImeAppAutoFocusHelper @JvmOverloads constructor(
wmHelper.waitForAppTransitionIdle()
}
}
+ fun getInsetsVisibleFromDialog(type: Int): Boolean {
+ var insetsVisibilityTextView = uiDevice.wait(
+ Until.findObject(By.res("android:id/text1")), FIND_TIMEOUT)
+ if (insetsVisibilityTextView != null) {
+ var visibility = insetsVisibilityTextView.text.toString()
+ val matcher = when (type) {
+ ime() -> {
+ Pattern.compile("IME\\: (VISIBLE|INVISIBLE)").matcher(visibility)
+ }
+ statusBars() -> {
+ Pattern.compile("StatusBar\\: (VISIBLE|INVISIBLE)").matcher(visibility)
+ }
+ navigationBars() -> {
+ Pattern.compile("NavBar\\: (VISIBLE|INVISIBLE)").matcher(visibility)
+ }
+ else -> null
+ }
+ if (matcher != null && matcher.find()) {
+ return matcher.group(1).equals("VISIBLE")
+ }
+ }
+ return false
+ }
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
index 1b60403ac354..2f8f9441a7b9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
@@ -16,6 +16,10 @@
package com.android.server.wm.flicker.ime
+import android.view.WindowInsets.Type.ime
+import android.view.WindowInsets.Type.navigationBars
+import android.view.WindowInsets.Type.statusBars
+
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
import android.view.Surface
@@ -35,6 +39,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
/**
* Test IME snapshot mechanism won't apply when transitioning from non-IME focused dialog activity.
@@ -56,6 +62,10 @@ class LaunchAppShowImeAndDialogThemeAppTest(private val testSpec: FlickerTestPar
testApp.launchViaIntent(wmHelper)
wmHelper.waitImeShown()
testApp.startDialogThemedActivity(wmHelper)
+ // Verify IME insets isn't visible on dialog since it's non-IME focusable window
+ assertFalse(testApp.getInsetsVisibleFromDialog(ime()))
+ assertTrue(testApp.getInsetsVisibleFromDialog(statusBars()))
+ assertTrue(testApp.getInsetsVisibleFromDialog(navigationBars()))
}
}
teardown {
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/DialogThemedActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/DialogThemedActivity.java
index 27606d81f9d3..20eb295d3e6b 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/DialogThemedActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/DialogThemedActivity.java
@@ -17,11 +17,16 @@
package com.android.server.wm.flicker.testapp;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.navigationBars;
+import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.graphics.Color;
import android.os.Bundle;
import android.view.WindowManager;
@@ -33,9 +38,12 @@ public class DialogThemedActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
+ getWindow().addFlags(FLAG_NOT_FOCUSABLE);
getWindow().getDecorView().setBackgroundColor(Color.TRANSPARENT);
TextView textView = new TextView(this);
- textView.setText("This is a test dialog");
+ // Print SystemBars' insets visibility on this window for demonstrating during the test.
+ textView.setId(android.R.id.text1);
+ textView.setText("Insets visibility\n\n");
textView.setTextColor(Color.BLACK);
LinearLayout layout = new LinearLayout(this);
layout.setBackgroundColor(Color.GREEN);
@@ -51,7 +59,17 @@ public class DialogThemedActivity extends Activity {
attrs.flags = FLAG_DIM_BEHIND | FLAG_ALT_FOCUSABLE_IM;
dialog.getWindow().getDecorView().setLayoutParams(attrs);
dialog.setCanceledOnTouchOutside(true);
+ dialog.setOnShowListener(d -> textView.setText(textView.getText()
+ + "IME: " + isInsetsVisible(dialog, ime()) + "\n"
+ + "StatusBar: " + isInsetsVisible(dialog, statusBars()) + "\n"
+ + "NavBar: " + isInsetsVisible(dialog, navigationBars()) + "\n")
+ );
dialog.show();
dialog.setOnDismissListener((d) -> finish());
}
+
+ private String isInsetsVisible(Dialog d, int type) {
+ return d.getWindow().getDecorView().getRootWindowInsets().isVisible(type) ? "VISIBLE"
+ : "INVISIBLE";
+ }
}
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java
index 90fd08bae4ef..47f87d6d75ff 100644
--- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java
@@ -95,6 +95,8 @@ public final class NotificationTest {
PackageManager pm = mContext.getPackageManager();
// Do not run on Automotive.
assumeFalse(pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
+ // Do not run on TV. Direct Reply isn't supported on TV.
+ assumeFalse(pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY));
}
@After