summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobStore.java15
-rw-r--r--core/api/module-lib-current.txt24
-rw-r--r--core/api/test-current.txt20
-rw-r--r--core/java/android/app/ActivityThread.java15
-rw-r--r--core/java/android/app/Notification.java41
-rw-r--r--core/java/android/app/NotificationManager.java6
-rw-r--r--core/java/android/companion/AssociationInfo.java257
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java96
-rw-r--r--core/java/android/companion/ICompanionDeviceManager.aidl5
-rw-r--r--core/java/android/content/BroadcastReceiver.java2
-rw-r--r--core/java/android/content/Context.java8
-rw-r--r--core/java/android/content/pm/PackageInstaller.java4
-rw-r--r--core/java/android/content/pm/PackageManager.java18
-rw-r--r--core/java/android/content/pm/PackageParser.java32
-rw-r--r--core/java/android/content/pm/TEST_MAPPING28
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java4
-rw-r--r--core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java41
-rw-r--r--core/java/android/content/res/Resources.java36
-rw-r--r--core/java/android/content/res/ThemedResourceCache.java28
-rw-r--r--core/java/android/credentials/ui/BaseDialogResult.java7
-rw-r--r--core/java/android/credentials/ui/UserSelectionDialogResult.java4
-rw-r--r--core/java/android/database/DatabaseUtils.java32
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java3
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java19
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java18
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java18
-rw-r--r--core/java/android/hardware/camera2/package.html28
-rw-r--r--core/java/android/hardware/camera2/params/ColorSpaceProfiles.java4
-rw-r--r--core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java14
-rw-r--r--core/java/android/hardware/camera2/params/SessionConfiguration.java7
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java30
-rw-r--r--core/java/android/hardware/display/DisplayManager.java9
-rw-r--r--core/java/android/hardware/usb/UsbConfiguration.java3
-rw-r--r--core/java/android/net/Uri.java36
-rw-r--r--core/java/android/os/UserManager.java2
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java12
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java19
-rw-r--r--core/java/android/view/InsetsController.java65
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java9
-rw-r--r--core/java/android/view/WindowManager.java220
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java22
-rw-r--r--core/java/android/widget/ScrollView.java2
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java56
-rw-r--r--core/java/com/android/internal/dynamicanimation/animation/DynamicAnimation.java2
-rw-r--r--core/java/com/android/internal/dynamicanimation/animation/SpringForce.java2
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java2
-rw-r--r--core/jni/android_view_InputDevice.cpp11
-rw-r--r--core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp12
-rw-r--r--core/jni/com_android_internal_os_LongMultiStateCounter.cpp12
-rw-r--r--core/res/AndroidManifest.xml6
-rw-r--r--core/res/res/values/attrs.xml14
-rw-r--r--core/res/res/values/attrs_manifest.xml24
-rw-r--r--core/res/res/values/config.xml21
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt6
-rw-r--r--core/tests/coretests/src/android/net/UriTest.java116
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java29
-rw-r--r--core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java12
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java40
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java39
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java55
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java50
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java31
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java3
-rw-r--r--libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt10
-rw-r--r--libs/hwui/jni/BitmapRegionDecoder.cpp35
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp4
-rw-r--r--media/java/android/media/MediaRoute2Info.java38
-rw-r--r--media/java/android/media/session/MediaSession.java23
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt19
-rw-r--r--packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt2
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt14
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/AnimatedNavHost.kt47
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavGraphBuilder.kt55
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt50
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt1
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt3
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt2
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt2
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt2
-rw-r--r--packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java17
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java56
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java16
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java5
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java35
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java23
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java35
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--packages/StatementService/src/com/android/statementservice/utils/StatementUtils.kt1
-rw-r--r--packages/SystemUI/TEST_MAPPING6
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt17
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt12
-rw-r--r--packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java10
-rw-r--r--packages/SystemUI/res-product/values/strings.xml38
-rw-r--r--packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml2
-rw-r--r--packages/SystemUI/res/layout/activity_rear_display_education.xml2
-rw-r--r--packages/SystemUI/res/layout/activity_rear_display_education_opened.xml2
-rw-r--r--packages/SystemUI/res/layout/auth_biometric_contents.xml2
-rw-r--r--packages/SystemUI/res/layout/biometric_prompt_layout.xml4
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml3
-rw-r--r--packages/SystemUI/res/layout/media_output_list_item_advanced.xml1
-rw-r--r--packages/SystemUI/res/layout/sidefps_view.xml2
-rw-r--r--packages/SystemUI/res/layout/udfps_keyguard_preview.xml2
-rw-r--r--packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml1
-rw-r--r--packages/SystemUI/res/values/strings.xml12
-rw-r--r--packages/SystemUI/res/xml/large_screen_shade_header.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java7
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java11
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricPromptLottieViewWrapper.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt50
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java140
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/UdfpsLottieViewWrapper.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserFactory.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayEducationLottieViewWrapper.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt70
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/wrapper/LottieViewWrapper.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java69
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt81
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java99
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt61
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java59
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt48
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java19
-rw-r--r--services/autofill/java/com/android/server/autofill/Helper.java43
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java12
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/FillUi.java11
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java3
-rw-r--r--services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java4
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java24
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java13
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java2
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java2
-rw-r--r--services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java3
-rw-r--r--services/companion/java/com/android/server/companion/transport/Transport.java12
-rw-r--r--services/core/java/com/android/server/PendingIntentUtils.java1
-rw-r--r--services/core/java/com/android/server/SystemConfig.java16
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java5
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java23
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java4
-rw-r--r--services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java4
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerService.java7
-rw-r--r--services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java50
-rw-r--r--services/core/java/com/android/server/dreams/DreamController.java32
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java4
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java132
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java8
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java41
-rw-r--r--services/core/java/com/android/server/media/projection/mediaprojection.md5
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java46
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecordLogger.java62
-rw-r--r--services/core/java/com/android/server/pm/DexOptHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java77
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java39
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceInjector.java10
-rw-r--r--services/core/java/com/android/server/pm/RemovePackageHelper.java1
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING6
-rw-r--r--services/core/java/com/android/server/pm/UpdateOwnershipHelper.java185
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java5
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java6
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java41
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java2
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java52
-rw-r--r--services/core/java/com/android/server/power/stats/BatteryStatsImpl.java10
-rw-r--r--services/core/java/com/android/server/utils/AlarmQueue.java7
-rw-r--r--services/core/java/com/android/server/utils/quota/CountQuotaTracker.java2
-rw-r--r--services/core/java/com/android/server/vr/VrManagerService.java6
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java19
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java17
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java32
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java7
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java2
-rw-r--r--services/core/java/com/android/server/wm/Dimmer.java15
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java2
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java35
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/SafeActivityOptions.java13
-rw-r--r--services/core/java/com/android/server/wm/Transition.java26
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java37
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java17
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java11
-rw-r--r--services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java11
-rw-r--r--services/permission/java/com/android/server/permission/access/permission/PermissionService.kt2
-rw-r--r--services/print/java/com/android/server/print/PrintManagerService.java35
-rw-r--r--services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt2
-rw-r--r--services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6bin16856 -> 16852 bytes
-rw-r--r--services/tests/PackageManagerServiceTests/server/res/raw/install_app2_cert5_rotated_cert6bin16856 -> 16852 bytes
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt8
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java58
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java203
-rw-r--r--services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java4
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java144
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java23
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java35
-rw-r--r--services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java47
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DimmerTests.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java10
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaDevice.java12
-rw-r--r--tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java5
-rw-r--r--tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt2
-rw-r--r--tests/Internal/src/android/service/wallpaper/OWNERS4
-rw-r--r--tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java13
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt60
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt6
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt2
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt2
311 files changed, 4854 insertions, 1724 deletions
diff --git a/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt b/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt
index 9482591c65b5..aadbc2319a62 100644
--- a/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt
+++ b/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt
@@ -130,7 +130,7 @@ class MotionPredictorBenchmark {
eventTime, ACTION_MOVE, /*x=*/eventPosition, /*y=*/eventPosition)
predictor.record(moveEvent)
val predictionTime = eventTime + eventInterval
- val predicted = predictor.predict(predictionTime.toNanos())
+ val predicted = checkNotNull(predictor.predict(predictionTime.toNanos()))
assertTrue(predicted.eventTime <= (predictionTime + offset).toMillis())
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 0a7bffc786cc..4b4e51290abd 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -1118,6 +1118,7 @@ public final class JobStore {
}
boolean needFileMigration = false;
long nowElapsed = sElapsedRealtimeClock.millis();
+ int numDuplicates = 0;
synchronized (mLock) {
for (File file : files) {
final AtomicFile aFile = createJobFile(file);
@@ -1126,6 +1127,16 @@ public final class JobStore {
if (jobs != null) {
for (int i = 0; i < jobs.size(); i++) {
JobStatus js = jobs.get(i);
+ final JobStatus existingJob = this.jobSet.get(
+ js.getUid(), js.getNamespace(), js.getJobId());
+ if (existingJob != null) {
+ numDuplicates++;
+ // Jobs are meant to have unique uid-namespace-jobId
+ // combinations, but we've somehow read multiple jobs with the
+ // combination. Drop the latter one since keeping both will
+ // result in other issues.
+ continue;
+ }
js.prepareLocked();
js.enqueueTime = nowElapsed;
this.jobSet.add(js);
@@ -1174,6 +1185,10 @@ public final class JobStore {
migrateJobFilesAsync();
}
+ if (numDuplicates > 0) {
+ Slog.wtf(TAG, "Encountered " + numDuplicates + " duplicate persisted jobs");
+ }
+
// Log the count immediately after loading from boot.
mCurrentJobSetSize = numJobs;
mScheduledJob30MinHighWaterMark = mCurrentJobSetSize;
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 7cfa1e377933..b1feb419ecde 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -6,6 +6,7 @@ package android {
field public static final String CONTROL_AUTOMOTIVE_GNSS = "android.permission.CONTROL_AUTOMOTIVE_GNSS";
field public static final String GET_INTENT_SENDER_INTENT = "android.permission.GET_INTENT_SENDER_INTENT";
field public static final String MAKE_UID_VISIBLE = "android.permission.MAKE_UID_VISIBLE";
+ field public static final String USE_COMPANION_TRANSPORTS = "android.permission.USE_COMPANION_TRANSPORTS";
}
}
@@ -81,6 +82,29 @@ package android.app.admin {
}
+package android.companion {
+
+ public final class CompanionDeviceManager {
+ method @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void addOnMessageReceivedListener(@NonNull java.util.concurrent.Executor, int, @NonNull android.companion.CompanionDeviceManager.OnMessageReceivedListener);
+ method @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void addOnTransportsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.OnTransportsChangedListener);
+ method @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void removeOnMessageReceivedListener(int, @NonNull android.companion.CompanionDeviceManager.OnMessageReceivedListener);
+ method @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void removeOnTransportsChangedListener(@NonNull android.companion.CompanionDeviceManager.OnTransportsChangedListener);
+ method @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void sendMessage(int, @NonNull byte[], @NonNull int[]);
+ field public static final int MESSAGE_REQUEST_CONTEXT_SYNC = 1667729539; // 0x63678883
+ field public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 1669491075; // 0x63826983
+ field public static final int MESSAGE_REQUEST_REMOTE_AUTHENTICATION = 1669494629; // 0x63827765
+ }
+
+ public static interface CompanionDeviceManager.OnMessageReceivedListener {
+ method public void onMessageReceived(int, @NonNull byte[]);
+ }
+
+ public static interface CompanionDeviceManager.OnTransportsChangedListener {
+ method public void onTransportsChanged(@NonNull java.util.List<android.companion.AssociationInfo>);
+ }
+
+}
+
package android.content {
public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 70377ab6a0d9..54633c05b6bc 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -836,6 +836,26 @@ package android.appwidget {
package android.companion {
+ public static final class AssociationInfo.Builder {
+ ctor public AssociationInfo.Builder(int, int, @NonNull String);
+ ctor public AssociationInfo.Builder(@NonNull android.companion.AssociationInfo);
+ method @NonNull public android.companion.AssociationInfo build();
+ method @NonNull public android.companion.AssociationInfo.Builder setAssociatedDevice(@Nullable android.companion.AssociatedDevice);
+ method @NonNull public android.companion.AssociationInfo.Builder setDeviceMacAddress(@Nullable android.net.MacAddress);
+ method @NonNull public android.companion.AssociationInfo.Builder setDeviceProfile(@Nullable String);
+ method @NonNull public android.companion.AssociationInfo.Builder setDisplayName(@Nullable CharSequence);
+ method @NonNull public android.companion.AssociationInfo.Builder setLastTimeConnected(long);
+ method @NonNull public android.companion.AssociationInfo.Builder setNotifyOnDeviceNearby(boolean);
+ method @NonNull public android.companion.AssociationInfo.Builder setRevoked(boolean);
+ method @NonNull public android.companion.AssociationInfo.Builder setSelfManaged(boolean);
+ method @NonNull public android.companion.AssociationInfo.Builder setSystemDataSyncFlags(int);
+ method @NonNull public android.companion.AssociationInfo.Builder setTimeApproved(long);
+ }
+
+ public final class CompanionDeviceManager {
+ field public static final int MESSAGE_REQUEST_PING = 1669362552; // 0x63807378
+ }
+
public abstract class CompanionDeviceService extends android.app.Service {
method public void onBindCompanionDeviceService(@NonNull android.content.Intent);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e4db1b734daf..ba26457b9f8a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4226,21 +4226,22 @@ public final class ActivityThread extends ClientTransactionHandler
decorView.addView(view);
view.requestLayout();
- view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
+ view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
private boolean mHandled = false;
@Override
- public void onDraw() {
+ public boolean onPreDraw() {
if (mHandled) {
- return;
+ return true;
}
mHandled = true;
// Transfer the splash screen view from shell to client.
- // Call syncTransferSplashscreenViewTransaction at the first onDraw so we can ensure
- // the client view is ready to show and we can use applyTransactionOnDraw to make
- // all transitions happen at the same frame.
+ // Call syncTransferSplashscreenViewTransaction at the first onPreDraw, so we can
+ // ensure the client view is ready to show, and can use applyTransactionOnDraw to
+ // make all transitions happen at the same frame.
syncTransferSplashscreenViewTransaction(
view, r.token, decorView, startingWindowLeash);
- view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this));
+ view.post(() -> view.getViewTreeObserver().removeOnPreDrawListener(this));
+ return true;
}
});
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2eb6ca758970..77b0e913496b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2171,6 +2171,10 @@ public class Notification implements Parcelable
}
}
+ private void visitUris(@NonNull Consumer<Uri> visitor) {
+ visitIconUri(visitor, getIcon());
+ }
+
@Override
public Action clone() {
return new Action(
@@ -2856,7 +2860,7 @@ public class Notification implements Parcelable
if (actions != null) {
for (Action action : actions) {
- visitIconUri(visitor, action.getIcon());
+ action.visitUris(visitor);
}
}
@@ -2886,11 +2890,6 @@ public class Notification implements Parcelable
}
}
- final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
- if (person != null) {
- visitor.accept(person.getIconUri());
- }
-
final RemoteInputHistoryItem[] history = extras.getParcelableArray(
Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
RemoteInputHistoryItem.class);
@@ -2902,9 +2901,14 @@ public class Notification implements Parcelable
}
}
}
- }
- if (isStyle(MessagingStyle.class) && extras != null) {
+ // Extras for MessagingStyle. We visit them even if not isStyle(MessagingStyle), since
+ // Notification Listeners might use directly (without the isStyle check).
+ final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
+ if (person != null) {
+ visitor.accept(person.getIconUri());
+ }
+
final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES,
Parcelable.class);
if (!ArrayUtils.isEmpty(messages)) {
@@ -2934,9 +2938,8 @@ public class Notification implements Parcelable
}
visitIconUri(visitor, extras.getParcelable(EXTRA_CONVERSATION_ICON, Icon.class));
- }
- if (isStyle(CallStyle.class) & extras != null) {
+ // Extras for CallStyle (same reason for visiting without checking isStyle).
Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class);
if (callPerson != null) {
visitor.accept(callPerson.getIconUri());
@@ -2947,6 +2950,11 @@ public class Notification implements Parcelable
if (mBubbleMetadata != null) {
visitIconUri(visitor, mBubbleMetadata.getIcon());
}
+
+ if (extras != null && extras.containsKey(WearableExtender.EXTRA_WEARABLE_EXTENSIONS)) {
+ WearableExtender extender = new WearableExtender(this);
+ extender.visitUris(visitor);
+ }
}
/**
@@ -3476,8 +3484,11 @@ public class Notification implements Parcelable
*
* @hide
*/
- public void setAllowlistToken(@Nullable IBinder token) {
- mAllowlistToken = token;
+ public void clearAllowlistToken() {
+ mAllowlistToken = null;
+ if (publicVersion != null) {
+ publicVersion.clearAllowlistToken();
+ }
}
/**
@@ -11711,6 +11722,12 @@ public class Notification implements Parcelable
mFlags &= ~mask;
}
}
+
+ private void visitUris(@NonNull Consumer<Uri> visitor) {
+ for (Action action : mActions) {
+ action.visitUris(visitor);
+ }
+ }
}
/**
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 785470f2f22e..79b68c1456c7 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -571,6 +571,12 @@ public class NotificationManager {
*/
public static final int BUBBLE_PREFERENCE_SELECTED = 2;
+ /**
+ * Maximum length of the component name of a registered NotificationListenerService.
+ * @hide
+ */
+ public static int MAX_SERVICE_COMPONENT_NAME_LENGTH = 500;
+
@UnsupportedAppUsage
private static INotificationManager sService;
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index 0958a806a5ff..c62675023e0b 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -17,7 +17,9 @@ package android.companion;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.net.MacAddress;
import android.os.Parcel;
@@ -41,23 +43,24 @@ public final class AssociationInfo implements Parcelable {
private static final String LAST_TIME_CONNECTED_NONE = "None";
/**
* A unique ID of this Association record.
- * Disclosed to the clients (ie. companion applications) for referring to this record (eg. in
+ * Disclosed to the clients (i.e. companion applications) for referring to this record (e.g. in
* {@code disassociate()} API call).
*/
private final int mId;
-
- private final @UserIdInt int mUserId;
- private final @NonNull String mPackageName;
-
- private final @Nullable MacAddress mDeviceMacAddress;
- private final @Nullable CharSequence mDisplayName;
- private final @Nullable String mDeviceProfile;
- private final @Nullable AssociatedDevice mAssociatedDevice;
-
+ @UserIdInt
+ private final int mUserId;
+ @NonNull
+ private final String mPackageName;
+ @Nullable
+ private final MacAddress mDeviceMacAddress;
+ @Nullable
+ private final CharSequence mDisplayName;
+ @Nullable
+ private final String mDeviceProfile;
+ @Nullable
+ private final AssociatedDevice mAssociatedDevice;
private final boolean mSelfManaged;
private final boolean mNotifyOnDeviceNearby;
- private final int mSystemDataSyncFlags;
-
/**
* Indicates that the association has been revoked (removed), but we keep the association
* record for final clean up (e.g. removing the app from the list of the role holders).
@@ -71,6 +74,7 @@ public final class AssociationInfo implements Parcelable {
* Default value is Long.MAX_VALUE.
*/
private final long mLastTimeConnectedMs;
+ private final int mSystemDataSyncFlags;
/**
* Creates a new Association.
@@ -80,8 +84,8 @@ public final class AssociationInfo implements Parcelable {
public AssociationInfo(int id, @UserIdInt int userId, @NonNull String packageName,
@Nullable MacAddress macAddress, @Nullable CharSequence displayName,
@Nullable String deviceProfile, @Nullable AssociatedDevice associatedDevice,
- boolean selfManaged, boolean notifyOnDeviceNearby, boolean revoked,
- long timeApprovedMs, long lastTimeConnectedMs, int systemDataSyncFlags) {
+ boolean selfManaged, boolean notifyOnDeviceNearby, boolean revoked, long timeApprovedMs,
+ long lastTimeConnectedMs, int systemDataSyncFlags) {
if (id <= 0) {
throw new IllegalArgumentException("Association ID should be greater than 0");
}
@@ -91,15 +95,12 @@ public final class AssociationInfo implements Parcelable {
}
mId = id;
-
mUserId = userId;
mPackageName = packageName;
-
mDeviceMacAddress = macAddress;
mDisplayName = displayName;
mDeviceProfile = deviceProfile;
mAssociatedDevice = associatedDevice;
-
mSelfManaged = selfManaged;
mNotifyOnDeviceNearby = notifyOnDeviceNearby;
mRevoked = revoked;
@@ -119,7 +120,8 @@ public final class AssociationInfo implements Parcelable {
* @return the ID of the user who "owns" this association.
* @hide
*/
- public @UserIdInt int getUserId() {
+ @UserIdInt
+ public int getUserId() {
return mUserId;
}
@@ -128,19 +130,22 @@ public final class AssociationInfo implements Parcelable {
* @hide
*/
@SystemApi
- public @NonNull String getPackageName() {
+ @NonNull
+ public String getPackageName() {
return mPackageName;
}
/**
* @return the MAC address of the device.
*/
- public @Nullable MacAddress getDeviceMacAddress() {
+ @Nullable
+ public MacAddress getDeviceMacAddress() {
return mDeviceMacAddress;
}
/** @hide */
- public @Nullable String getDeviceMacAddressAsString() {
+ @Nullable
+ public String getDeviceMacAddressAsString() {
return mDeviceMacAddress != null ? mDeviceMacAddress.toString().toUpperCase() : null;
}
@@ -150,7 +155,8 @@ public final class AssociationInfo implements Parcelable {
*
* @see AssociationRequest.Builder#setDisplayName(CharSequence)
*/
- public @Nullable CharSequence getDisplayName() {
+ @Nullable
+ public CharSequence getDisplayName() {
return mDisplayName;
}
@@ -159,7 +165,8 @@ public final class AssociationInfo implements Parcelable {
* association, or {@code null} if no specific profile was used.
* @see AssociationRequest.Builder#setDeviceProfile(String)
*/
- public @Nullable String getDeviceProfile() {
+ @Nullable
+ public String getDeviceProfile() {
return mDeviceProfile;
}
@@ -176,7 +183,8 @@ public final class AssociationInfo implements Parcelable {
* @return the companion device that was associated, or {@code null} if the device is
* self-managed or this association info was retrieved from persistent storage.
*/
- public @Nullable AssociatedDevice getAssociatedDevice() {
+ @Nullable
+ public AssociatedDevice getAssociatedDevice() {
return mAssociatedDevice;
}
@@ -217,14 +225,14 @@ public final class AssociationInfo implements Parcelable {
* @return the last time self reported disconnected for selfManaged only.
* @hide
*/
- public Long getLastTimeConnectedMs() {
+ public long getLastTimeConnectedMs() {
return mLastTimeConnectedMs;
}
/**
* @return Enabled system data sync flags set via
- * {@link CompanionDeviceManager#enableSystemDataSync(int, int)} and
- * {@link CompanionDeviceManager#disableSystemDataSync(int, int)}.
+ * {@link CompanionDeviceManager#enableSystemDataSyncForTypes(int, int)} (int, int)} and
+ * {@link CompanionDeviceManager#disableSystemDataSyncForTypes(int, int)} (int, int)}.
* Or by default all flags are 1 (enabled).
*/
public int getSystemDataSyncFlags() {
@@ -268,7 +276,8 @@ public final class AssociationInfo implements Parcelable {
}
/** @hide */
- public @NonNull String toShortString() {
+ @NonNull
+ public String toShortString() {
final StringBuilder sb = new StringBuilder();
sb.append("id=").append(mId);
if (mDeviceMacAddress != null) {
@@ -337,15 +346,12 @@ public final class AssociationInfo implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mId);
-
dest.writeInt(mUserId);
dest.writeString(mPackageName);
-
dest.writeTypedObject(mDeviceMacAddress, 0);
dest.writeCharSequence(mDisplayName);
dest.writeString(mDeviceProfile);
dest.writeTypedObject(mAssociatedDevice, 0);
-
dest.writeBoolean(mSelfManaged);
dest.writeBoolean(mNotifyOnDeviceNearby);
dest.writeBoolean(mRevoked);
@@ -356,15 +362,12 @@ public final class AssociationInfo implements Parcelable {
private AssociationInfo(@NonNull Parcel in) {
mId = in.readInt();
-
mUserId = in.readInt();
mPackageName = in.readString();
-
mDeviceMacAddress = in.readTypedObject(MacAddress.CREATOR);
mDisplayName = in.readCharSequence();
mDeviceProfile = in.readString();
mAssociatedDevice = in.readTypedObject(AssociatedDevice.CREATOR);
-
mSelfManaged = in.readBoolean();
mNotifyOnDeviceNearby = in.readBoolean();
mRevoked = in.readBoolean();
@@ -388,71 +391,139 @@ public final class AssociationInfo implements Parcelable {
};
/**
- * Use this method to obtain a builder that you can use to create a copy of the
- * given {@link AssociationInfo} with modified values of {@code mLastTimeConnected}
- * or {@code mNotifyOnDeviceNearby}.
- * <p>
- * Note that you <b>must</b> call either {@link Builder#setLastTimeConnected(long)
- * setLastTimeConnected} or {@link Builder#setNotifyOnDeviceNearby(boolean)
- * setNotifyOnDeviceNearby} before you will be able to call {@link Builder#build() build}.
- *
- * This is ensured statically at compile time.
+ * Builder for {@link AssociationInfo}
*
* @hide
*/
- @NonNull
- public static NonActionableBuilder builder(@NonNull AssociationInfo info) {
- return new Builder(info);
- }
-
- /** @hide */
- public static final class Builder implements NonActionableBuilder {
- @NonNull
- private final AssociationInfo mOriginalInfo;
+ @TestApi
+ public static final class Builder {
+ private final int mId;
+ private final int mUserId;
+ private final String mPackageName;
+ private MacAddress mDeviceMacAddress;
+ private CharSequence mDisplayName;
+ private String mDeviceProfile;
+ private AssociatedDevice mAssociatedDevice;
+ private boolean mSelfManaged;
private boolean mNotifyOnDeviceNearby;
private boolean mRevoked;
+ private long mTimeApprovedMs;
private long mLastTimeConnectedMs;
private int mSystemDataSyncFlags;
- private Builder(@NonNull AssociationInfo info) {
- mOriginalInfo = info;
+ /** @hide */
+ @TestApi
+ public Builder(int id, int userId, @NonNull String packageName) {
+ mId = id;
+ mUserId = userId;
+ mPackageName = packageName;
+ }
+
+ /** @hide */
+ @TestApi
+ public Builder(@NonNull AssociationInfo info) {
+ mId = info.mId;
+ mUserId = info.mUserId;
+ mPackageName = info.mPackageName;
+ mDeviceMacAddress = info.mDeviceMacAddress;
+ mDisplayName = info.mDisplayName;
+ mDeviceProfile = info.mDeviceProfile;
+ mAssociatedDevice = info.mAssociatedDevice;
+ mSelfManaged = info.mSelfManaged;
mNotifyOnDeviceNearby = info.mNotifyOnDeviceNearby;
mRevoked = info.mRevoked;
+ mTimeApprovedMs = info.mTimeApprovedMs;
mLastTimeConnectedMs = info.mLastTimeConnectedMs;
mSystemDataSyncFlags = info.mSystemDataSyncFlags;
}
/** @hide */
- @Override
+ @TestApi
@NonNull
- public Builder setLastTimeConnected(long lastTimeConnectedMs) {
- if (lastTimeConnectedMs < 0) {
- throw new IllegalArgumentException(
- "lastTimeConnectedMs must not be negative! (Given " + lastTimeConnectedMs
- + " )");
- }
- mLastTimeConnectedMs = lastTimeConnectedMs;
+ public Builder setDeviceMacAddress(@Nullable MacAddress deviceMacAddress) {
+ mDeviceMacAddress = deviceMacAddress;
return this;
}
/** @hide */
- @Override
+ @TestApi
@NonNull
+ public Builder setDisplayName(@Nullable CharSequence displayName) {
+ mDisplayName = displayName;
+ return this;
+ }
+
+ /** @hide */
+ @TestApi
+ @NonNull
+ public Builder setDeviceProfile(@Nullable String deviceProfile) {
+ mDeviceProfile = deviceProfile;
+ return this;
+ }
+
+ /** @hide */
+ @TestApi
+ @NonNull
+ public Builder setAssociatedDevice(@Nullable AssociatedDevice associatedDevice) {
+ mAssociatedDevice = associatedDevice;
+ return this;
+ }
+
+ /** @hide */
+ @TestApi
+ @NonNull
+ public Builder setSelfManaged(boolean selfManaged) {
+ mSelfManaged = selfManaged;
+ return this;
+ }
+
+ /** @hide */
+ @TestApi
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
public Builder setNotifyOnDeviceNearby(boolean notifyOnDeviceNearby) {
mNotifyOnDeviceNearby = notifyOnDeviceNearby;
return this;
}
/** @hide */
- @Override
+ @TestApi
@NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
public Builder setRevoked(boolean revoked) {
mRevoked = revoked;
return this;
}
/** @hide */
- @Override
+ @TestApi
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setTimeApproved(long timeApprovedMs) {
+ if (timeApprovedMs < 0) {
+ throw new IllegalArgumentException("timeApprovedMs must be positive. Was given ("
+ + timeApprovedMs + ")");
+ }
+ mTimeApprovedMs = timeApprovedMs;
+ return this;
+ }
+
+ /** @hide */
+ @TestApi
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setLastTimeConnected(long lastTimeConnectedMs) {
+ if (lastTimeConnectedMs < 0) {
+ throw new IllegalArgumentException(
+ "lastTimeConnectedMs must not be negative! (Given " + lastTimeConnectedMs
+ + " )");
+ }
+ mLastTimeConnectedMs = lastTimeConnectedMs;
+ return this;
+ }
+
+ /** @hide */
+ @TestApi
@NonNull
public Builder setSystemDataSyncFlags(int flags) {
mSystemDataSyncFlags = flags;
@@ -460,53 +531,31 @@ public final class AssociationInfo implements Parcelable {
}
/** @hide */
+ @TestApi
@NonNull
public AssociationInfo build() {
+ if (mId <= 0) {
+ throw new IllegalArgumentException("Association ID should be greater than 0");
+ }
+ if (mDeviceMacAddress == null && mDisplayName == null) {
+ throw new IllegalArgumentException("MAC address and the display name must NOT be "
+ + "null at the same time");
+ }
return new AssociationInfo(
- mOriginalInfo.mId,
- mOriginalInfo.mUserId,
- mOriginalInfo.mPackageName,
- mOriginalInfo.mDeviceMacAddress,
- mOriginalInfo.mDisplayName,
- mOriginalInfo.mDeviceProfile,
- mOriginalInfo.mAssociatedDevice,
- mOriginalInfo.mSelfManaged,
+ mId,
+ mUserId,
+ mPackageName,
+ mDeviceMacAddress,
+ mDisplayName,
+ mDeviceProfile,
+ mAssociatedDevice,
+ mSelfManaged,
mNotifyOnDeviceNearby,
mRevoked,
- mOriginalInfo.mTimeApprovedMs,
+ mTimeApprovedMs,
mLastTimeConnectedMs,
mSystemDataSyncFlags
);
}
}
-
- /**
- * This interface is returned from the
- * {@link AssociationInfo#builder(android.companion.AssociationInfo) builder} entry point
- * to indicate that this builder is not yet in a state that can produce a meaningful
- * {@link AssociationInfo} object that is different from the one originally passed in.
- *
- * <p>
- * Only by calling one of the setter methods is this builder turned into one where calling
- * {@link Builder#build() build()} makes sense.
- *
- * @hide
- */
- public interface NonActionableBuilder {
- /** @hide */
- @NonNull
- Builder setNotifyOnDeviceNearby(boolean notifyOnDeviceNearby);
-
- /** @hide */
- @NonNull
- Builder setLastTimeConnected(long lastTimeConnectedMs);
-
- /** @hide */
- @NonNull
- Builder setRevoked(boolean revoked);
-
- /** @hide */
- @NonNull
- Builder setSystemDataSyncFlags(int flags);
- }
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index 4dea4a7e3aca..c77c3c48dde4 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -20,7 +20,9 @@ import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMIN
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER;
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,6 +30,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.annotation.UserHandleAware;
import android.app.Activity;
import android.app.ActivityManager;
@@ -216,6 +219,34 @@ public final class CompanionDeviceManager {
"com.android.companiondevicemanager";
/**
+ * Test message type without a designated callback.
+ *
+ * @hide
+ */
+ @TestApi public static final int MESSAGE_REQUEST_PING = 0x63807378; // ?PIN
+ /**
+ * Message header assigned to the remote authentication handshakes.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int MESSAGE_REQUEST_REMOTE_AUTHENTICATION = 0x63827765; // ?RMA
+ /**
+ * Message header assigned to the telecom context sync metadata.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int MESSAGE_REQUEST_CONTEXT_SYNC = 0x63678883; // ?CXS
+ /**
+ * Message header assigned to the permission restore request.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
+
+ /**
* Callback for applications to receive updates about and the outcome of
* {@link AssociationRequest} issued via {@code associate()} call.
*
@@ -804,28 +835,36 @@ public final class CompanionDeviceManager {
}
/**
- * Listener for any changes to {@link com.android.server.companion.transport.Transport}.
+ * Listener for any changes to the list of attached transports.
+ *
+ * @see com.android.server.companion.transport.Transport
*
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public interface OnTransportsChangedListener {
/**
- * Invoked when a change occurs to any of the transports
+ * Invoked when a transport is attached or detached.
*
- * @param associations all the associations which have connected transports
+ * @param associations all the associations which have connected transports.
*/
void onTransportsChanged(@NonNull List<AssociationInfo> associations);
}
/**
- * Register a listener for any changes to
- * {@link com.android.server.companion.transport.Transport}. Your app will receive a callback to
- * {@link OnTransportsChangedListener} immediately with all the existing transports.
+ * Adds a listener for any changes to the list of attached transports.
+ * {@link OnTransportsChangedListener#onTransportsChanged(List)} will be triggered with a list
+ * of existing transports when a transport is detached or a new transport is attached.
+ *
+ * @see com.android.server.companion.transport.Transport
*
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void addOnTransportsChangedListener(
- @NonNull Executor executor, @NonNull OnTransportsChangedListener listener) {
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnTransportsChangedListener listener) {
final OnTransportsChangedListenerProxy proxy = new OnTransportsChangedListenerProxy(
executor, listener);
try {
@@ -836,11 +875,14 @@ public final class CompanionDeviceManager {
}
/**
- * Unregister a listener to stop receiving any changes to
- * {@link com.android.server.companion.transport.Transport}.
+ * Removes the registered listener for any changes to the list of attached transports.
+ *
+ * @see com.android.server.companion.transport.Transport
*
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void removeOnTransportsChangedListener(
@NonNull OnTransportsChangedListener listener) {
final OnTransportsChangedListenerProxy proxy = new OnTransportsChangedListenerProxy(
@@ -853,11 +895,16 @@ public final class CompanionDeviceManager {
}
/**
- * Send a message to remote devices
+ * Sends a message to associated remote devices. The target associations must already have a
+ * connected transport.
+ *
+ * @see #attachSystemDataTransport(int, InputStream, OutputStream)
*
* @hide
*/
- public void sendMessage(int messageType, byte[] data, int[] associationIds) {
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
+ public void sendMessage(int messageType, @NonNull byte[] data, @NonNull int[] associationIds) {
try {
mService.sendMessage(messageType, data, associationIds);
} catch (RemoteException e) {
@@ -866,28 +913,30 @@ public final class CompanionDeviceManager {
}
/**
- * Listener when a message is received for the registered message type
+ * Listener that triggers a callback when a message is received through a connected transport.
*
* @see #addOnMessageReceivedListener(Executor, int, OnMessageReceivedListener)
*
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public interface OnMessageReceivedListener {
/**
- * Called when a message is received
+ * Called when a message is received.
*/
- void onMessageReceived(int associationId, byte[] data);
+ void onMessageReceived(int associationId, @NonNull byte[] data);
}
/**
- * Register a listener to receive callbacks when a message is received by the given type
- *
- * @see com.android.server.companion.transport.Transport for supported message types
+ * Adds a listener to trigger callbacks when messages of given type are received.
*
* @hide
*/
- public void addOnMessageReceivedListener(@NonNull Executor executor, int messageType,
- OnMessageReceivedListener listener) {
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
+ public void addOnMessageReceivedListener(
+ @NonNull @CallbackExecutor Executor executor, int messageType,
+ @NonNull OnMessageReceivedListener listener) {
final OnMessageReceivedListenerProxy proxy = new OnMessageReceivedListenerProxy(
executor, listener);
try {
@@ -898,15 +947,14 @@ public final class CompanionDeviceManager {
}
/**
- * Unregister a listener to stop receiving callbacks when a message is received by the given
- * type
- *
- * @see com.android.server.companion.transport.Transport for supported message types
+ * Removes the registered listener for received messages of given type.
*
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void removeOnMessageReceivedListener(int messageType,
- OnMessageReceivedListener listener) {
+ @NonNull OnMessageReceivedListener listener) {
final OnMessageReceivedListenerProxy proxy = new OnMessageReceivedListenerProxy(
null, listener);
try {
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index b5e2670e5299..1e95fb3fa532 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -69,14 +69,19 @@ interface ICompanionDeviceManager {
void removeOnAssociationsChangedListener(IOnAssociationsChangedListener listener, int userId);
+ @EnforcePermission("USE_COMPANION_TRANSPORTS")
void addOnTransportsChangedListener(IOnTransportsChangedListener listener);
+ @EnforcePermission("USE_COMPANION_TRANSPORTS")
void removeOnTransportsChangedListener(IOnTransportsChangedListener listener);
+ @EnforcePermission("USE_COMPANION_TRANSPORTS")
void sendMessage(int messageType, in byte[] data, in int[] associationIds);
+ @EnforcePermission("USE_COMPANION_TRANSPORTS")
void addOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener);
+ @EnforcePermission("USE_COMPANION_TRANSPORTS")
void removeOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener);
void notifyDeviceAppeared(int associationId);
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 3d76b28a3ccc..d7195a76d873 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -65,7 +65,7 @@ public abstract class BroadcastReceiver {
* thread of your app.
*
* <p>Note on threading: the state inside of this class is not itself
- * thread-safe, however you can use it from any thread if you properly
+ * thread-safe. However, you can use it from any thread if you make
* sure that you do not have races. Typically this means you will hand
* the entire object to another thread, which will be solely responsible
* for setting any results and finally calling {@link #finish()}.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d7dcb8881ce4..4e241617cc6e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -683,7 +683,7 @@ public abstract class Context {
public static final int BIND_EXTERNAL_SERVICE = 0x80000000;
/**
- * Works in the same way as {@link #BIND_EXTERNAL_SERVICE}, but it's defined as a (@code long)
+ * Works in the same way as {@link #BIND_EXTERNAL_SERVICE}, but it's defined as a {@code long}
* value that is compatible to {@link BindServiceFlags}.
*/
public static final long BIND_EXTERNAL_SERVICE_LONG = 1L << 62;
@@ -1413,7 +1413,7 @@ public abstract class Context {
* </ul>
* <p>
* If a shared storage device is emulated (as determined by
- * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+ * {@link Environment#isExternalStorageEmulated(File)}), its contents are
* backed by a private user data partition, which means there is little
* benefit to storing data here instead of the private directories returned
* by {@link #getFilesDir()}, etc.
@@ -1501,7 +1501,7 @@ public abstract class Context {
* </ul>
* <p>
* If a shared storage device is emulated (as determined by
- * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+ * {@link Environment#isExternalStorageEmulated(File)}), its contents are
* backed by a private user data partition, which means there is little
* benefit to storing data here instead of the private directories returned
* by {@link #getFilesDir()}, etc.
@@ -1812,7 +1812,7 @@ public abstract class Context {
* </ul>
* <p>
* If a shared storage device is emulated (as determined by
- * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+ * {@link Environment#isExternalStorageEmulated(File)}), its contents are
* backed by a private user data partition, which means there is little
* benefit to storing data here instead of the private directory returned by
* {@link #getCacheDir()}.
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index ef26235a3879..082ede2641ea 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -3049,10 +3049,6 @@ public class PackageInstaller {
* The update ownership enforcement can only be enabled on initial installation. Set
* this to {@code true} on package update is a no-op.
*
- * Apps may opt themselves out of update ownership by setting the
- * <a href="https://developer.android.com/guide/topics/manifest/manifest-element.html#allowupdateownership">android:alllowUpdateOwnership</a>
- * attribute in their manifest to <code>false</code>.
- *
* Note: To enable the update ownership enforcement, the installer must have the
* {@link android.Manifest.permission#ENFORCE_UPDATE_OWNERSHIP ENFORCE_UPDATE_OWNERSHIP}
* permission.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0f020fa3c402..02650c65e1a4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -234,6 +234,24 @@ public abstract class PackageManager {
"android.camera.PROPERTY_COMPAT_OVERRIDE_LANDSCAPE_TO_PORTRAIT";
/**
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager
+ * .Property} for a privileged system installer to define a list of up to 500 packages that
+ * should not have their updates owned by any installer. The list must be provided via a default
+ * XML resource with the following format:
+ *
+ * <pre>
+ * &lt;deny-ownership&gt;PACKAGE_NAME&lt;/deny-ownership&gt;
+ * &lt;deny-ownership&gt;PACKAGE_NAME&lt;/deny-ownership&gt;
+ * </pre>
+ *
+ * <b>NOTE:</b> Installers that provide this property will not granted update ownership for any
+ * packages that they request update ownership of.
+ * @hide
+ */
+ public static final String PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST =
+ "android.app.PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST";
+
+ /**
* A property value set within the manifest.
* <p>
* The value of a property will only have a single type, as defined by
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 18611d8867ef..048289f56a0c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1949,8 +1949,6 @@ public class PackageParser {
int type;
boolean foundApp = false;
- String pkgName = (pkg != null) ? pkg.packageName : "<unknown>";
-
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
@@ -2220,14 +2218,14 @@ public class PackageParser {
sa.recycle();
final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode,
- SDK_VERSION, SDK_CODENAMES, outError, pkgName);
+ SDK_VERSION, SDK_CODENAMES, outError);
if (minSdkVersion < 0) {
mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
return null;
}
final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers,
- targetCode, SDK_CODENAMES, outError, pkgName);
+ targetCode, SDK_CODENAMES, outError);
if (targetSdkVersion < 0) {
mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
return null;
@@ -2612,15 +2610,13 @@ public class PackageParser {
* @param platformSdkCodenames array of allowed pre-release SDK codenames
* for this platform
* @param outError output array to populate with error, if applicable
- * @param pkgName for debug logging
* @return the targetSdkVersion to use at runtime, or -1 if the package is
* not compatible with this platform
* @hide Exposed for unit testing only.
*/
public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
@Nullable String targetCode, @NonNull String[] platformSdkCodenames,
- @NonNull String[] outError,
- String pkgName) {
+ @NonNull String[] outError) {
// If it's a release SDK, return the version number unmodified.
if (targetCode == null) {
return targetVers;
@@ -2632,15 +2628,6 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
- // TODO(b/294161396): add a check for a "true REL" flag.
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- targetCode)) {
- Slog.w(TAG, "Package " + pkgName + " requires development platform " + targetCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return Build.VERSION.SDK_INT;
- }
-
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + targetCode
@@ -2687,15 +2674,13 @@ public class PackageParser {
* @param platformSdkCodenames array of allowed prerelease SDK codenames
* for this platform
* @param outError output array to populate with error, if applicable
- * @param pkgName for debug logging
* @return the minSdkVersion to use at runtime, or -1 if the package is not
* compatible with this platform
* @hide Exposed for unit testing only.
*/
public static int computeMinSdkVersion(@IntRange(from = 1) int minVers,
@Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
- @NonNull String[] platformSdkCodenames, @NonNull String[] outError,
- String pkgName) {
+ @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
// If it's a release SDK, make sure we meet the minimum SDK requirement.
if (minCode == null) {
if (minVers <= platformSdkVersion) {
@@ -2714,15 +2699,6 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
- // TODO(b/294161396): add a check for a "true REL" flag.
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- minCode)) {
- Slog.w(TAG, "Package " + pkgName + " requires min development platform " + minCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return Build.VERSION.SDK_INT;
- }
-
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 3ffbe1d1c71b..2ea6513c4d77 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -101,20 +101,6 @@
],
"presubmit-large":[
{
- "name":"CtsContentTestCases",
- "options":[
- {
- "exclude-annotation":"androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation":"org.junit.Ignore"
- },
- {
- "include-filter":"android.content.pm.cts"
- }
- ]
- },
- {
"name":"CtsUsesNativeLibraryTest",
"options":[
{
@@ -156,6 +142,20 @@
],
"postsubmit":[
{
+ "name":"CtsContentTestCases",
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ },
+ {
+ "include-filter":"android.content.pm.cts"
+ }
+ ]
+ },
+ {
"name":"CtsAppSecurityHostTestCases",
"options":[
{
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index dcb1b7eb8320..4f6bcb6f0be5 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -578,14 +578,14 @@ public class ApkLiteParseUtils {
ParseResult<Integer> targetResult = FrameworkParsingPackageUtils.computeTargetSdkVersion(
targetVer, targetCode, SDK_CODENAMES, input,
- allowUnknownCodenames, codePath);
+ allowUnknownCodenames);
if (targetResult.isError()) {
return input.error(targetResult);
}
targetSdkVersion = targetResult.getResult();
ParseResult<Integer> minResult = FrameworkParsingPackageUtils.computeMinSdkVersion(
- minVer, minCode, SDK_VERSION, SDK_CODENAMES, input, codePath);
+ minVer, minCode, SDK_VERSION, SDK_CODENAMES, input);
if (minResult.isError()) {
return input.error(minResult);
}
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 30e289f62698..3e1c5bb3d7ec 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -293,14 +293,11 @@ public class FrameworkParsingPackageUtils {
* {@code null} otherwise
* @param platformSdkVersion platform SDK version number, typically Build.VERSION.SDK_INT
* @param platformSdkCodenames array of allowed prerelease SDK codenames for this platform
- * @param input parsing context
- * @param pkgName for debug logging
* @return the minSdkVersion to use at runtime if successful
*/
public static ParseResult<Integer> computeMinSdkVersion(@IntRange(from = 1) int minVers,
@Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
- @NonNull String[] platformSdkCodenames, @NonNull ParseInput input,
- String pkgName) {
+ @NonNull String[] platformSdkCodenames, @NonNull ParseInput input) {
// If it's a release SDK, make sure we meet the minimum SDK requirement.
if (minCode == null) {
if (minVers <= platformSdkVersion) {
@@ -319,15 +316,6 @@ public class FrameworkParsingPackageUtils {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
- // TODO(b/294161396): add a check for a "true REL" flag.
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- minCode)) {
- Slog.w(TAG, "Parsed package " + pkgName + " requires min development platform "
- + minCode + ", returning current version " + Build.VERSION.SDK_INT);
- return input.success(Build.VERSION.SDK_INT);
- }
-
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -370,38 +358,29 @@ public class FrameworkParsingPackageUtils {
* @param platformSdkCodenames array of allowed pre-release SDK codenames for this platform
* @param allowUnknownCodenames allow unknown codenames, if true this method will accept unknown
* (presumed to be future) codenames
- * @param pkgName for debug logging
* @return the targetSdkVersion to use at runtime if successful
*/
public static ParseResult<Integer> computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
@Nullable String targetCode, @NonNull String[] platformSdkCodenames,
- @NonNull ParseInput input, boolean allowUnknownCodenames,
- String pkgName) {
+ @NonNull ParseInput input, boolean allowUnknownCodenames) {
// If it's a release SDK, return the version number unmodified.
if (targetCode == null) {
return input.success(targetVers);
}
- // TODO(b/294161396): add a check for a "true REL" flag.
- // If it's a pre-release SDK and the codename matches this platform, it
- // definitely targets this SDK.
- if (matchTargetCode(platformSdkCodenames, targetCode)) {
- return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
- }
- if (platformSdkCodenames.length == 0
- && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
- targetCode)) {
- Slog.w(TAG, "Parsed package " + pkgName + " requires development platform " + targetCode
- + ", returning current version " + Build.VERSION.SDK_INT);
- return input.success(Build.VERSION.SDK_INT);
- }
-
try {
if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
} catch (IllegalArgumentException e) {
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
+ // isAtMost() throws it when encountering an older SDK codename
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, e.getMessage());
+ }
+
+ // If it's a pre-release SDK and the codename matches this platform, it
+ // definitely targets this SDK.
+ if (matchTargetCode(platformSdkCodenames, targetCode)) {
+ return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
// Otherwise, we're looking at an incompatible pre-release SDK.
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 7d72f2459e15..ed22284ae23d 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2009,13 +2009,25 @@ public class Resources {
private int mHashCode = 0;
- private boolean containsValue(int resId, boolean force) {
+ private int findValue(int resId, boolean force) {
for (int i = 0; i < mCount; ++i) {
if (mResId[i] == resId && mForce[i] == force) {
- return true;
+ return i;
}
}
- return false;
+ return -1;
+ }
+
+ private void moveToLast(int index) {
+ if (index < 0 || index >= mCount - 1) {
+ return;
+ }
+ final int id = mResId[index];
+ final boolean force = mForce[index];
+ System.arraycopy(mResId, index + 1, mResId, index, mCount - index - 1);
+ mResId[mCount - 1] = id;
+ System.arraycopy(mForce, index + 1, mForce, index, mCount - index - 1);
+ mForce[mCount - 1] = force;
}
public void append(int resId, boolean force) {
@@ -2028,15 +2040,17 @@ public class Resources {
}
// Some apps tend to keep adding same resources over and over, let's protect from it.
- if (containsValue(resId, force)) {
- return;
+ // Note: the order still matters, as the values that come later override the earlier
+ // ones.
+ final int index = findValue(resId, force);
+ if (index >= 0) {
+ moveToLast(index);
+ } else {
+ mResId = GrowingArrayUtils.append(mResId, mCount, resId);
+ mForce = GrowingArrayUtils.append(mForce, mCount, force);
+ mCount++;
+ mHashCode = 31 * (31 * mHashCode + resId) + (force ? 1 : 0);
}
-
- mResId = GrowingArrayUtils.append(mResId, mCount, resId);
- mForce = GrowingArrayUtils.append(mForce, mCount, force);
- mCount++;
-
- mHashCode = 31 * (31 * mHashCode + resId) + (force ? 1 : 0);
}
/**
diff --git a/core/java/android/content/res/ThemedResourceCache.java b/core/java/android/content/res/ThemedResourceCache.java
index a7cd168690b4..690dfcf9619b 100644
--- a/core/java/android/content/res/ThemedResourceCache.java
+++ b/core/java/android/content/res/ThemedResourceCache.java
@@ -137,8 +137,10 @@ abstract class ThemedResourceCache<T> {
*/
@UnsupportedAppUsage
public void onConfigurationChange(@Config int configChanges) {
- prune(configChanges);
- mGeneration++;
+ synchronized (this) {
+ pruneLocked(configChanges);
+ mGeneration++;
+ }
}
/**
@@ -214,22 +216,20 @@ abstract class ThemedResourceCache<T> {
* simply prune missing weak references
* @return {@code true} if the cache is completely empty after pruning
*/
- private boolean prune(@Config int configChanges) {
- synchronized (this) {
- if (mThemedEntries != null) {
- for (int i = mThemedEntries.size() - 1; i >= 0; i--) {
- if (pruneEntriesLocked(mThemedEntries.valueAt(i), configChanges)) {
- mThemedEntries.removeAt(i);
- }
+ private boolean pruneLocked(@Config int configChanges) {
+ if (mThemedEntries != null) {
+ for (int i = mThemedEntries.size() - 1; i >= 0; i--) {
+ if (pruneEntriesLocked(mThemedEntries.valueAt(i), configChanges)) {
+ mThemedEntries.removeAt(i);
}
}
+ }
- pruneEntriesLocked(mNullThemedEntries, configChanges);
- pruneEntriesLocked(mUnthemedEntries, configChanges);
+ pruneEntriesLocked(mNullThemedEntries, configChanges);
+ pruneEntriesLocked(mUnthemedEntries, configChanges);
- return mThemedEntries == null && mNullThemedEntries == null
- && mUnthemedEntries == null;
- }
+ return mThemedEntries == null && mNullThemedEntries == null
+ && mUnthemedEntries == null;
}
private boolean pruneEntriesLocked(@Nullable LongSparseArray<WeakReference<T>> entries,
diff --git a/core/java/android/credentials/ui/BaseDialogResult.java b/core/java/android/credentials/ui/BaseDialogResult.java
index f0442de74e9e..e8cf5abd5239 100644
--- a/core/java/android/credentials/ui/BaseDialogResult.java
+++ b/core/java/android/credentials/ui/BaseDialogResult.java
@@ -85,15 +85,15 @@ public class BaseDialogResult implements Parcelable {
*/
public static final int RESULT_CODE_DATA_PARSING_FAILURE = 3;
- @NonNull
+ @Nullable
private final IBinder mRequestToken;
- public BaseDialogResult(@NonNull IBinder requestToken) {
+ public BaseDialogResult(@Nullable IBinder requestToken) {
mRequestToken = requestToken;
}
/** Returns the unique identifier for the request that launched the operation. */
- @NonNull
+ @Nullable
public IBinder getRequestToken() {
return mRequestToken;
}
@@ -101,7 +101,6 @@ public class BaseDialogResult implements Parcelable {
protected BaseDialogResult(@NonNull Parcel in) {
IBinder requestToken = in.readStrongBinder();
mRequestToken = requestToken;
- AnnotationValidations.validate(NonNull.class, null, mRequestToken);
}
@Override
diff --git a/core/java/android/credentials/ui/UserSelectionDialogResult.java b/core/java/android/credentials/ui/UserSelectionDialogResult.java
index 44b3b36844c2..3089bf674b95 100644
--- a/core/java/android/credentials/ui/UserSelectionDialogResult.java
+++ b/core/java/android/credentials/ui/UserSelectionDialogResult.java
@@ -60,7 +60,7 @@ public final class UserSelectionDialogResult extends BaseDialogResult implements
@Nullable private ProviderPendingIntentResponse mProviderPendingIntentResponse;
public UserSelectionDialogResult(
- @NonNull IBinder requestToken, @NonNull String providerId,
+ @Nullable IBinder requestToken, @NonNull String providerId,
@NonNull String entryKey, @NonNull String entrySubkey) {
super(requestToken);
mProviderId = providerId;
@@ -69,7 +69,7 @@ public final class UserSelectionDialogResult extends BaseDialogResult implements
}
public UserSelectionDialogResult(
- @NonNull IBinder requestToken, @NonNull String providerId,
+ @Nullable IBinder requestToken, @NonNull String providerId,
@NonNull String entryKey, @NonNull String entrySubkey,
@Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
super(requestToken);
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 6c8a8500e4e3..d41df4f49d48 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -511,17 +511,31 @@ public class DatabaseUtils {
*/
public static void appendEscapedSQLString(StringBuilder sb, String sqlString) {
sb.append('\'');
- if (sqlString.indexOf('\'') != -1) {
- int length = sqlString.length();
- for (int i = 0; i < length; i++) {
- char c = sqlString.charAt(i);
- if (c == '\'') {
- sb.append('\'');
+ int length = sqlString.length();
+ for (int i = 0; i < length; i++) {
+ char c = sqlString.charAt(i);
+ if (Character.isHighSurrogate(c)) {
+ if (i == length - 1) {
+ continue;
+ }
+ if (Character.isLowSurrogate(sqlString.charAt(i + 1))) {
+ // add them both
+ sb.append(c);
+ sb.append(sqlString.charAt(i + 1));
+ continue;
+ } else {
+ // this is a lone surrogate, skip it
+ continue;
}
- sb.append(c);
}
- } else
- sb.append(sqlString);
+ if (Character.isLowSurrogate(c)) {
+ continue;
+ }
+ if (c == '\'') {
+ sb.append('\'');
+ }
+ sb.append(c);
+ }
sb.append('\'');
}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 65fc1c62a471..082a3361be4e 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -283,7 +283,8 @@ public abstract class CameraDevice implements AutoCloseable {
* @see StreamConfigurationMap#getInputFormats
* @see StreamConfigurationMap#getInputSizes
* @see StreamConfigurationMap#getValidOutputFormatsForInput
- * @see StreamConfigurationMap#getOutputSizes
+ * @see StreamConfigurationMap#getOutputSizes(int)
+ * @see StreamConfigurationMap#getOutputSizes(Class)
* @see android.media.ImageWriter
* @see android.media.ImageReader
* @deprecated Please use {@link
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 51501b558fba..2a120d2043f0 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -129,14 +129,17 @@ public final class CameraManager {
/**
* Enable physical camera availability callbacks when the logical camera is unavailable
*
- * <p>Previously once a logical camera becomes unavailable, no {@link
- * #onPhysicalCameraAvailable} or {@link #onPhysicalCameraUnavailable} will be called until
- * the logical camera becomes available again. The results in the app opening the logical
- * camera not able to receive physical camera availability change.</p>
- *
- * <p>With this change, the {@link #onPhysicalCameraAvailable} and {@link
- * #onPhysicalCameraUnavailable} can still be called while the logical camera is unavailable.
- * </p>
+ * <p>Previously once a logical camera becomes unavailable, no
+ * {@link AvailabilityCallback#onPhysicalCameraAvailable} or
+ * {@link AvailabilityCallback#onPhysicalCameraUnavailable} will
+ * be called until the logical camera becomes available again. The
+ * results in the app opening the logical camera not able to
+ * receive physical camera availability change.</p>
+ *
+ * <p>With this change, the {@link
+ * AvailabilityCallback#onPhysicalCameraAvailable} and {@link
+ * AvailabilityCallback#onPhysicalCameraUnavailable} can still be
+ * called while the logical camera is unavailable. </p>
*/
@ChangeId
@EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 3a660812fd24..59408191cdf5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -3535,7 +3535,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_DEFAULT } mode.
* They can be queried through
* {@link android.hardware.camera2.CameraCharacteristics#get } with
- * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION) }.
+ * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION }.
* Unless reported by both
* {@link android.hardware.camera2.params.StreamConfigurationMap }s, the outputs from
* <code>{@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION android.scaler.streamConfigurationMapMaximumResolution}</code> and
@@ -3550,13 +3550,12 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <ul>
* <li>
* <p>The mandatory stream combinations listed in
- * {@link android.hardware.camera2.CameraCharacteristics.mandatoryMaximumResolutionStreamCombinations }
- * would not apply.</p>
+ * {@link CameraCharacteristics#SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS android.scaler.mandatoryMaximumResolutionStreamCombinations} would not apply.</p>
* </li>
* <li>
* <p>The bayer pattern of {@code RAW} streams when
* {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION }
- * is selected will be the one listed in {@link android.sensor.info.binningFactor }.</p>
+ * is selected will be the one listed in {@link CameraCharacteristics#SENSOR_INFO_BINNING_FACTOR android.sensor.info.binningFactor}.</p>
* </li>
* <li>
* <p>The following keys will always be present:</p>
@@ -3576,9 +3575,11 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
*
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
+ * @see CameraCharacteristics#SENSOR_INFO_BINNING_FACTOR
* @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see #SENSOR_PIXEL_MODE_DEFAULT
@@ -4193,9 +4194,8 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* <p>This control allows Camera extension clients to configure the strength of the applied
* extension effect. Strength equal to 0 means that the extension must not apply any
* post-processing and return a regular captured frame. Strength equal to 100 is the
- * default level of post-processing applied when the control is not supported or not set
- * by the client. Values between 0 and 100 will have different effect depending on the
- * extension type as described below:</p>
+ * maximum level of post-processing. Values between 0 and 100 will have different effect
+ * depending on the extension type as described below:</p>
* <ul>
* <li>{@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_BOKEH BOKEH} -
* the strength is expected to control the amount of blur.</li>
@@ -4210,7 +4210,9 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* {@link android.hardware.camera2.CameraExtensionCharacteristics#getAvailableCaptureRequestKeys }.
* The control is only defined and available to clients sending capture requests via
* {@link android.hardware.camera2.CameraExtensionSession }.
- * The default value is 100.</p>
+ * If the client doesn't specify the extension strength value, then a default value will
+ * be set by the extension. Clients can retrieve the default value by checking the
+ * corresponding capture result.</p>
* <p><b>Range of valid values:</b><br>
* 0 - 100</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 1536376e4eb5..905f98de75ff 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -4460,7 +4460,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_DEFAULT } mode.
* They can be queried through
* {@link android.hardware.camera2.CameraCharacteristics#get } with
- * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION) }.
+ * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION }.
* Unless reported by both
* {@link android.hardware.camera2.params.StreamConfigurationMap }s, the outputs from
* <code>{@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION android.scaler.streamConfigurationMapMaximumResolution}</code> and
@@ -4475,13 +4475,12 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <ul>
* <li>
* <p>The mandatory stream combinations listed in
- * {@link android.hardware.camera2.CameraCharacteristics.mandatoryMaximumResolutionStreamCombinations }
- * would not apply.</p>
+ * {@link CameraCharacteristics#SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS android.scaler.mandatoryMaximumResolutionStreamCombinations} would not apply.</p>
* </li>
* <li>
* <p>The bayer pattern of {@code RAW} streams when
* {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION }
- * is selected will be the one listed in {@link android.sensor.info.binningFactor }.</p>
+ * is selected will be the one listed in {@link CameraCharacteristics#SENSOR_INFO_BINNING_FACTOR android.sensor.info.binningFactor}.</p>
* </li>
* <li>
* <p>The following keys will always be present:</p>
@@ -4501,9 +4500,11 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
*
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
+ * @see CameraCharacteristics#SENSOR_INFO_BINNING_FACTOR
* @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
* @see #SENSOR_PIXEL_MODE_DEFAULT
@@ -5693,9 +5694,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* <p>This control allows Camera extension clients to configure the strength of the applied
* extension effect. Strength equal to 0 means that the extension must not apply any
* post-processing and return a regular captured frame. Strength equal to 100 is the
- * default level of post-processing applied when the control is not supported or not set
- * by the client. Values between 0 and 100 will have different effect depending on the
- * extension type as described below:</p>
+ * maximum level of post-processing. Values between 0 and 100 will have different effect
+ * depending on the extension type as described below:</p>
* <ul>
* <li>{@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_BOKEH BOKEH} -
* the strength is expected to control the amount of blur.</li>
@@ -5710,7 +5710,9 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* {@link android.hardware.camera2.CameraExtensionCharacteristics#getAvailableCaptureRequestKeys }.
* The control is only defined and available to clients sending capture requests via
* {@link android.hardware.camera2.CameraExtensionSession }.
- * The default value is 100.</p>
+ * If the client doesn't specify the extension strength value, then a default value will
+ * be set by the extension. Clients can retrieve the default value by checking the
+ * corresponding capture result.</p>
* <p><b>Range of valid values:</b><br>
* 0 - 100</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/package.html b/core/java/android/hardware/camera2/package.html
index 719c2f620234..3fd5d7c60832 100644
--- a/core/java/android/hardware/camera2/package.html
+++ b/core/java/android/hardware/camera2/package.html
@@ -62,12 +62,28 @@ RAW buffers for {@link android.hardware.camera2.DngCreator} can be
done with {@link android.media.ImageReader} with the {@link
android.graphics.ImageFormat#JPEG} and {@link
android.graphics.ImageFormat#RAW_SENSOR} formats. Application-driven
-processing of camera data in RenderScript, OpenGL ES, or directly in
-managed or native code is best done through {@link
-android.renderscript.Allocation} with a YUV {@link
-android.renderscript.Type}, {@link android.graphics.SurfaceTexture},
-and {@link android.media.ImageReader} with a {@link
-android.graphics.ImageFormat#YUV_420_888} format, respectively.</p>
+processing of camera data in OpenGL ES, or directly in managed or
+native code is best done through {@link
+android.graphics.SurfaceTexture}, or {@link android.media.ImageReader}
+with a {@link android.graphics.ImageFormat#YUV_420_888} format,
+respectively. </p>
+
+<p>By default, YUV-format buffers provided by the camera are using the
+JFIF YUV<->RGB transform matrix (equivalent to Rec.601 full-range
+encoding), and after conversion to RGB with this matrix, the resulting
+RGB data is in the sRGB colorspace. Captured JPEG images may contain
+an ICC profile to specify their color space information; if not, they
+should be assumed to be in the sRGB space as well. On some devices,
+the output colorspace can be changed via {@link
+android.hardware.camera2.params.SessionConfiguration#setColorSpace}.
+</p>
+<p>
+Note that although the YUV->RGB transform is the JFIF matrix (Rec.601
+full-range), due to legacy and compatibility reasons, the output is in
+the sRGB colorspace, which uses the Rec.709 color primaries. Image
+processing code can safely treat the output RGB as being in the sRGB
+colorspace.
+</p>
<p>The application then needs to construct a {@link
android.hardware.camera2.CaptureRequest}, which defines all the
diff --git a/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java b/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java
index 2e3af80f9cc0..bb154a96cbe9 100644
--- a/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java
+++ b/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java
@@ -192,7 +192,7 @@ public final class ColorSpaceProfiles {
* @see OutputConfiguration#setDynamicRangeProfile
* @see SessionConfiguration#setColorSpace
* @see ColorSpace.Named
- * @see DynamicRangeProfiles.Profile
+ * @see DynamicRangeProfiles
*/
public @NonNull Set<Long> getSupportedDynamicRangeProfiles(@NonNull ColorSpace.Named colorSpace,
@ImageFormat.Format int imageFormat) {
@@ -230,7 +230,7 @@ public final class ColorSpaceProfiles {
* @see SessionConfiguration#setColorSpace
* @see OutputConfiguration#setDynamicRangeProfile
* @see ColorSpace.Named
- * @see DynamicRangeProfiles.Profile
+ * @see DynamicRangeProfiles
*/
public @NonNull Set<ColorSpace.Named> getSupportedColorSpacesForDynamicRange(
@ImageFormat.Format int imageFormat,
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
index 80db38fc9d8f..d4ce0ebbc528 100644
--- a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
@@ -45,7 +45,7 @@ import java.util.Set;
* Immutable class to store the recommended stream configurations to set up
* {@link android.view.Surface Surfaces} for creating a
* {@link android.hardware.camera2.CameraCaptureSession capture session} with
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession(SessionConfiguration)}.
*
* <p>The recommended list does not replace or deprecate the exhaustive complete list found in
* {@link StreamConfigurationMap}. It is a suggestion about available power and performance
@@ -70,7 +70,7 @@ import java.util.Set;
* }</code></pre>
*
* @see CameraCharacteristics#getRecommendedStreamConfigurationMap
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
*/
public final class RecommendedStreamConfigurationMap {
@@ -282,7 +282,7 @@ public final class RecommendedStreamConfigurationMap {
/**
* Determine whether or not output surfaces with a particular user-defined format can be passed
- * {@link CameraDevice#createCaptureSession createCaptureSession}.
+ * {@link CameraDevice#createCaptureSession(SessionConfiguration) createCaptureSession}.
*
* <p>
* For further information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
@@ -292,7 +292,7 @@ public final class RecommendedStreamConfigurationMap {
* @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
* @return
* {@code true} if using a {@code surface} with this {@code format} will be
- * supported with {@link CameraDevice#createCaptureSession}
+ * supported with {@link CameraDevice#createCaptureSession(SessionConfiguration)}
*
* @throws IllegalArgumentException
* if the image format was not a defined named constant
@@ -508,8 +508,10 @@ public final class RecommendedStreamConfigurationMap {
}
/**
- * Determine whether or not the {@code surface} in its current state is suitable to be included
- * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+ * Determine whether or not the {@code surface} in its current
+ * state is suitable to be included in a {@link
+ * CameraDevice#createCaptureSession(SessionConfiguration) capture
+ * session} as an output.
*
* <p>For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
* </p>
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index 385f10719509..8f611a831204 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -55,7 +55,7 @@ public final class SessionConfiguration implements Parcelable {
* at regular non high speed FPS ranges and optionally {@link InputConfiguration} for
* reprocessable sessions.
*
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
* @see CameraDevice#createReprocessableCaptureSession
*/
public static final int SESSION_REGULAR = CameraDevice.SESSION_OPERATION_MODE_NORMAL;
@@ -110,10 +110,7 @@ public final class SessionConfiguration implements Parcelable {
*
* @see #SESSION_REGULAR
* @see #SESSION_HIGH_SPEED
- * @see CameraDevice#createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)
- * @see CameraDevice#createCaptureSessionByOutputConfigurations
- * @see CameraDevice#createReprocessableCaptureSession
- * @see CameraDevice#createConstrainedHighSpeedCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
*/
public SessionConfiguration(@SessionMode int sessionType,
@NonNull List<OutputConfiguration> outputs,
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index fac64da764d8..b85d6869a1ff 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -41,7 +41,7 @@ import java.util.Set;
* {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to set up
* {@link android.view.Surface Surfaces} for creating a
* {@link android.hardware.camera2.CameraCaptureSession capture session} with
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession(SessionConfiguration)}.
* <!-- TODO: link to input stream configuration -->
*
* <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
@@ -62,7 +62,7 @@ import java.util.Set;
* }</code></pre>
*
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
*/
public final class StreamConfigurationMap {
@@ -456,7 +456,7 @@ public final class StreamConfigurationMap {
/**
* Determine whether or not output surfaces with a particular user-defined format can be passed
- * {@link CameraDevice#createCaptureSession createCaptureSession}.
+ * {@link CameraDevice#createCaptureSession(SessionConfiguration) createCaptureSession}.
*
* <p>This method determines that the output {@code format} is supported by the camera device;
* each output {@code surface} target may or may not itself support that {@code format}.
@@ -468,7 +468,7 @@ public final class StreamConfigurationMap {
* @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
* @return
* {@code true} iff using a {@code surface} with this {@code format} will be
- * supported with {@link CameraDevice#createCaptureSession}
+ * supported with {@link CameraDevice#createCaptureSession(SessionConfiguration)}
*
* @throws IllegalArgumentException
* if the image format was not a defined named constant
@@ -476,7 +476,7 @@ public final class StreamConfigurationMap {
*
* @see ImageFormat
* @see PixelFormat
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
*/
public boolean isOutputSupportedFor(int format) {
checkArgumentFormat(format);
@@ -519,7 +519,7 @@ public final class StreamConfigurationMap {
*
* <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
* provide a producer endpoint that is suitable to be used with
- * {@link CameraDevice#createCaptureSession}.</p>
+ * {@link CameraDevice#createCaptureSession(SessionConfiguration)}.</p>
*
* <p>Since not all of the above classes support output of all format and size combinations,
* the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
@@ -529,7 +529,7 @@ public final class StreamConfigurationMap {
*
* @throws NullPointerException if {@code klass} was {@code null}
*
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
* @see #isOutputSupportedFor(Surface)
*/
public static <T> boolean isOutputSupportedFor(Class<T> klass) {
@@ -553,8 +553,10 @@ public final class StreamConfigurationMap {
}
/**
- * Determine whether or not the {@code surface} in its current state is suitable to be included
- * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+ * Determine whether or not the {@code surface} in its current
+ * state is suitable to be included in a {@link
+ * CameraDevice#createCaptureSession(SessionConfiguration) capture
+ * session} as an output.
*
* <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
* of that {@code surface} are compatible. Some classes that provide the {@code surface} are
@@ -586,7 +588,7 @@ public final class StreamConfigurationMap {
* @throws NullPointerException if {@code surface} was {@code null}
* @throws IllegalArgumentException if the Surface endpoint is no longer valid
*
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
* @see #isOutputSupportedFor(Class)
*/
public boolean isOutputSupportedFor(Surface surface) {
@@ -621,14 +623,16 @@ public final class StreamConfigurationMap {
}
/**
- * Determine whether or not the particular stream configuration is suitable to be included
- * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+ * Determine whether or not the particular stream configuration is
+ * suitable to be included in a {@link
+ * CameraDevice#createCaptureSession(SessionConfiguration) capture
+ * session} as an output.
*
* @param size stream configuration size
* @param format stream configuration format
* @return {@code true} if this is supported, {@code false} otherwise
*
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
* @see #isOutputSupportedFor(Class)
* @hide
*/
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 76efce56dcf0..21e4ab195f28 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -1762,6 +1762,15 @@ public final class DisplayManager {
* 123,1,critical,0.8,default;123,1,moderate,0.6,id_2;456,2,moderate,0.9,critical,0.7
*/
String KEY_BRIGHTNESS_THROTTLING_DATA = "brightness_throttling_data";
+
+ /**
+ * Key for disabling screen wake locks while apps are in cached state.
+ * Read value via {@link android.provider.DeviceConfig#getBoolean(String, String, boolean)}
+ * with {@link android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER} as the namespace.
+ * @hide
+ */
+ String KEY_DISABLE_SCREEN_WAKE_LOCKS_WHILE_CACHED =
+ "disable_screen_wake_locks_while_cached";
}
/**
diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java
index 66269cb772f8..b25f47b11532 100644
--- a/core/java/android/hardware/usb/UsbConfiguration.java
+++ b/core/java/android/hardware/usb/UsbConfiguration.java
@@ -172,7 +172,8 @@ public class UsbConfiguration implements Parcelable {
String name = in.readString();
int attributes = in.readInt();
int maxPower = in.readInt();
- Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader());
+ Parcelable[] interfaces = in.readParcelableArray(
+ UsbInterface.class.getClassLoader(), UsbInterface.class);
UsbConfiguration configuration = new UsbConfiguration(id, name, attributes, maxPower);
configuration.setInterfaces(interfaces);
return configuration;
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 3da696ad0bc7..7fbaf1027af6 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -882,10 +882,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
static Uri readFrom(Parcel parcel) {
+ final StringUri stringUri = new StringUri(parcel.readString8());
return new OpaqueUri(
- parcel.readString8(),
- Part.readFrom(parcel),
- Part.readFrom(parcel)
+ stringUri.parseScheme(),
+ stringUri.getSsp(),
+ stringUri.getFragmentPart()
);
}
@@ -895,9 +896,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(TYPE_ID);
- parcel.writeString8(scheme);
- ssp.writeTo(parcel);
- fragment.writeTo(parcel);
+ parcel.writeString8(toString());
}
public boolean isHierarchical() {
@@ -1196,22 +1195,25 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
Part query, Part fragment) {
this.scheme = scheme;
this.authority = Part.nonNull(authority);
- this.path = path == null ? PathPart.NULL : path;
+ this.path = generatePath(path);
this.query = Part.nonNull(query);
this.fragment = Part.nonNull(fragment);
}
- static Uri readFrom(Parcel parcel) {
- final String scheme = parcel.readString8();
- final Part authority = Part.readFrom(parcel);
+ private PathPart generatePath(PathPart originalPath) {
// 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);
+ final PathPart newPath = hasSchemeOrAuthority ? PathPart.makeAbsolute(originalPath)
+ : originalPath;
+ return newPath == null ? PathPart.NULL : newPath;
+ }
+
+ static Uri readFrom(Parcel parcel) {
+ final StringUri stringUri = new StringUri(parcel.readString8());
+ return new HierarchicalUri(stringUri.getScheme(), stringUri.getAuthorityPart(),
+ stringUri.getPathPart(), stringUri.getQueryPart(), stringUri.getFragmentPart());
}
public int describeContents() {
@@ -1220,11 +1222,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(TYPE_ID);
- parcel.writeString8(scheme);
- authority.writeTo(parcel);
- path.writeTo(parcel);
- query.writeTo(parcel);
- fragment.writeTo(parcel);
+ parcel.writeString8(toString());
}
public boolean isHierarchical() {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 159394b2b776..cf8e875c1644 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1810,7 +1810,7 @@ public class UserManager {
public static final String DISALLOW_ULTRA_WIDEBAND_RADIO = "no_ultra_wideband_radio";
/**
- * This user restriction specifies if Near-fied communication is disallowed on the device. If
+ * This user restriction specifies if Near-field communication is disallowed on the device. If
* Near-field communication is disallowed it cannot be turned on via Settings.
*
* <p>This restriction can only be set by a device owner or a profile owner of an
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 1d49049ab7d4..07f8aac43bf5 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -485,9 +485,6 @@ public abstract class NotificationListenerService extends Service {
/**
* Implement this method to learn when notifications are removed.
* <p>
- * This might occur because the user has dismissed the notification using system UI (or another
- * notification listener) or because the app has withdrawn the notification.
- * <p>
* NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
* result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
* fields such as {@link android.app.Notification#contentView} and
@@ -506,9 +503,6 @@ public abstract class NotificationListenerService extends Service {
/**
* Implement this method to learn when notifications are removed.
* <p>
- * This might occur because the user has dismissed the notification using system UI (or another
- * notification listener) or because the app has withdrawn the notification.
- * <p>
* NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
* result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
* fields such as {@link android.app.Notification#contentView} and
@@ -531,9 +525,6 @@ public abstract class NotificationListenerService extends Service {
/**
* Implement this method to learn when notifications are removed and why.
* <p>
- * This might occur because the user has dismissed the notification using system UI (or another
- * notification listener) or because the app has withdrawn the notification.
- * <p>
* NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
* result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
* fields such as {@link android.app.Notification#contentView} and
@@ -546,10 +537,9 @@ public abstract class NotificationListenerService extends Service {
* was just removed.
* @param rankingMap The current ranking map that can be used to retrieve ranking information
* for active notifications.
- * @param reason see {@link #REASON_LISTENER_CANCEL}, etc.
*/
public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
- int reason) {
+ @NotificationCancelReason int reason) {
onNotificationRemoved(sbn, rankingMap);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index dbc1be141571..d9ac4850e924 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -868,6 +868,11 @@ public abstract class WallpaperService extends Service {
* This will trigger a {@link #onComputeColors()} call.
*/
public void notifyColorsChanged() {
+ if (mDestroyed) {
+ Log.i(TAG, "Ignoring notifyColorsChanged(), Engine has already been destroyed.");
+ return;
+ }
+
final long now = mClockFunction.get();
if (now - mLastColorInvalidation < NOTIFY_COLORS_RATE_LIMIT_MS) {
Log.w(TAG, "This call has been deferred. You should only call "
@@ -2226,7 +2231,11 @@ public abstract class WallpaperService extends Service {
}
}
- void detach() {
+ /**
+ * @hide
+ */
+ @VisibleForTesting
+ public void detach() {
if (mDestroyed) {
return;
}
@@ -2442,6 +2451,14 @@ public abstract class WallpaperService extends Service {
}
public void reportShown() {
+ if (mEngine == null) {
+ Log.i(TAG, "Can't report null engine as shown.");
+ return;
+ }
+ if (mEngine.mDestroyed) {
+ Log.i(TAG, "Engine was destroyed before we could draw.");
+ return;
+ }
if (!mShownReported) {
mShownReported = true;
Trace.beginSection("WPMS.mConnection.engineShown");
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 5019b85ca503..a3d1be07c51c 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -69,6 +69,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.internal.util.function.TriFunction;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -77,7 +78,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
-import java.util.function.BiFunction;
/**
* Implements {@link WindowInsetsController} on the client.
@@ -621,7 +621,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private final InsetsState mLastDispatchedState = new InsetsState();
private final Rect mFrame = new Rect();
- private final BiFunction<InsetsController, InsetsSource, InsetsSourceConsumer> mConsumerCreator;
+ private final TriFunction<InsetsController, Integer, Integer, InsetsSourceConsumer>
+ mConsumerCreator;
private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>();
private final InsetsSourceConsumer mImeSourceConsumer;
private final Host mHost;
@@ -689,13 +690,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// Don't change the indexes of the sources while traversing. Remove it later.
mPendingRemoveIndexes.add(index1);
-
- // Remove the consumer as well except the IME one. IME consumer should always
- // be there since we need to communicate with InputMethodManager no matter we
- // have the source or not.
- if (source1.getType() != ime()) {
- mSourceConsumers.remove(source1.getId());
- }
}
@Override
@@ -750,12 +744,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
};
public InsetsController(Host host) {
- this(host, (controller, source) -> {
- if (source.getType() == ime()) {
- return new ImeInsetsSourceConsumer(source.getId(), controller.mState,
+ this(host, (controller, id, type) -> {
+ if (type == ime()) {
+ return new ImeInsetsSourceConsumer(id, controller.mState,
Transaction::new, controller);
} else {
- return new InsetsSourceConsumer(source.getId(), source.getType(), controller.mState,
+ return new InsetsSourceConsumer(id, type, controller.mState,
Transaction::new, controller);
}
}, host.getHandler());
@@ -763,7 +757,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public InsetsController(Host host,
- BiFunction<InsetsController, InsetsSource, InsetsSourceConsumer> consumerCreator,
+ TriFunction<InsetsController, Integer, Integer, InsetsSourceConsumer> consumerCreator,
Handler handler) {
mHost = host;
mConsumerCreator = consumerCreator;
@@ -815,7 +809,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
};
// Make mImeSourceConsumer always non-null.
- mImeSourceConsumer = getSourceConsumer(new InsetsSource(ID_IME, ime()));
+ mImeSourceConsumer = getSourceConsumer(ID_IME, ime());
}
@VisibleForTesting
@@ -893,7 +887,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
cancelledUserAnimationTypes[0] |= type;
}
}
- getSourceConsumer(source).updateSource(source, animationType);
+ final InsetsSourceConsumer consumer = mSourceConsumers.get(source.getId());
+ if (consumer != null) {
+ consumer.updateSource(source, animationType);
+ } else {
+ mState.addSource(source);
+ }
existingTypes |= type;
if (source.isVisible()) {
visibleTypes |= type;
@@ -997,8 +996,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@InsetsType int controllableTypes = 0;
int consumedControlCount = 0;
- final int[] showTypes = new int[1];
- final int[] hideTypes = new int[1];
+ final @InsetsType int[] showTypes = new int[1];
+ final @InsetsType int[] hideTypes = new int[1];
// Ensure to update all existing source consumers
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
@@ -1014,15 +1013,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
consumer.setControl(control, showTypes, hideTypes);
}
+ // Ensure to create source consumers if not available yet.
if (consumedControlCount != mTmpControlArray.size()) {
- // Whoops! The server sent us some controls without sending corresponding sources.
for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
final InsetsSourceControl control = mTmpControlArray.valueAt(i);
- final InsetsSourceConsumer consumer = mSourceConsumers.get(control.getId());
- if (consumer == null) {
- control.release(SurfaceControl::release);
- Log.e(TAG, control + " has no consumer.");
- }
+ getSourceConsumer(control.getId(), control.getType())
+ .setControl(control, showTypes, hideTypes);
}
}
@@ -1587,6 +1583,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (type == ime()) {
abortPendingImeControlRequest();
}
+ if (consumer.getType() != ime()) {
+ // IME consumer should always be there since we need to communicate with
+ // InputMethodManager no matter we have the control or not.
+ mSourceConsumers.remove(consumer.getId());
+ }
}
private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
@@ -1640,21 +1641,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
@VisibleForTesting
- public @NonNull InsetsSourceConsumer getSourceConsumer(InsetsSource source) {
- final int sourceId = source.getId();
- InsetsSourceConsumer consumer = mSourceConsumers.get(sourceId);
+ public @NonNull InsetsSourceConsumer getSourceConsumer(int id, int type) {
+ InsetsSourceConsumer consumer = mSourceConsumers.get(id);
if (consumer != null) {
return consumer;
}
- if (source.getType() == ime() && mImeSourceConsumer != null) {
+ if (type == ime() && mImeSourceConsumer != null) {
// WindowInsets.Type.ime() should be only provided by one source.
mSourceConsumers.remove(mImeSourceConsumer.getId());
consumer = mImeSourceConsumer;
- consumer.setId(sourceId);
+ consumer.setId(id);
} else {
- consumer = mConsumerCreator.apply(this, source);
+ consumer = mConsumerCreator.apply(this, id, type);
}
- mSourceConsumers.put(sourceId, consumer);
+ mSourceConsumers.put(id, consumer);
return consumer;
}
@@ -1663,8 +1663,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
return mImeSourceConsumer;
}
- @VisibleForTesting
- public void notifyVisibilityChanged() {
+ void notifyVisibilityChanged() {
mHost.notifyInsetsChanged();
}
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 467d720196b1..34b288460a67 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -149,9 +149,12 @@ public class InsetsSourceConsumer {
// Check if we need to restore server visibility.
final InsetsSource localSource = mState.peekSource(mId);
final InsetsSource serverSource = mController.getLastDispatchedState().peekSource(mId);
- if (localSource != null && serverSource != null
- && localSource.isVisible() != serverSource.isVisible()) {
- localSource.setVisible(serverSource.isVisible());
+ final boolean localVisible = localSource != null && localSource.isVisible();
+ final boolean serverVisible = serverSource != null && serverSource.isVisible();
+ if (localSource != null) {
+ localSource.setVisible(serverVisible);
+ }
+ if (localVisible != serverVisible) {
mController.notifyVisibilityChanged();
}
} else {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index a91781580ac4..f221db35b9bc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -880,22 +880,23 @@ public interface WindowManager extends ViewManager {
int LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP = 600;
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} for an app to inform the system that the app can be opted-in or opted-out
- * from the compatibility treatment that avoids {@link
- * android.app.Activity#setRequestedOrientation} loops. The loop can be trigerred by
- * ignoreRequestedOrientation display setting enabled on the device or by the landscape natural
- * orientation of the device.
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the app can be opted-in or opted-out from the
+ * compatibility treatment that avoids {@link android.app.Activity#setRequestedOrientation
+ * Activity#setRequestedOrientation()} loops. Loops can be triggered by the OEM-configured
+ * ignore requested orientation display setting (on Android 12 (API level 31) and higher) or by
+ * the landscape natural orientation of the device.
*
* <p>The treatment is disabled by default but device manufacturers can enable the treatment
* using their discretion to improve display compatibility.
*
- * <p>With this property set to {@code true}, the system could ignore {@link
- * android.app.Activity#setRequestedOrientation} call from an app if one of the following
- * conditions are true:
+ * <p>With this property set to {@code true}, the system could ignore
+ * {@link android.app.Activity#setRequestedOrientation Activity#setRequestedOrientation()} call
+ * from an app if one of the following conditions are true:
* <ul>
- * <li>Activity is relaunching due to the previous {@link
- * android.app.Activity#setRequestedOrientation} call.
+ * <li>Activity is relaunching due to the previous
+ * {@link android.app.Activity#setRequestedOrientation Activity#setRequestedOrientation()}
+ * call.
* <li>Camera compatibility force rotation treatment is active for the package.
* </ul>
*
@@ -919,14 +920,16 @@ public interface WindowManager extends ViewManager {
/**
* Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
* for an app to inform the system that the app can be opted-out from the compatibility
- * treatment that avoids {@link android.app.Activity#setRequestedOrientation} loops. The loop
- * can be trigerred by ignoreRequestedOrientation display setting enabled on the device or
- * by the landscape natural orientation of the device.
+ * treatment that avoids {@link android.app.Activity#setRequestedOrientation
+ * Activity#setRequestedOrientation()} loops. Loops can be triggered by the OEM-configured
+ * ignore requested orientation display setting (on Android 12 (API level 31) and higher) or by
+ * the landscape natural orientation of the device.
*
- * <p>The system could ignore {@link android.app.Activity#setRequestedOrientation}
- * call from an app if both of the following conditions are true:
+ * <p>The system could ignore {@link android.app.Activity#setRequestedOrientation
+ * Activity#setRequestedOrientation()} call from an app if both of the following conditions are
+ * true:
* <ul>
- * <li>Activity has requested orientation more than 2 times within 1-second timer
+ * <li>Activity has requested orientation more than two times within one-second timer
* <li>Activity is not letterboxed for fixed orientation
* </ul>
*
@@ -953,23 +956,21 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED";
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} for an app to inform the system that it needs to be opted-out from the
- * compatibility treatment that sandboxes {@link android.view.View} API.
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that it needs to be opted-out from the compatibility
+ * treatment that sandboxes the {@link android.view.View View} API.
*
* <p>The treatment can be enabled by device manufacturers for applications which misuse
- * {@link android.view.View} APIs by expecting that
- * {@link android.view.View#getLocationOnScreen},
- * {@link android.view.View#getBoundsOnScreen},
- * {@link android.view.View#getWindowVisibleDisplayFrame},
- * {@link android.view.View#getWindowDisplayFrame}
+ * {@link android.view.View View} APIs by expecting that
+ * {@link android.view.View#getLocationOnScreen View#getLocationOnScreen()} and
+ * {@link android.view.View#getWindowVisibleDisplayFrame View#getWindowVisibleDisplayFrame()}
* return coordinates as if an activity is positioned in the top-left corner of the screen, with
- * left coordinate equal to 0. This may not be the case for applications in multi-window and in
+ * left coordinate equal to 0. This may not be the case for applications in multi-window and
* letterbox modes.
*
* <p>Setting this property to {@code false} informs the system that the application must be
- * opted-out from the "Sandbox {@link android.view.View} API to Activity bounds" treatment even
- * if the device manufacturer has opted the app into the treatment.
+ * opted-out from the "Sandbox View API to Activity bounds" treatment even if the device
+ * manufacturer has opted the app into the treatment.
*
* <p>Not setting this property at all, or setting this property to {@code true} has no effect.
*
@@ -987,12 +988,11 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS";
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} for an app to inform the system that the application can be opted-in or opted-out
- * from the compatibility treatment that enables sending a fake focus event for unfocused
- * resumed split screen activities. This is needed because some game engines wait to get
- * focus before drawing the content of the app which isn't guaranteed by default in multi-window
- * modes.
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the application can be opted-in or opted-out from the
+ * compatibility treatment that enables sending a fake focus event for unfocused resumed
+ * split-screen activities. This is needed because some game engines wait to get focus before
+ * drawing the content of the app which isn't guaranteed by default in multi-window mode.
*
* <p>Device manufacturers can enable this treatment using their discretion on a per-device
* basis to improve display compatibility. The treatment also needs to be specifically enabled
@@ -1022,9 +1022,9 @@ public interface WindowManager extends ViewManager {
String PROPERTY_COMPAT_ENABLE_FAKE_FOCUS = "android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS";
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} for an app to inform the system that the app should be excluded from the
- * camera compatibility force rotation treatment.
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the app should be excluded from the camera compatibility
+ * force rotation treatment.
*
* <p>The camera compatibility treatment aligns orientations of portrait app window and natural
* orientation of the device and set opposite to natural orientation for a landscape app
@@ -1034,10 +1034,11 @@ public interface WindowManager extends ViewManager {
* rotation can cause letterboxing. The forced rotation is triggered as soon as app opens to
* camera and is removed once camera is closed.
*
- * <p>The camera compatibility can be enabled by device manufacturers on the displays that have
- * ignoreOrientationRequest display setting enabled (enables compatibility mode for fixed
- * orientation, see <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced letterboxing</a>
- * for more details).
+ * <p>The camera compatibility can be enabled by device manufacturers on displays that have the
+ * ignore requested orientation display setting enabled (enables compatibility mode for fixed
+ * orientation on Android 12 (API level 31) or higher; see
+ * <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced
+ * letterboxing</a> for more details).
*
* <p>With this property set to {@code true} or unset, the system may apply the force rotation
* treatment to fixed orientation activities. Device manufacturers can exclude packages from the
@@ -1060,9 +1061,9 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION";
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} for an app to inform the system that the app should be excluded
- * from the activity "refresh" after the camera compatibility force rotation treatment.
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the app should be excluded from the activity "refresh"
+ * after the camera compatibility force rotation treatment.
*
* <p>The camera compatibility treatment aligns orientations of portrait app window and natural
* orientation of the device and set opposite to natural orientation for a landscape app
@@ -1079,10 +1080,11 @@ public interface WindowManager extends ViewManager {
* camera preview and can lead to sideways or stretching issues persisting even after force
* rotation.
*
- * <p>The camera compatibility can be enabled by device manufacturers on the displays that have
- * ignoreOrientationRequest display setting enabled (enables compatibility mode for fixed
- * orientation, see <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced letterboxing</a>
- * for more details).
+ * <p>The camera compatibility can be enabled by device manufacturers on displays that have the
+ * ignore requested orientation display setting enabled (enables compatibility mode for fixed
+ * orientation on Android 12 (API level 31) or higher; see
+ * <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced
+ * letterboxing</a> for more details).
*
* <p>With this property set to {@code true} or unset, the system may "refresh" activity after
* the force rotation treatment. Device manufacturers can exclude packages from the "refresh"
@@ -1105,10 +1107,10 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH";
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} for an app to inform the system that the activity should be or shouldn't be
- * "refreshed" after the camera compatibility force rotation treatment using "paused ->
- * resumed" cycle rather than "stopped -> resumed".
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the activity should be or shouldn't be "refreshed" after
+ * the camera compatibility force rotation treatment using "paused -> resumed" cycle rather than
+ * "stopped -> resumed".
*
* <p>The camera compatibility treatment aligns orientations of portrait app window and natural
* orientation of the device and set opposite to natural orientation for a landscape app
@@ -1124,10 +1126,11 @@ public interface WindowManager extends ViewManager {
* values in apps (e.g., display or camera rotation) that influence camera preview and can lead
* to sideways or stretching issues persisting even after force rotation.
*
- * <p>The camera compatibility can be enabled by device manufacturers on the displays that have
- * ignoreOrientationRequest display setting enabled (enables compatibility mode for fixed
- * orientation, see <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced letterboxing</a>
- * for more details).
+ * <p>The camera compatibility can be enabled by device manufacturers on displays that have the
+ * ignore requested orientation display setting enabled (enables compatibility mode for fixed
+ * orientation on Android 12 (API level 31) or higher; see
+ * <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced
+ * letterboxing</a> for more details).
*
* <p>Device manufacturers can override packages to "refresh" via "resumed -> paused -> resumed"
* cycle using their discretion to improve display compatibility.
@@ -1153,22 +1156,23 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE";
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} for an app to inform the system that the app should be excluded from the
- * compatibility override for orientation set by the device manufacturer. When the orientation
- * override is applied it can:
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the app should be excluded from the compatibility
+ * override for orientation set by the device manufacturer. When the orientation override is
+ * applied it can:
* <ul>
* <li>Replace the specific orientation requested by the app with another selected by the
- device manufacturer, e.g. replace undefined requested by the app with portrait.
+ device manufacturer; for example, replace undefined requested by the app with portrait.
* <li>Always use an orientation selected by the device manufacturer.
* <li>Do one of the above but only when camera connection is open.
* </ul>
*
- * <p>This property is different from {@link PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION}
+ * <p>This property is different from {@link #PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION}
* (which is used to avoid orientation loops caused by the incorrect use of {@link
- * android.app.Activity#setRequestedOrientation}) because this property overrides the app to an
- * orientation selected by the device manufacturer rather than ignoring one of orientation
- * requests coming from the app while respecting the previous one.
+ * android.app.Activity#setRequestedOrientation Activity#setRequestedOrientation()}) because
+ * this property overrides the app to an orientation selected by the device manufacturer rather
+ * than ignoring one of orientation requests coming from the app while respecting the previous
+ * one.
*
* <p>With this property set to {@code true} or unset, device manufacturers can override
* orientation for the app using their discretion to improve display compatibility.
@@ -1190,10 +1194,10 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE";
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} for an app to inform the system that the app should be opted-out from the
- * compatibility override that fixes display orientation to landscape natural orientation when
- * an activity is fullscreen.
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the app should be opted-out from the compatibility
+ * override that fixes display orientation to landscape natural orientation when an activity is
+ * fullscreen.
*
* <p>When this compat override is enabled and while display is fixed to the landscape natural
* orientation, the orientation requested by the activity will be still respected by bounds
@@ -1202,16 +1206,17 @@ public interface WindowManager extends ViewManager {
* lanscape natural orientation.
*
* <p>The treatment is disabled by default but device manufacturers can enable the treatment
- * using their discretion to improve display compatibility on the displays that have
- * ignoreOrientationRequest display setting enabled (enables compatibility mode for fixed
- * orientation, see <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced letterboxing</a>
- * for more details).
+ * using their discretion to improve display compatibility on displays that have the ignore
+ * orientation request display setting enabled by OEMs on the device (enables compatibility mode
+ * for fixed orientation on Android 12 (API level 31) or higher; see
+ * <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced
+ * letterboxing</a> for more details).
*
* <p>With this property set to {@code true} or unset, the system wiil use landscape display
* orientation when the following conditions are met:
* <ul>
* <li>Natural orientation of the display is landscape
- * <li>ignoreOrientationRequest display setting is enabled
+ * <li>ignore requested orientation display setting is enabled
* <li>Activity is fullscreen.
* <li>Device manufacturer enabled the treatment.
* </ul>
@@ -1233,9 +1238,9 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE";
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} for an app to inform the system that the app should be opted-out from the
- * compatibility override that changes the min aspect ratio.
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the app should be opted-out from the compatibility
+ * override that changes the min aspect ratio.
*
* <p>When this compat override is enabled the min aspect ratio given in the app's manifest can
* be overridden by the device manufacturer using their discretion to improve display
@@ -1264,14 +1269,14 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE";
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} for an app to inform the system that the app should be opted-out from the
- * compatibility overrides that change the resizability of the app.
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the app should be opted-out from the compatibility
+ * overrides that change the resizability of the app.
*
* <p>When these compat overrides are enabled they force the packages they are applied to to be
- * resizable / unresizable. If the app is forced to be resizable this won't change whether
- * the app can be put into multi-windowing mode, but allow the app to resize without going into
- * size-compat mode when the window container resizes, such as display size change or screen
+ * resizable/unresizable. If the app is forced to be resizable this won't change whether the app
+ * can be put into multi-windowing mode, but allow the app to resize without going into size
+ * compatibility mode when the window container resizes, such as display size change or screen
* rotation.
*
* <p>Setting this property to {@code false} informs the system that the app must be
@@ -1320,34 +1325,29 @@ public interface WindowManager extends ViewManager {
}
/**
- * Application-level
- * {@link android.content.pm.PackageManager.Property PackageManager.Property}
- * tag that specifies whether OEMs are permitted to provide activity
- * embedding split-rule configurations on behalf of the app.
+ * Application-level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * tag that specifies whether OEMs are permitted to provide activity embedding split-rule
+ * configurations on behalf of the app.
*
- * <p>If {@code true}, the system is permitted to override the app's
- * windowing behavior and implement activity embedding split rules, such as
- * displaying activities side by side. A system override informs the app
- * that the activity embedding APIs are disabled so the app will not provide
- * its own activity embedding rules, which would conflict with the system's
+ * <p>If {@code true}, the system is permitted to override the app's windowing behavior and
+ * implement activity embedding split rules, such as displaying activities side by side. A
+ * system override informs the app that the activity embedding APIs are disabled so the app
+ * doesn't provide its own activity embedding rules, which would conflict with the system's
* rules.
*
- * <p>If {@code false}, the system is not permitted to override the
- * windowing behavior of the app. Set the property to {@code false} if the
- * app provides its own activity embedding split rules, or if you want to
- * prevent the system override for any other reason.
+ * <p>If {@code false}, the system is not permitted to override the windowing behavior of the
+ * app. Set the property to {@code false} if the app provides its own activity embedding split
+ * rules, or if you want to prevent the system override for any other reason.
*
* <p>The default value is {@code false}.
*
- * <p class="note"><b>Note:</b> Refusal to permit the system override is not
- * enforceable. OEMs can override the app's activity embedding
- * implementation whether or not this property is specified and set to
- * <code>false</code>. The property is, in effect, a hint to OEMs.
+ * <p class="note"><b>Note:</b> Refusal to permit the system override is not enforceable. OEMs
+ * can override the app's activity embedding implementation whether or not this property is
+ * specified and set to {@code false}. The property is, in effect, a hint to OEMs.
*
- * <p>OEMs can implement activity embedding on any API level. The best
- * practice for apps is to always explicitly set this property in the app
- * manifest file regardless of targeted API level rather than rely on the
- * default value.
+ * <p>OEMs can implement activity embedding on any API level. The best practice for apps is to
+ * always explicitly set this property in the app manifest file regardless of targeted API level
+ * rather than rely on the default value.
*
* <p><b>Syntax:</b>
* <pre>
@@ -1362,14 +1362,15 @@ public interface WindowManager extends ViewManager {
"android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
/**
- * Application level {@link android.content.pm.PackageManager.Property PackageManager
- * .Property} that an app can specify to inform the system that the app is ActivityEmbedding
- * split feature enabled.
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * that an app can specify to inform the system that the app is activity embedding split feature
+ * enabled.
*
* <p>With this property, the system could provide custom behaviors for the apps that are
- * ActivityEmbedding split feature enabled. For example, the fixed-portrait orientation
+ * activity embedding split feature enabled. For example, the fixed-portrait orientation
* requests of the activities could be ignored by the system in order to provide seamless
- * ActivityEmbedding split experiences while holding the large-screen devices in landscape mode.
+ * activity embedding split experiences while holding large screen devices in landscape
+ * orientation.
*
* <p><b>Syntax:</b>
* <pre>
@@ -3722,6 +3723,7 @@ public interface WindowManager extends ViewManager {
* @see #ROTATION_ANIMATION_ROTATE
* @see #ROTATION_ANIMATION_CROSSFADE
* @see #ROTATION_ANIMATION_JUMPCUT
+ * @see #ROTATION_ANIMATION_SEAMLESS
*/
public int rotationAnimation = ROTATION_ANIMATION_ROTATE;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 41ef44e1ac1f..3cac1e5f7d6e 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2657,17 +2657,6 @@ public final class InputMethodManager {
}
}
- if (windowGainingFocus == null) {
- windowGainingFocus = view.getWindowToken();
- if (windowGainingFocus == null) {
- Log.e(TAG, "ABORT input: ServedView must be attached to a Window");
- return false;
- }
- startInputFlags = getStartInputFlags(view, startInputFlags);
- softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode;
- windowFlags = view.getViewRootImpl().mWindowAttributes.flags;
- }
-
// Now we need to get an input connection from the served view.
// This is complicated in a couple ways: we can't be holding our lock
// when calling out to the view, and we need to make sure we call into
@@ -2690,6 +2679,17 @@ public final class InputMethodManager {
return false;
}
+ if (windowGainingFocus == null) {
+ windowGainingFocus = view.getWindowToken();
+ if (windowGainingFocus == null) {
+ Log.e(TAG, "ABORT input: ServedView must be attached to a Window");
+ return false;
+ }
+ startInputFlags = getStartInputFlags(view, startInputFlags);
+ softInputMode = view.getViewRootImpl().mWindowAttributes.softInputMode;
+ windowFlags = view.getViewRootImpl().mWindowAttributes.flags;
+ }
+
// Okay we are now ready to call into the served view and have it
// do its stuff.
// Life is good: let's hook everything up!
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index b65c1a17e26b..cb5dbe6c5618 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1550,6 +1550,7 @@ public class ScrollView extends FrameLayout {
float deltaDistance = -unconsumed * FLING_DESTRETCH_FACTOR / size;
int consumed = Math.round(-size / FLING_DESTRETCH_FACTOR
* mEdgeGlowTop.onPullDistance(deltaDistance, 0.5f));
+ mEdgeGlowTop.onRelease();
if (consumed != unconsumed) {
mEdgeGlowTop.finish();
}
@@ -1560,6 +1561,7 @@ public class ScrollView extends FrameLayout {
float deltaDistance = unconsumed * FLING_DESTRETCH_FACTOR / size;
int consumed = Math.round(size / FLING_DESTRETCH_FACTOR
* mEdgeGlowBottom.onPullDistance(deltaDistance, 0.5f));
+ mEdgeGlowBottom.onRelease();
if (consumed != unconsumed) {
mEdgeGlowBottom.finish();
}
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 7452daa4908c..65b59790e327 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -56,6 +56,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.telecom.TelecomManager;
+import android.util.Log;
import android.util.Slog;
import android.view.View;
import android.widget.Button;
@@ -124,16 +125,19 @@ public class IntentForwarderActivity extends Activity {
String className = intentReceived.getComponent().getClassName();
final int targetUserId;
final String userMessage;
+ final UserInfo managedProfile;
if (className.equals(FORWARD_INTENT_TO_PARENT)) {
userMessage = getForwardToPersonalMessage();
targetUserId = getProfileParent();
+ managedProfile = null;
getMetricsLogger().write(
new LogMaker(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE)
.setSubtype(MetricsEvent.PARENT_PROFILE));
} else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
userMessage = getForwardToWorkMessage();
- targetUserId = getManagedProfile();
+ managedProfile = getManagedProfile();
+ targetUserId = managedProfile == null ? UserHandle.USER_NULL : managedProfile.id;
getMetricsLogger().write(
new LogMaker(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE)
@@ -142,6 +146,7 @@ public class IntentForwarderActivity extends Activity {
Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
userMessage = null;
targetUserId = UserHandle.USER_NULL;
+ managedProfile = null;
}
if (targetUserId == UserHandle.USER_NULL) {
// This covers the case where there is no parent / managed profile.
@@ -185,27 +190,49 @@ public class IntentForwarderActivity extends Activity {
finish();
// When switching to the work profile, ask the user for consent before launching
} else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
- maybeShowUserConsentMiniResolver(result, newIntent, targetUserId);
+ maybeShowUserConsentMiniResolver(result, newIntent, managedProfile);
}
}, getApplicationContext().getMainExecutor());
}
private void maybeShowUserConsentMiniResolver(
- ResolveInfo target, Intent launchIntent, int targetUserId) {
+ ResolveInfo target, Intent launchIntent, UserInfo managedProfile) {
if (target == null || isIntentForwarderResolveInfo(target) || !isDeviceProvisioned()) {
finish();
return;
}
- if (launchIntent.getBooleanExtra(EXTRA_SKIP_USER_CONFIRMATION, /* defaultValue= */ false)
- && getCallingPackage() != null
- && PERMISSION_GRANTED == getPackageManager().checkPermission(
- INTERACT_ACROSS_USERS, getCallingPackage())) {
+ int targetUserId = managedProfile == null ? UserHandle.USER_NULL : managedProfile.id;
+ String callingPackage = getCallingPackage();
+ boolean privilegedCallerAskedToSkipUserConsent =
+ launchIntent.getBooleanExtra(
+ EXTRA_SKIP_USER_CONFIRMATION, /* defaultValue= */ false)
+ && callingPackage != null
+ && PERMISSION_GRANTED == getPackageManager().checkPermission(
+ INTERACT_ACROSS_USERS, callingPackage);
+
+ DevicePolicyManager devicePolicyManager =
+ getSystemService(DevicePolicyManager.class);
+ ComponentName profileOwnerName = devicePolicyManager.getProfileOwnerAsUser(targetUserId);
+ boolean intentToLaunchProfileOwner = profileOwnerName != null
+ && profileOwnerName.getPackageName().equals(target.getComponentInfo().packageName);
+
+ if (privilegedCallerAskedToSkipUserConsent || intentToLaunchProfileOwner) {
+ Log.i("IntentForwarderActivity", String.format(
+ "Skipping user consent for redirection into the managed profile for intent [%s]"
+ + ", privilegedCallerAskedToSkipUserConsent=[%s]"
+ + ", intentToLaunchProfileOwner=[%s]",
+ launchIntent, privilegedCallerAskedToSkipUserConsent,
+ intentToLaunchProfileOwner));
startActivityAsCaller(launchIntent, targetUserId);
finish();
return;
}
+ Log.i("IntentForwarderActivity", String.format(
+ "Showing user consent for redirection into the managed profile for intent [%s] and "
+ + " calling package [%s]",
+ launchIntent, callingPackage));
int layoutId = R.layout.miniresolver;
setContentView(layoutId);
@@ -245,8 +272,7 @@ public class IntentForwarderActivity extends Activity {
View telephonyInfo = findViewById(R.id.miniresolver_info_section);
- DevicePolicyManager devicePolicyManager =
- getSystemService(DevicePolicyManager.class);
+
// Additional information section is work telephony specific. Therefore, it is only shown
// for telephony related intents, when all sim subscriptions are in the work profile.
if ((isDialerIntent(launchIntent) || isTextMessageIntent(launchIntent))
@@ -507,20 +533,18 @@ public class IntentForwarderActivity extends Activity {
}
/**
- * Returns the userId of the managed profile for this device or UserHandle.USER_NULL if there is
- * no managed profile.
+ * Returns the managed profile for this device or null if there is no managed profile.
*
- * TODO: Remove the assumption that there is only one managed profile
- * on the device.
+ * TODO: Remove the assumption that there is only one managed profile on the device.
*/
- private int getManagedProfile() {
+ @Nullable private UserInfo getManagedProfile() {
List<UserInfo> relatedUsers = mInjector.getUserManager().getProfiles(UserHandle.myUserId());
for (UserInfo userInfo : relatedUsers) {
- if (userInfo.isManagedProfile()) return userInfo.id;
+ if (userInfo.isManagedProfile()) return userInfo;
}
Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE
+ " has been called, but there is no managed profile");
- return UserHandle.USER_NULL;
+ return null;
}
/**
diff --git a/core/java/com/android/internal/dynamicanimation/animation/DynamicAnimation.java b/core/java/com/android/internal/dynamicanimation/animation/DynamicAnimation.java
index 03f10b65629a..d4fe7c8d7f36 100644
--- a/core/java/com/android/internal/dynamicanimation/animation/DynamicAnimation.java
+++ b/core/java/com/android/internal/dynamicanimation/animation/DynamicAnimation.java
@@ -651,7 +651,7 @@ public abstract class DynamicAnimation<T extends DynamicAnimation<T>>
if (!mStartValueIsSet) {
mValue = getPropertyValue();
}
- // Initial check:
+ // Sanity check:
if (mValue > mMaxValue || mValue < mMinValue) {
throw new IllegalArgumentException("Starting value need to be in between min"
+ " value and max value");
diff --git a/core/java/com/android/internal/dynamicanimation/animation/SpringForce.java b/core/java/com/android/internal/dynamicanimation/animation/SpringForce.java
index dea4907cd689..36242ae2cf3d 100644
--- a/core/java/com/android/internal/dynamicanimation/animation/SpringForce.java
+++ b/core/java/com/android/internal/dynamicanimation/animation/SpringForce.java
@@ -228,7 +228,7 @@ public final class SpringForce implements Force {
}
/**
- * Initialize the string by doing the necessary pre-calculation as well as some initial check
+ * Initialize the string by doing the necessary pre-calculation as well as some sanity check
* on the setup.
*
* @throws IllegalStateException if the final position is not yet set by the time the spring
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index ca3373c55588..490ec35d1482 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1008,7 +1008,7 @@ public class LockPatternUtils {
CREDENTIAL_TYPE_API, CREDENTIAL_TYPE_API, mCredentialTypeQuery);
/**
- * Invalidate the credential cache
+ * Invalidate the credential type cache
* @hide
*/
public final static void invalidateCredentialTypeCache() {
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 0bc0878b7309..f97d41b6a122 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -42,6 +42,13 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
return NULL;
}
+ // b/274058082: Pass a copy of the key character map to avoid concurrent
+ // access
+ std::shared_ptr<KeyCharacterMap> map = deviceInfo.getKeyCharacterMap();
+ if (map != nullptr) {
+ map = std::make_shared<KeyCharacterMap>(*map);
+ }
+
ScopedLocalRef<jstring> descriptorObj(env,
env->NewStringUTF(deviceInfo.getIdentifier().descriptor.c_str()));
if (!descriptorObj.get()) {
@@ -61,8 +68,8 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi
: NULL));
ScopedLocalRef<jobject> kcmObj(env,
- android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
- deviceInfo.getKeyCharacterMap()));
+ android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
+ map));
if (!kcmObj.get()) {
return NULL;
}
diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
index a95b6e37f5de..76f5c107c970 100644
--- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -127,16 +127,17 @@ static void native_writeToParcel(JNIEnv *env, jobject self, jlong nativePtr, job
}
}
-static void throwReadRE(JNIEnv *env, binder_status_t status) {
+static void throwReadException(JNIEnv *env, binder_status_t status) {
ALOGE("Could not read LongArrayMultiStateCounter from Parcel, status = %d", status);
- jniThrowRuntimeException(env, "Could not read LongArrayMultiStateCounter from Parcel");
+ jniThrowException(env, "android.os.BadParcelableException",
+ "Could not read LongArrayMultiStateCounter from Parcel");
}
#define THROW_AND_RETURN_ON_READ_ERROR(expr) \
{ \
binder_status_t status = expr; \
if (status != STATUS_OK) { \
- throwReadRE(env, status); \
+ throwReadException(env, status); \
return 0L; \
} \
}
@@ -147,6 +148,11 @@ static jlong native_initFromParcel(JNIEnv *env, jclass theClass, jobject jParcel
int32_t stateCount;
THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &stateCount));
+ if (stateCount < 0 || stateCount > 0xEFFF) {
+ throwReadException(env, STATUS_INVALID_OPERATION);
+ return 0L;
+ }
+
int32_t arrayLength;
THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &arrayLength));
diff --git a/core/jni/com_android_internal_os_LongMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongMultiStateCounter.cpp
index 1712b3a8512b..ddf7a67e00ce 100644
--- a/core/jni/com_android_internal_os_LongMultiStateCounter.cpp
+++ b/core/jni/com_android_internal_os_LongMultiStateCounter.cpp
@@ -131,16 +131,17 @@ static void native_writeToParcel(JNIEnv *env, jobject self, jlong nativePtr, job
}
}
-static void throwReadRE(JNIEnv *env, binder_status_t status) {
+static void throwReadException(JNIEnv *env, binder_status_t status) {
ALOGE("Could not read LongMultiStateCounter from Parcel, status = %d", status);
- jniThrowRuntimeException(env, "Could not read LongMultiStateCounter from Parcel");
+ jniThrowException(env, "android.os.BadParcelableException",
+ "Could not read LongMultiStateCounter from Parcel");
}
#define THROW_AND_RETURN_ON_READ_ERROR(expr) \
{ \
binder_status_t status = expr; \
if (status != STATUS_OK) { \
- throwReadRE(env, status); \
+ throwReadException(env, status); \
return 0L; \
} \
}
@@ -151,6 +152,11 @@ static jlong native_initFromParcel(JNIEnv *env, jclass theClass, jobject jParcel
int32_t stateCount;
THROW_AND_RETURN_ON_READ_ERROR(AParcel_readInt32(parcel.get(), &stateCount));
+ if (stateCount < 0 || stateCount > 0xEFFF) {
+ throwReadException(env, STATUS_INVALID_OPERATION);
+ return 0L;
+ }
+
auto counter = std::make_unique<battery::LongMultiStateCounter>(stateCount, 0);
for (battery::state_t state = 0; state < stateCount; state++) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7d9d99113663..c16daccac081 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5633,6 +5633,12 @@
android:description="@string/permdesc_deliverCompanionMessages"
android:protectionLevel="normal" />
+ <!-- @hide @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)
+ Allows an application to send and receive messages via CDM transports.
+ -->
+ <permission android:name="android.permission.USE_COMPANION_TRANSPORTS"
+ android:protectionLevel="signature|module" />
+
<!-- Allows an application to create new companion device associations.
@SystemApi
@hide -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6f7bc53e891c..f0f39d160b59 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2465,7 +2465,7 @@
duration of the vector animation automatically. -->
<attr name="windowSplashScreenAnimationDuration" format="integer"/>
- <!-- Place an drawable image in the bottom of the starting window, it can be used to
+ <!-- Place a drawable image in the bottom of the starting window. The image can be used to
represent the branding of the application. -->
<attr name="windowSplashScreenBrandingImage" format="reference"/>
<!-- Set a background behind the splash screen icon. This is useful if there is not enough
@@ -3245,7 +3245,7 @@
<!-- Specifies the id of a view for which this view serves as a label for
accessibility purposes. For example, a TextView before an EditText in
- the UI usually specifies what infomation is contained in the EditText.
+ the UI usually specifies what information is contained in the EditText.
Hence, the TextView is a label for the EditText. -->
<attr name="labelFor" format="reference" />
@@ -3537,11 +3537,11 @@
<attr name="preferKeepClear" format="boolean" />
<!-- <p>Whether or not the auto handwriting initiation is enabled in this View.
- <p>For a view with active {@link android.view.inputmethod.InputConnection},
- if auto handwriting initiation is enabled stylus movement within its view boundary
+ <p>For a view with an active {@link android.view.inputmethod.InputConnection},
+ if auto handwriting initiation is enabled, stylus movement within its view boundary
will automatically trigger the handwriting mode.
- <p>This is true by default.
- See {@link android.view.View#setAutoHandwritingEnabled}. -->
+ See {@link android.view.View#setAutoHandwritingEnabled}.
+ <p>The default value of this flag is configurable by the device manufacturer. -->
<attr name="autoHandwritingEnabled" format="boolean" />
<!-- <p>The amount of offset that is applied to the left edge of the view's stylus
@@ -6787,7 +6787,7 @@
edges of a bitmap when rotated. Default value is false. -->
<attr name="antialias" format="boolean" />
<!-- Enables or disables bitmap filtering. Filtering is used when the bitmap is
- shrunk or stretched to smooth its apperance. Default value is true. -->
+ shrunk or stretched to smooth its appearance. Default value is true. -->
<attr name="filter" format="boolean" />
<!-- Enables or disables dithering of the bitmap if the bitmap does not have the
same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b7d088bd3d82..95f14931c6ef 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -634,7 +634,7 @@
able to return to it. -->
<attr name="noHistory" format="boolean" />
- <!-- Specify whether an acitivty's task state should always be maintained
+ <!-- Specify whether an activity's task state should always be maintained
by the system, or if it is allowed to reset the task to its initial
state in certain situations.
@@ -731,15 +731,17 @@
This is equivalent to calling {@link android.app.Activity#setVrModeEnabled} with the
the given component name within the Activity that this attribute is set for.
Declaring this will prevent the system from leaving VR mode during an Activity
- transtion from one VR activity to another. -->
+ transition from one VR activity to another. -->
<attr name="enableVrMode" format="string" />
- <!-- Flag allowing the activity to specify which screen rotation animation
- it desires. Valid values are "rotate", "crossfade", and "jumpcut"
- as described in {@link android.view.WindowManager.LayoutParams#rotationAnimation}.
- Specifying your Rotation animation in the WindowManager.LayoutParams
- may be racy with app startup and updattransitions occuring during application startup and thusly
- the manifest attribute is preferred.
+ <!-- Flag that specifies the activity's preferred screen rotation animation.
+ Valid values are "rotate", "crossfade", "jumpcut", and "seamless" as
+ described in
+ {@link android.view.WindowManager.LayoutParams#rotationAnimation}.
+ Specifying your rotation animation in
+ <code>WindowManager.LayoutParams</code> may be racy with app startup
+ and update transitions that occur during application startup; and so,
+ specify the animation in the manifest attribute.
-->
<attr name="rotationAnimation">
<flag name="rotate" value= "0" />
@@ -830,7 +832,7 @@
<enum name="singleInstance" value="3" />
<!-- The activity can only be running as the root activity of the task, the first activity
that created the task, and therefore there will only be one instance of this activity
- in a task. In constrast to the {@code singleTask} launch mode, this activity can be
+ in a task. In contrast to the {@code singleTask} launch mode, this activity can be
started in multiple instances in different tasks if the
{@code FLAG_ACTIVITY_MULTIPLE_TASK} or {@code FLAG_ACTIVITY_NEW_DOCUMENT} is set.-->
<enum name="singleInstancePerTask" value="4" />
@@ -1328,7 +1330,7 @@
<p>Such a document is any kind of item for which an application may want to
maintain multiple simultaneous instances. Examples might be text files, web
pages, spreadsheets, or emails. Each such document will be in a separate
- task in the recent taskss list.
+ task in the recent tasks list.
<p>This attribute is equivalent to adding the flag {@link
android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} to every Intent used to launch
@@ -1771,7 +1773,7 @@
</attr>
<!-- Enable hardware memory tagging (ARM MTE) in this process.
- When enabled, heap memory bugs like use-after-free and buffer overlow
+ When enabled, heap memory bugs like use-after-free and buffer overflow
are detected and result in an immediate ("sync" mode) or delayed ("async"
mode) crash instead of a silent memory corruption. Sync mode, while slower,
provides enhanced bug reports including stack traces at the time of allocation
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 52cc35d0d86e..0b67b6ca734f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2560,6 +2560,17 @@
assistant activities (ACTIVITY_TYPE_ASSISTANT) -->
<bool name="config_dismissDreamOnActivityStart">false</bool>
+ <!-- Whether to send a user activity event to PowerManager when a dream quits unexpectedly so
+ that the screen won't immediately shut off.
+
+ When a dream stops unexpectedly, such as due to an app update, if the device has been
+ inactive less than the user's screen timeout, the device goes to keyguard and times out
+ back to dreaming after a few seconds. If the device has been inactive longer, the screen
+ will immediately turn off. With this flag on, the device will go back to keyguard in all
+ scenarios rather than turning off, which gives the device a chance to start dreaming
+ again. -->
+ <bool name="config_resetScreenTimeoutOnUnexpectedDreamExit">false</bool>
+
<!-- The prefixes of dream component names that are loggable.
Matched against ComponentName#flattenToString() for dream components.
If empty, logs "other" for all. -->
@@ -2805,12 +2816,14 @@
<bool name="config_multiuserDelayUserDataLocking">false</bool>
<!-- Whether the device allows users to start in background visible on displays.
- Should be false for most devices, except automotive vehicle with passenger displays. -->
+ Should be false for all devices in production. Can be enabled only for development use
+ in automotive vehicles with passenger displays. -->
<bool name="config_multiuserVisibleBackgroundUsers">false</bool>
<!-- Whether the device allows users to start in background visible on the default display.
- Should be false for most devices, except passenger-only automotive build (i.e., when
- Android runs in a separate system in the back seat to manage the passenger displays).
+ Should be false for all devices in production. Can be enabled only for development use
+ in passenger-only automotive build (i.e., when Android runs in a separate system in the
+ back seat to manage the passenger displays).
When set to true, config_multiuserVisibleBackgroundUsers must also be true. -->
<bool name="config_multiuserVisibleBackgroundUsersOnDefaultDisplay">false</bool>
@@ -5178,7 +5191,7 @@
</string-array>
<!-- The integer index of the selected option in config_udfps_touch_detection_options -->
- <integer name="config_selected_udfps_touch_detection">3</integer>
+ <integer name="config_selected_udfps_touch_detection">0</integer>
<!-- An array of arrays of side fingerprint sensor properties relative to each display.
Note: this value is temporary and is expected to be queried directly
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1ccee27dcaa5..63bfa13387b6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2207,6 +2207,7 @@
<java-symbol type="array" name="config_supportedDreamComplications" />
<java-symbol type="array" name="config_disabledDreamComponents" />
<java-symbol type="bool" name="config_dismissDreamOnActivityStart" />
+ <java-symbol type="bool" name="config_resetScreenTimeoutOnUnexpectedDreamExit" />
<java-symbol type="integer" name="config_dreamOverlayReconnectTimeoutMs" />
<java-symbol type="integer" name="config_dreamOverlayMaxReconnectAttempts" />
<java-symbol type="integer" name="config_minDreamOverlayDurationMs" />
diff --git a/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
index 9acb99a8c1c2..b794352e5e27 100644
--- a/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
+++ b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
@@ -445,7 +445,9 @@ class PackageSessionTests {
Manifest.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION)
}
handlerThread = HandlerThread("PackageSessionTests")
- handlerThread?.start()
- handler = Handler(handlerThread?.looper)
+ handlerThread?.let {
+ it.start()
+ handler = Handler(it.looper)
+ }
}
}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 89632a46267e..2a4ca79d997e 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -25,8 +25,6 @@ import junit.framework.TestCase;
import java.io.File;
import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -869,84 +867,90 @@ public class UriTest extends TestCase {
return (Uri) hierarchicalUriConstructor.newInstance("https", authority, path, null, null);
}
- /** Attempting to unparcel a legacy parcel format of Uri.{,Path}Part should fail. */
- public void testUnparcelLegacyPart_fails() throws Exception {
- assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$Part"));
- assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$PathPart"));
- }
-
- private static void assertUnparcelLegacyPart_fails(Class partClass) throws Exception {
- Parcel parcel = Parcel.obtain();
- parcel.writeInt(0 /* BOTH */);
- parcel.writeString("encoded");
- parcel.writeString("decoded");
- parcel.setDataPosition(0);
-
- Method readFromMethod = partClass.getDeclaredMethod("readFrom", Parcel.class);
- readFromMethod.setAccessible(true);
- try {
- readFromMethod.invoke(null, parcel);
- fail();
- } catch (InvocationTargetException expected) {
- 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,
+ private Uri buildUriFromParts(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();
+ final Uri.Builder builder = new Uri.Builder();
+ builder.scheme(scheme);
+ if (argumentsEncoded) {
+ builder.encodedAuthority(authority);
+ builder.encodedPath(path);
+ builder.encodedQuery(query);
+ builder.encodedFragment(fragment);
+ } else {
+ builder.authority(authority);
+ builder.path(path);
+ builder.query(query);
+ builder.fragment(fragment);
}
+ return builder.build();
}
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);
+ Uri uri0 = buildUriFromParts(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");
+ Uri uri1 = buildUriFromParts(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);
+ Uri uri2 = buildUriFromParts(true, "http:", null, "@evil.com", null, null);
assertEquals("http::/@evil.com", uri2.toString());
- Uri uri3 = buildUriFromRawParcel(true, null, null, "@evil.com", null, null);
+ Uri uri3 = buildUriFromParts(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);
+ Uri uriA = buildUriFromParts(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);
+ Uri uriB = buildUriFromParts(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);
+ Uri uriC = buildUriFromParts(false, "http:", null, "@evil.com", null, null);
assertEquals("http::/%40evil.com", uriC.toString());
- Uri uriD = buildUriFromRawParcel(false, null, null, "@evil.com", "name=spark", "y");
+ Uri uriD = buildUriFromParts(false, null, null, "@evil.com", "name=spark", "y");
assertEquals("%40evil.com?name%3Dspark#y", uriD.toString());
}
+ public void testParsedUriFromStringEquality() {
+ Uri uri = buildUriFromParts(
+ true, "https", "google.com", "@evil.com", null, null);
+ assertEquals(uri, Uri.parse(uri.toString()));
+ Uri uri2 = buildUriFromParts(
+ true, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null);
+ assertEquals(uri2, Uri.parse(uri2.toString()));
+ Uri uri3 = buildUriFromParts(
+ false, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null);
+ assertEquals(uri3, Uri.parse(uri3.toString()));
+ }
+
+ public void testParceledUrisAreEqual() {
+ Uri opaqueUri = Uri.fromParts("fake://uri#", "ssp", "fragment");
+ Parcel parcel = Parcel.obtain();
+ try {
+ opaqueUri.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel);
+ Uri parsedUri = Uri.parse(postParcelUri.toString());
+ assertEquals(parsedUri.getScheme(), postParcelUri.getScheme());
+ } finally {
+ parcel.recycle();
+ }
+
+ Uri hierarchicalUri = new Uri.Builder().scheme("fake://uri#").authority("auth").build();
+ parcel = Parcel.obtain();
+ try {
+ hierarchicalUri.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel);
+ Uri parsedUri = Uri.parse(postParcelUri.toString());
+ assertEquals(parsedUri.getScheme(), postParcelUri.getScheme());
+ } finally {
+ parcel.recycle();
+ }
+ }
+
public void testToSafeString() {
checkToSafeString("tel:xxxxxx", "tel:Google");
checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 06920524acfc..b8f0d5c82eac 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -131,10 +131,10 @@ public class InsetsControllerTest {
mTestClock = new OffsettableClock();
mTestHandler = new TestHandler(null, mTestClock);
mTestHost = spy(new TestHost(mViewRoot));
- mController = new InsetsController(mTestHost, (controller, source) -> {
- if (source.getType() == ime()) {
- return new InsetsSourceConsumer(source.getId(), source.getType(),
- controller.getState(), Transaction::new, controller) {
+ mController = new InsetsController(mTestHost, (controller, id, type) -> {
+ if (type == ime()) {
+ return new InsetsSourceConsumer(id, type, controller.getState(),
+ Transaction::new, controller) {
private boolean mImeRequestedShow;
@@ -150,8 +150,8 @@ public class InsetsControllerTest {
}
};
} else {
- return new InsetsSourceConsumer(source.getId(), source.getType(),
- controller.getState(), Transaction::new, controller);
+ return new InsetsSourceConsumer(id, type, controller.getState(),
+ Transaction::new, controller);
}
}, mTestHandler);
final Rect rect = new Rect(5, 5, 5, 5);
@@ -182,7 +182,8 @@ public class InsetsControllerTest {
@Test
public void testControlsChanged() {
mController.onControlsChanged(createSingletonControl(ID_STATUS_BAR, statusBars()));
- assertNotNull(mController.getSourceConsumer(mStatusSource).getControl().getLeash());
+ assertNotNull(
+ mController.getSourceConsumer(ID_STATUS_BAR, statusBars()).getControl().getLeash());
mController.addOnControllableInsetsChangedListener(
((controller, typeMask) -> assertEquals(statusBars(), typeMask)));
}
@@ -194,7 +195,7 @@ public class InsetsControllerTest {
mController.addOnControllableInsetsChangedListener(listener);
mController.onControlsChanged(createSingletonControl(ID_STATUS_BAR, statusBars()));
mController.onControlsChanged(new InsetsSourceControl[0]);
- assertNull(mController.getSourceConsumer(mStatusSource).getControl());
+ assertNull(mController.getSourceConsumer(ID_STATUS_BAR, statusBars()).getControl());
InOrder inOrder = Mockito.inOrder(listener);
inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(0));
inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(statusBars()));
@@ -254,7 +255,7 @@ public class InsetsControllerTest {
// only the original thread that created view hierarchy can touch its views
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.setSystemDrivenInsetsAnimationLoggingListener(loggingListener);
- mController.getSourceConsumer(mImeSource).onWindowFocusGained(true);
+ mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
// since there is no focused view, forcefully make IME visible.
mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
// When using the animation thread, this must not invoke onReady()
@@ -271,7 +272,7 @@ public class InsetsControllerTest {
prepareControls();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- mController.getSourceConsumer(mImeSource).onWindowFocusGained(true);
+ mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
// since there is no focused view, forcefully make IME visible.
mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
mController.show(all());
@@ -284,7 +285,7 @@ public class InsetsControllerTest {
mController.hide(all());
mController.cancelExistingAnimations();
assertEquals(0, mController.getRequestedVisibleTypes() & types);
- mController.getSourceConsumer(mImeSource).onWindowFocusLost();
+ mController.getSourceConsumer(ID_IME, ime()).onWindowFocusLost();
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -294,14 +295,14 @@ public class InsetsControllerTest {
InsetsSourceControl ime = createControl(ID_IME, ime());
mController.onControlsChanged(new InsetsSourceControl[] { ime });
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- mController.getSourceConsumer(mImeSource).onWindowFocusGained(true);
+ mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
mController.cancelExistingAnimations();
assertTrue(isRequestedVisible(mController, ime()));
mController.hide(ime(), true /* fromIme */, null /* statsToken */);
mController.cancelExistingAnimations();
assertFalse(isRequestedVisible(mController, ime()));
- mController.getSourceConsumer(mImeSource).onWindowFocusLost();
+ mController.getSourceConsumer(ID_IME, ime()).onWindowFocusLost();
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -914,7 +915,7 @@ public class InsetsControllerTest {
// Simulate IME insets is not controllable
mController.onControlsChanged(new InsetsSourceControl[0]);
final InsetsSourceConsumer imeInsetsConsumer =
- mController.getSourceConsumer(mImeSource);
+ mController.getSourceConsumer(ID_IME, ime());
assertNull(imeInsetsConsumer.getControl());
// Verify IME requested visibility should be updated to IME consumer from controller.
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 988e69008008..655cb4519d3c 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -219,10 +219,10 @@ public class InsetsSourceConsumerTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
InsetsState state = new InsetsState();
ViewRootInsetsControllerHost host = new ViewRootInsetsControllerHost(mViewRoot);
- InsetsController insetsController = new InsetsController(host, (controller, source) -> {
- if (source.getType() == ime()) {
+ InsetsController insetsController = new InsetsController(host, (ic, id, type) -> {
+ if (type == ime()) {
return new InsetsSourceConsumer(ID_IME, ime(), state,
- () -> mMockTransaction, controller) {
+ () -> mMockTransaction, ic) {
@Override
public int requestShow(boolean fromController,
ImeTracker.Token statsToken) {
@@ -230,11 +230,9 @@ public class InsetsSourceConsumerTest {
}
};
}
- return new InsetsSourceConsumer(source.getId(), source.getType(),
- controller.getState(), Transaction::new, controller);
+ return new InsetsSourceConsumer(id, type, ic.getState(), Transaction::new, ic);
}, host.getHandler());
- InsetsSource imeSource = new InsetsSource(ID_IME, ime());
- InsetsSourceConsumer imeConsumer = insetsController.getSourceConsumer(imeSource);
+ InsetsSourceConsumer imeConsumer = insetsController.getSourceConsumer(ID_IME, ime());
// Initial IME insets source control with its leash.
imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash,
diff --git a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
index 516dee7dc9aa..faccf1ad19a1 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import android.os.BadParcelableException;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
@@ -163,6 +164,45 @@ public class LongArrayMultiStateCounterTest {
}
@Test
+ public void createFromBadBundle() {
+ Parcel data = Parcel.obtain();
+ int bundleLenPos = data.dataPosition();
+ data.writeInt(0);
+ data.writeInt(0x4C444E42); // BaseBundle.BUNDLE_MAGIC
+
+ int bundleStart = data.dataPosition();
+
+ data.writeInt(1);
+ data.writeString("key");
+ data.writeInt(4);
+ int lazyValueLenPos = data.dataPosition();
+ data.writeInt(0);
+ int lazyValueStart = data.dataPosition();
+ data.writeString("com.android.internal.os.LongArrayMultiStateCounter");
+
+ // Invalid int16 value
+ data.writeInt(0x10000); // stateCount
+ data.writeInt(10); // arrayLength
+ for (int i = 0; i < 0x10000; ++i) {
+ data.writeLong(0);
+ }
+
+ backPatchLength(data, lazyValueLenPos, lazyValueStart);
+ backPatchLength(data, bundleLenPos, bundleStart);
+ data.setDataPosition(0);
+
+ assertThrows(BadParcelableException.class,
+ () -> data.readBundle().getParcelable("key", LongArrayMultiStateCounter.class));
+ }
+
+ private static void backPatchLength(Parcel parcel, int lengthPos, int startPos) {
+ int endPos = parcel.dataPosition();
+ parcel.setDataPosition(lengthPos);
+ parcel.writeInt(endPos - startPos);
+ parcel.setDataPosition(endPos);
+ }
+
+ @Test
public void combineValues() {
long[] values = new long[] {0, 1, 2, 3, 42};
LongArrayMultiStateCounter.LongArrayContainer container =
diff --git a/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java
index fc86ebe1c10e..341375357902 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongMultiStateCounterTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import android.os.BadParcelableException;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
@@ -210,4 +211,42 @@ public class LongMultiStateCounterTest {
assertThrows(RuntimeException.class,
() -> LongMultiStateCounter.CREATOR.createFromParcel(parcel));
}
+
+ @Test
+ public void createFromBadBundle() {
+ Parcel data = Parcel.obtain();
+ int bundleLenPos = data.dataPosition();
+ data.writeInt(0);
+ data.writeInt(0x4C444E42); // BaseBundle.BUNDLE_MAGIC
+
+ int bundleStart = data.dataPosition();
+
+ data.writeInt(1);
+ data.writeString("key");
+ data.writeInt(4);
+ int lazyValueLenPos = data.dataPosition();
+ data.writeInt(0);
+ int lazyValueStart = data.dataPosition();
+ data.writeString("com.android.internal.os.LongMultiStateCounter");
+
+ // Invalid int16 value
+ data.writeInt(0x10000); // stateCount
+ for (int i = 0; i < 0x10000; ++i) {
+ data.writeLong(0);
+ }
+
+ backPatchLength(data, lazyValueLenPos, lazyValueStart);
+ backPatchLength(data, bundleLenPos, bundleStart);
+ data.setDataPosition(0);
+
+ assertThrows(BadParcelableException.class,
+ () -> data.readBundle().getParcelable("key", LongMultiStateCounter.class));
+ }
+
+ private static void backPatchLength(Parcel parcel, int lengthPos, int startPos) {
+ int endPos = parcel.dataPosition();
+ parcel.setDataPosition(lengthPos);
+ parcel.writeInt(endPos - startPos);
+ parcel.setDataPosition(endPos);
+ }
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a044602f7ec0..b05507e7e128 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -257,6 +257,7 @@ applications that come with the platform
<permission name="android.permission.CLEAR_APP_CACHE"/>
<permission name="android.permission.ACCESS_INSTANT_APPS" />
<permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
<permission name="android.permission.DELETE_CACHE_FILES"/>
<permission name="android.permission.DELETE_PACKAGES"/>
<permission name="android.permission.DUMP"/>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index b14c3c10846b..08da4857a0b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -1927,6 +1927,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
pw.println(innerPrefix + "mLeash=" + mLeash);
pw.println(innerPrefix + "mState=" + mPipTransitionState.getTransitionState());
pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
+ mPipTransitionController.dump(pw, innerPrefix);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index b8407c465741..e3d53fc415db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -72,6 +72,7 @@ import com.android.wm.shell.transition.CounterRotatorHelper;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.util.TransitionUtil;
+import java.io.PrintWriter;
import java.util.Optional;
/**
@@ -339,19 +340,36 @@ public class PipTransition extends PipTransitionController {
}
// This means an expand happened before enter-pip finished and we are now "merging" a
// no-op transition that happens to match our exit-pip.
+ // Or that the keyguard is up and preventing the transition from applying, in which case we
+ // want to manually reset pip. (b/283783868)
boolean cancelled = false;
if (mPipAnimationController.getCurrentAnimator() != null) {
mPipAnimationController.getCurrentAnimator().cancel();
+ mPipAnimationController.resetAnimatorState();
cancelled = true;
}
+
// Unset exitTransition AFTER cancel so that finishResize knows we are merging.
mExitTransition = null;
- if (!cancelled || aborted) return;
+ if (!cancelled) return;
final ActivityManager.RunningTaskInfo taskInfo = mPipOrganizer.getTaskInfo();
if (taskInfo != null) {
- startExpandAnimation(taskInfo, mPipOrganizer.getSurfaceControl(),
- mPipBoundsState.getBounds(), mPipBoundsState.getBounds(),
- new Rect(mExitDestinationBounds), Surface.ROTATION_0, null /* startT */);
+ if (aborted) {
+ // keyguard case - the transition got aborted, so we want to reset state and
+ // windowing mode before reapplying the resize transaction
+ sendOnPipTransitionFinished(TRANSITION_DIRECTION_LEAVE_PIP);
+ mPipOrganizer.onExitPipFinished(taskInfo);
+
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ mPipOrganizer.applyWindowingModeChangeOnExit(wct, TRANSITION_DIRECTION_LEAVE_PIP);
+ wct.setBounds(taskInfo.token, null);
+ mPipOrganizer.applyFinishBoundsResize(wct, TRANSITION_DIRECTION_LEAVE_PIP, false);
+ } else {
+ // merge case
+ startExpandAnimation(taskInfo, mPipOrganizer.getSurfaceControl(),
+ mPipBoundsState.getBounds(), mPipBoundsState.getBounds(),
+ new Rect(mExitDestinationBounds), Surface.ROTATION_0, null /* startT */);
+ }
}
mExitDestinationBounds.setEmpty();
mCurrentPipTaskToken = null;
@@ -434,6 +452,9 @@ public class PipTransition extends PipTransitionController {
@Override
public void forceFinishTransition() {
+ // mFinishCallback might be null with an outdated mCurrentPipTaskToken
+ // for example, when app crashes while in PiP and exit transition has not started
+ mCurrentPipTaskToken = null;
if (mFinishCallback == null) return;
mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
mFinishCallback = null;
@@ -567,7 +588,16 @@ public class PipTransition extends PipTransitionController {
mPipBoundsState.getDisplayBounds());
mFinishCallback = (wct, wctCB) -> {
mPipOrganizer.onExitPipFinished(taskInfo);
- if (!Transitions.SHELL_TRANSITIONS_ROTATION && toFullscreen) {
+
+ // TODO(b/286346098): remove the OPEN app flicker completely
+ // not checking if we go to fullscreen helps avoid getting pip into an inconsistent
+ // state after the flicker occurs. This is a temp solution until flicker is removed.
+ if (!Transitions.SHELL_TRANSITIONS_ROTATION) {
+ // will help to debug the case when we are not exiting to fullscreen
+ if (!toFullscreen) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: startExitAnimation() not exiting to fullscreen", TAG);
+ }
wct = wct != null ? wct : new WindowContainerTransaction();
wct.setBounds(pipTaskToken, null);
mPipOrganizer.applyWindowingModeChangeOnExit(wct, TRANSITION_DIRECTION_LEAVE_PIP);
@@ -831,7 +861,7 @@ public class PipTransition extends PipTransitionController {
}
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
- final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds();
+ final Rect currentBounds = pipChange.getStartAbsBounds();
int rotationDelta = deltaRotation(startRotation, endRotation);
Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
taskInfo.pictureInPictureParams, currentBounds, destinationBounds);
@@ -856,6 +886,9 @@ public class PipTransition extends PipTransitionController {
final int enterAnimationType = mEnterAnimationType;
if (enterAnimationType == ANIM_TYPE_ALPHA) {
startTransaction.setAlpha(leash, 0f);
+ } else {
+ // set alpha to 1, because for multi-activity PiP it will create a new task with alpha 0
+ startTransaction.setAlpha(leash, 1f);
}
startTransaction.apply();
@@ -1047,7 +1080,7 @@ public class PipTransition extends PipTransitionController {
// When the PIP window is visible and being a part of the transition, such as display
// rotation, we need to update its bounds and rounded corner.
final SurfaceControl leash = pipChange.getLeash();
- final Rect destBounds = mPipBoundsState.getBounds();
+ final Rect destBounds = mPipOrganizer.getCurrentOrAnimatingBounds();
final boolean isInPip = mPipTransitionState.isInPip();
mSurfaceTransactionHelper
.crop(startTransaction, leash, destBounds)
@@ -1108,4 +1141,12 @@ public class PipTransition extends PipTransitionController {
PipMenuController.ALPHA_NO_CHANGE);
mPipMenuController.updateMenuBounds(destinationBounds);
}
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + "mCurrentPipTaskToken=" + mCurrentPipTaskToken);
+ pw.println(innerPrefix + "mFinishCallback=" + mFinishCallback);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index e1bcd70c256b..63627938ec87 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -42,6 +42,7 @@ import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -283,4 +284,9 @@ public abstract class PipTransitionController implements Transitions.TransitionH
*/
void onPipTransitionCanceled(int direction);
}
+
+ /**
+ * Dumps internal states.
+ */
+ public void dump(PrintWriter pw, String prefix) {}
}
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 01d8967c7d60..7699e2f7c13d 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
@@ -2441,6 +2441,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.setFreezeDividerWindow(false);
final StageChangeRecord record = new StageChangeRecord();
+ final int transitType = info.getType();
+ boolean hasEnteringPip = false;
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
final TransitionInfo.Change change = info.getChanges().get(iC);
if (change.getMode() == TRANSIT_CHANGE
@@ -2448,6 +2450,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.update(startTransaction);
}
+ if (mMixedHandler.isEnteringPip(change, transitType)) {
+ hasEnteringPip = true;
+ }
+
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (taskInfo == null) continue;
if (taskInfo.token.equals(mRootTaskInfo.token)) {
@@ -2496,6 +2502,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
}
+
+ if (hasEnteringPip) {
+ mMixedHandler.animatePendingEnterPipFromSplit(transition, info,
+ startTransaction, finishTransaction, finishCallback);
+ return true;
+ }
+
final ArraySet<StageTaskListener> dismissStages = record.getShouldDismissedStage();
if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0
|| dismissStages.size() == 1) {
@@ -2530,8 +2543,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// handling to the mixed-handler to deal with splitting it up.
if (mMixedHandler.animatePendingSplitWithDisplayChange(transition, info,
startTransaction, finishTransaction, finishCallback)) {
- mSplitLayout.update(startTransaction);
- startTransaction.apply();
+ if (mSplitTransitions.isPendingResize(transition)) {
+ // Only need to update in resize because divider exist before transition.
+ mSplitLayout.update(startTransaction);
+ startTransaction.apply();
+ }
return true;
}
}
@@ -2828,18 +2844,24 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
+ final ArrayMap<Integer, SurfaceControl> dismissingTasks = new ArrayMap<>();
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+ if (taskInfo == null) continue;
+ if (getStageOfTask(taskInfo) != null
+ || getSplitItemPosition(change.getLastParent()) != SPLIT_POSITION_UNDEFINED) {
+ dismissingTasks.put(taskInfo.taskId, change.getLeash());
+ }
+ }
+
+
if (shouldBreakPairedTaskInRecents(dismissReason)) {
// Notify recents if we are exiting in a way that breaks the pair, and disable further
// updates to splits in the recents until we enter split again
mRecentTasks.ifPresent(recentTasks -> {
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (taskInfo != null && (getStageOfTask(taskInfo) != null
- || getSplitItemPosition(change.getLastParent())
- != SPLIT_POSITION_UNDEFINED)) {
- recentTasks.removeSplitPair(taskInfo.taskId);
- }
+ for (int i = dismissingTasks.keySet().size() - 1; i >= 0; --i) {
+ recentTasks.removeSplitPair(dismissingTasks.keyAt(i));
}
});
}
@@ -2857,6 +2879,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
t.hide(toStage == STAGE_TYPE_MAIN ? mSideStage.mRootLeash : mMainStage.mRootLeash);
t.setPosition(toStage == STAGE_TYPE_MAIN
? mMainStage.mRootLeash : mSideStage.mRootLeash, 0, 0);
+ } else {
+ for (int i = dismissingTasks.keySet().size() - 1; i >= 0; --i) {
+ finishT.hide(dismissingTasks.valueAt(i));
+ }
}
if (toStage == STAGE_TYPE_UNDEFINED) {
@@ -2866,7 +2892,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
// Hide divider and dim layer on transition finished.
- setDividerVisibility(false, finishT);
+ setDividerVisibility(false, t);
finishT.hide(mMainStage.mDimLayer);
finishT.hide(mSideStage.mDimLayer);
}
@@ -2890,8 +2916,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSideStage.getSplitDecorManager().release(callbackT);
callbackWct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false);
});
-
- addDividerBarToTransition(info, false /* show */);
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index c964df1452e0..c2f15f6cba75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.startingsurface;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.graphics.Color.WHITE;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -77,6 +78,13 @@ public class TaskSnapshotWindow {
@NonNull Runnable clearWindowHandler) {
final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo;
final int taskId = runningTaskInfo.taskId;
+
+ // if we're in PIP we don't want to create the snapshot
+ if (runningTaskInfo.getWindowingMode() == WINDOWING_MODE_PINNED) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
+ "did not create taskSnapshot due to being in PIP");
+ return null;
+ }
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
"create taskSnapshot surface for task: %d", taskId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index e83780a6fc77..d0a361a8ecd2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -25,6 +25,7 @@ import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
import static com.android.wm.shell.util.TransitionUtil.isOpeningType;
@@ -447,7 +448,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
}
finishCallback.onTransitionFinished(mixed.mFinishWCT, wctCB);
};
- if (isGoingHome) {
+ if (isGoingHome || mSplitHandler.getSplitItemPosition(pipChange.getLastParent())
+ != SPLIT_POSITION_UNDEFINED) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is actually mixed "
+ "since entering-PiP caused us to leave split and return home.");
// We need to split the transition into 2 parts: the pip part (animated by pip)
@@ -476,6 +478,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
}
}
+ mPipHandler.setEnterAnimationType(ANIM_TYPE_ALPHA);
mPipHandler.startEnterAnimation(pipChange, startTransaction, finishTransaction,
finishCB);
// Dispatch the rest of the transition normally. This will most-likely be taken by
@@ -516,10 +519,27 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
}
/**
+ * This is intended to be called by SplitCoordinator as a helper to mix a split handling
+ * transition with an entering-pip change. The use-case for this is when an auto-pip change
+ * gets collected into the transition which has already claimed by
+ * StageCoordinator.handleRequest. This happens when launching a fullscreen app while having an
+ * auto-pip activity in the foreground split pair.
+ */
+ // TODO(b/287704263): Remove when split/mixed are reversed.
+ public boolean animatePendingEnterPipFromSplit(IBinder transition, TransitionInfo info,
+ SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
+ Transitions.TransitionFinishCallback finishCallback) {
+ final MixedTransition mixed = new MixedTransition(
+ MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT, transition);
+ mActiveTransitions.add(mixed);
+ return animateEnterPipFromSplit(mixed, info, startT, finishT, finishCallback);
+ }
+
+ /**
* This is intended to be called by SplitCoordinator as a helper to mix an already-pending
* split transition with a display-change. The use-case for this is when a display
* change/rotation gets collected into a split-screen enter/exit transition which has already
- * been claimed by StageCoordinator.handleRequest . This happens during launcher tests.
+ * been claimed by StageCoordinator.handleRequest. This happens during launcher tests.
*/
public boolean animatePendingSplitWithDisplayChange(@NonNull IBinder transition,
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startT,
@@ -657,6 +677,13 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
return mPipHandler.requestHasPipEnter(request);
}
+ /** Whether a particular change is a window that is entering pip. */
+ // TODO(b/287704263): Remove when split/mixed are reversed.
+ public boolean isEnteringPip(TransitionInfo.Change change,
+ @WindowManager.TransitionType int transitType) {
+ return mPipHandler.isEnteringPip(change, transitType);
+ }
+
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 3b05651f884b..44c76de945b0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -75,6 +75,7 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
+import com.android.wm.shell.transition.DefaultMixedHandler;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -101,6 +102,7 @@ public class SplitTransitionTests extends ShellTestCase {
@Mock private SurfaceSession mSurfaceSession;
@Mock private IconProvider mIconProvider;
@Mock private ShellExecutor mMainExecutor;
+ @Mock private DefaultMixedHandler mMixedHandler;
private SplitLayout mSplitLayout;
private MainStage mMainStage;
private SideStage mSideStage;
@@ -131,6 +133,7 @@ public class SplitTransitionTests extends ShellTestCase {
mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
mTransactionPool, mMainExecutor, Optional.empty());
+ mStageCoordinator.setMixedHandler(mMixedHandler);
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
.when(mTransitions).startTransition(anyInt(), any(), any());
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
index 26efb55fa560..473603002b21 100644
--- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
@@ -111,8 +111,14 @@ class LowLightTransitionCoordinator @Inject constructor() {
}
animator.addListener(listener)
continuation.invokeOnCancellation {
- animator.removeListener(listener)
- animator.cancel()
+ try {
+ animator.removeListener(listener)
+ animator.cancel()
+ } catch (exception: IndexOutOfBoundsException) {
+ // TODO(b/285666217): remove this try/catch once a proper fix is implemented.
+ // Cancelling the animator can cause an exception since we may be removing a
+ // listener during the cancellation. See b/285666217 for more details.
+ }
}
}
}
diff --git a/libs/hwui/jni/BitmapRegionDecoder.cpp b/libs/hwui/jni/BitmapRegionDecoder.cpp
index 4c9a23d3fde0..740988f77270 100644
--- a/libs/hwui/jni/BitmapRegionDecoder.cpp
+++ b/libs/hwui/jni/BitmapRegionDecoder.cpp
@@ -90,8 +90,8 @@ public:
requireUnpremul, prefColorSpace);
}
- bool decodeGainmapRegion(sp<uirenderer::Gainmap>* outGainmap, const SkIRect& desiredSubset,
- int sampleSize, bool requireUnpremul) {
+ bool decodeGainmapRegion(sp<uirenderer::Gainmap>* outGainmap, int outWidth, int outHeight,
+ const SkIRect& desiredSubset, int sampleSize, bool requireUnpremul) {
SkColorType decodeColorType = mGainmapBRD->computeOutputColorType(kN32_SkColorType);
sk_sp<SkColorSpace> decodeColorSpace =
mGainmapBRD->computeOutputColorSpace(decodeColorType, nullptr);
@@ -109,9 +109,8 @@ public:
// kPremul_SkAlphaType is used just as a placeholder as it doesn't change the underlying
// allocation type. RecyclingClippingPixelAllocator will populate this with the
// actual alpha type in either allocPixelRef() or copyIfNecessary()
- sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(
- SkImageInfo::Make(desiredSubset.width(), desiredSubset.height(), decodeColorType,
- kPremul_SkAlphaType, decodeColorSpace));
+ sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(SkImageInfo::Make(
+ outWidth, outHeight, decodeColorType, kPremul_SkAlphaType, decodeColorSpace));
if (!nativeBitmap) {
ALOGE("OOM allocating Bitmap for Gainmap");
return false;
@@ -134,9 +133,12 @@ public:
return true;
}
- SkIRect calculateGainmapRegion(const SkIRect& mainImageRegion) {
+ SkIRect calculateGainmapRegion(const SkIRect& mainImageRegion, int* inOutWidth,
+ int* inOutHeight) {
const float scaleX = ((float)mGainmapBRD->width()) / mMainImageBRD->width();
const float scaleY = ((float)mGainmapBRD->height()) / mMainImageBRD->height();
+ *inOutWidth *= scaleX;
+ *inOutHeight *= scaleY;
// TODO: Account for rounding error?
return SkIRect::MakeLTRB(mainImageRegion.left() * scaleX, mainImageRegion.top() * scaleY,
mainImageRegion.right() * scaleX,
@@ -328,21 +330,16 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in
sp<uirenderer::Gainmap> gainmap;
bool hasGainmap = brd->hasGainmap();
if (hasGainmap) {
- SkIRect adjustedSubset{};
+ int gainmapWidth = bitmap.width();
+ int gainmapHeight = bitmap.height();
if (javaBitmap) {
- // Clamp to the width/height of the recycled bitmap in case the reused bitmap
- // was too small for the specified rectangle, in which case we need to clip
- adjustedSubset = SkIRect::MakeXYWH(inputX, inputY,
- std::min(subset.width(), recycledBitmap->width()),
- std::min(subset.height(), recycledBitmap->height()));
- } else {
- // We are not recycling, so use the decoded width/height for calculating the gainmap
- // subset instead to ensure the gainmap region proportionally matches
- adjustedSubset = SkIRect::MakeXYWH(std::max(0, inputX), std::max(0, inputY),
- bitmap.width(), bitmap.height());
+ // If we are recycling we must match the inBitmap's relative dimensions
+ gainmapWidth = recycledBitmap->width();
+ gainmapHeight = recycledBitmap->height();
}
- SkIRect gainmapSubset = brd->calculateGainmapRegion(adjustedSubset);
- if (!brd->decodeGainmapRegion(&gainmap, gainmapSubset, sampleSize, requireUnpremul)) {
+ SkIRect gainmapSubset = brd->calculateGainmapRegion(subset, &gainmapWidth, &gainmapHeight);
+ if (!brd->decodeGainmapRegion(&gainmap, gainmapWidth, gainmapHeight, gainmapSubset,
+ sampleSize, requireUnpremul)) {
// If there is an error decoding Gainmap - we don't fail. We just don't provide Gainmap
hasGainmap = false;
}
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index d4e919fefbbd..46698a6fdcc0 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -40,7 +40,7 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-static std::array<std::string_view, 19> sEnableExtensions{
+static std::array<std::string_view, 20> sEnableExtensions{
VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
@@ -60,6 +60,7 @@ static std::array<std::string_view, 19> sEnableExtensions{
VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
+ VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME,
};
static bool shouldEnableExtension(const std::string_view& extension) {
@@ -657,7 +658,6 @@ void VulkanManager::destroySurface(VulkanSurface* surface) {
if (VK_NULL_HANDLE != mGraphicsQueue) {
mQueueWaitIdle(mGraphicsQueue);
}
- mDeviceWaitIdle(mDevice);
delete surface;
}
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 0e9c162e4929..651c732abdb8 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -156,6 +156,7 @@ public final class MediaRoute2Info implements Parcelable {
TYPE_REMOTE_GAME_CONSOLE,
TYPE_REMOTE_CAR,
TYPE_REMOTE_SMARTWATCH,
+ TYPE_REMOTE_SMARTPHONE,
TYPE_GROUP
})
@Retention(RetentionPolicy.SOURCE)
@@ -343,6 +344,17 @@ public final class MediaRoute2Info implements Parcelable {
public static final int TYPE_REMOTE_SMARTWATCH = 1009;
/**
+ * Indicates the route is a remote smartphone.
+ *
+ * <p>A remote device uses a routing protocol managed by the application, as opposed to the
+ * routing being done by the system.
+ *
+ * @see #getType
+ * @hide
+ */
+ public static final int TYPE_REMOTE_SMARTPHONE = 1010;
+
+ /**
* Indicates the route is a group of devices.
*
* @see #getType
@@ -546,32 +558,8 @@ public final class MediaRoute2Info implements Parcelable {
return mFeatures;
}
- // TODO (b/278728942): Add the following once the symbols are published in the SDK. Until then,
- // adding them would cause the generated link to be broken.
- // @see #TYPE_REMOTE_TABLET
- // @see #TYPE_REMOTE_TABLET_DOCKED
- // @see #TYPE_REMOTE_COMPUTER
- // @see #TYPE_REMOTE_GAME_CONSOLE
- // @see #TYPE_REMOTE_CAR
- // @see #TYPE_REMOTE_SMARTWATCH
/**
* Returns the type of this route.
- *
- * @see #TYPE_UNKNOWN
- * @see #TYPE_BUILTIN_SPEAKER
- * @see #TYPE_WIRED_HEADSET
- * @see #TYPE_WIRED_HEADPHONES
- * @see #TYPE_BLUETOOTH_A2DP
- * @see #TYPE_HDMI
- * @see #TYPE_DOCK
- * @see #TYPE_USB_DEVICE
- * @see #TYPE_USB_ACCESSORY
- * @see #TYPE_USB_HEADSET
- * @see #TYPE_HEARING_AID
- * @see #TYPE_REMOTE_TV
- * @see #TYPE_REMOTE_SPEAKER
- * @see #TYPE_REMOTE_AUDIO_VIDEO_RECEIVER
- * @see #TYPE_GROUP
*/
@Type
public int getType() {
@@ -954,6 +942,8 @@ public final class MediaRoute2Info implements Parcelable {
return "REMOTE_CAR";
case TYPE_REMOTE_SMARTWATCH:
return "REMOTE_SMARTWATCH";
+ case TYPE_REMOTE_SMARTPHONE:
+ return "REMOTE_SMARTPHONE";
case TYPE_GROUP:
return "GROUP";
case TYPE_UNKNOWN:
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 29e8716f08ac..6121b8837f4f 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -267,17 +267,22 @@ public final class MediaSession {
}
/**
- * Set a pending intent for your media button receiver to allow restarting
- * playback after the session has been stopped. If your app is started in
- * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
- * the pending intent.
- * <p>
- * The pending intent is recommended to be explicit to follow the security recommendation of
- * {@link PendingIntent#getActivity}.
+ * Set a pending intent for your media button receiver to allow restarting playback after the
+ * session has been stopped.
+ *
+ * <p>If your app is started in this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be
+ * sent via the pending intent.
+ *
+ * <p>The provided {@link PendingIntent} must not target an activity. Passing an activity
+ * pending intent will cause the call to be ignored. Refer to this <a
+ * href="https://developer.android.com/guide/components/activities/background-starts">guide</a>
+ * for more information.
+ *
+ * <p>The pending intent is recommended to be explicit to follow the security recommendation of
+ * {@link PendingIntent#getService}.
*
* @param mbr The {@link PendingIntent} to send the media button event to.
* @see PendingIntent#getActivity
- *
* @deprecated Use {@link #setMediaButtonBroadcastReceiver(ComponentName)} instead.
*/
@Deprecated
@@ -285,7 +290,7 @@ public final class MediaSession {
try {
mBinder.setMediaButtonReceiver(mbr);
} catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
+ e.rethrowFromSystemServer();
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index b86eec04d542..8361877744cf 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -68,11 +68,12 @@ fun getAppLabel(
): String? {
return try {
val pkgInfo = pm.getPackageInfo(appPackageName, PackageManager.PackageInfoFlags.of(0))
- pkgInfo.applicationInfo.loadSafeLabel(
+ val applicationInfo = checkNotNull(pkgInfo.applicationInfo)
+ applicationInfo.loadSafeLabel(
pm, 0f,
TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM
).toString()
- } catch (e: PackageManager.NameNotFoundException) {
+ } catch (e: Exception) {
Log.e(Constants.LOG_TAG, "Caller app not found", e)
null
}
@@ -93,13 +94,14 @@ private fun getServiceLabelAndIcon(
providerFlattenedComponentName,
PackageManager.PackageInfoFlags.of(0)
)
+ val applicationInfo = checkNotNull(pkgInfo.applicationInfo)
providerLabel =
- pkgInfo.applicationInfo.loadSafeLabel(
+ applicationInfo.loadSafeLabel(
pm, 0f,
TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM
).toString()
- providerIcon = pkgInfo.applicationInfo.loadIcon(pm)
- } catch (e: PackageManager.NameNotFoundException) {
+ providerIcon = applicationInfo.loadIcon(pm)
+ } catch (e: Exception) {
Log.e(Constants.LOG_TAG, "Provider package info not found", e)
}
} else {
@@ -119,13 +121,14 @@ private fun getServiceLabelAndIcon(
component.packageName,
PackageManager.PackageInfoFlags.of(0)
)
+ val applicationInfo = checkNotNull(pkgInfo.applicationInfo)
providerLabel =
- pkgInfo.applicationInfo.loadSafeLabel(
+ applicationInfo.loadSafeLabel(
pm, 0f,
TextUtils.SAFE_STRING_FLAG_FIRST_LINE or TextUtils.SAFE_STRING_FLAG_TRIM
).toString()
- providerIcon = pkgInfo.applicationInfo.loadIcon(pm)
- } catch (e: PackageManager.NameNotFoundException) {
+ providerIcon = applicationInfo.loadIcon(pm)
+ } catch (e: Exception) {
Log.e(Constants.LOG_TAG, "Provider package info not found", e)
}
}
diff --git a/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt b/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt
index 5fa61373a686..562f7be5ae1e 100644
--- a/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt
+++ b/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt
@@ -293,7 +293,7 @@ class ClueView(context: Context) : View(context) {
return correct
}
- override fun onDraw(canvas: Canvas?) {
+ override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
if (!showText) return
canvas?.let {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
index 0f5862a9829d..afce16c530c7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
@@ -24,7 +24,7 @@ import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.VisibleForTesting
-import androidx.compose.animation.AnimatedContentScope
+import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
@@ -146,22 +146,26 @@ private fun NavControllerWrapperImpl.NavContent(
arguments = spp.parameter,
enterTransition = {
slideIntoContainer(
- AnimatedContentScope.SlideDirection.Start, animationSpec = slideEffect
+ AnimatedContentTransitionScope.SlideDirection.Start,
+ animationSpec = slideEffect
) + fadeIn(animationSpec = fadeEffect)
},
exitTransition = {
slideOutOfContainer(
- AnimatedContentScope.SlideDirection.Start, animationSpec = slideEffect
+ AnimatedContentTransitionScope.SlideDirection.Start,
+ animationSpec = slideEffect
) + fadeOut(animationSpec = fadeEffect)
},
popEnterTransition = {
slideIntoContainer(
- AnimatedContentScope.SlideDirection.End, animationSpec = slideEffect
+ AnimatedContentTransitionScope.SlideDirection.End,
+ animationSpec = slideEffect
) + fadeIn(animationSpec = fadeEffect)
},
popExitTransition = {
slideOutOfContainer(
- AnimatedContentScope.SlideDirection.End, animationSpec = slideEffect
+ AnimatedContentTransitionScope.SlideDirection.End,
+ animationSpec = slideEffect
) + fadeOut(animationSpec = fadeEffect)
},
) { navBackStackEntry ->
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/AnimatedNavHost.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/AnimatedNavHost.kt
index 57bb838d55ea..81bbc2456577 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/AnimatedNavHost.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/AnimatedNavHost.kt
@@ -18,7 +18,7 @@ package com.android.settingslib.spa.framework.compose
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.animation.AnimatedContent
-import androidx.compose.animation.AnimatedContentScope
+import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
@@ -78,14 +78,10 @@ public fun AnimatedNavHost(
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.Center,
route: String? = null,
- enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition) =
- { fadeIn(animationSpec = tween(700)) },
- exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition) =
- { fadeOut(animationSpec = tween(700)) },
- popEnterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition) =
- enterTransition,
- popExitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition) =
- exitTransition,
+ enterTransition: (AnimatedScope.() -> EnterTransition) = { fadeIn(animationSpec = tween(700)) },
+ exitTransition: (AnimatedScope.() -> ExitTransition) = { fadeOut(animationSpec = tween(700)) },
+ popEnterTransition: (AnimatedScope.() -> EnterTransition) = enterTransition,
+ popExitTransition: (AnimatedScope.() -> ExitTransition) = exitTransition,
builder: NavGraphBuilder.() -> Unit
) {
AnimatedNavHost(
@@ -123,14 +119,10 @@ public fun AnimatedNavHost(
graph: NavGraph,
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.Center,
- enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition) =
- { fadeIn(animationSpec = tween(700)) },
- exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition) =
- { fadeOut(animationSpec = tween(700)) },
- popEnterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition) =
- enterTransition,
- popExitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition) =
- exitTransition,
+ enterTransition: (AnimatedScope.() -> EnterTransition) = { fadeIn(animationSpec = tween(700)) },
+ exitTransition: (AnimatedScope.() -> ExitTransition) = { fadeOut(animationSpec = tween(700)) },
+ popEnterTransition: (AnimatedScope.() -> EnterTransition) = enterTransition,
+ popExitTransition: (AnimatedScope.() -> ExitTransition) = exitTransition,
) {
val lifecycleOwner = LocalLifecycleOwner.current
@@ -168,7 +160,7 @@ public fun AnimatedNavHost(
val backStackEntry = visibleEntries.lastOrNull()
if (backStackEntry != null) {
- val finalEnter: AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition = {
+ val finalEnter: AnimatedScope.() -> EnterTransition = {
val targetDestination = targetState.destination as AnimatedComposeNavigator.Destination
if (composeNavigator.isPop.value) {
@@ -182,7 +174,7 @@ public fun AnimatedNavHost(
}
}
- val finalExit: AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition = {
+ val finalExit: AnimatedScope.() -> ExitTransition = {
val initialDestination =
initialState.destination as AnimatedComposeNavigator.Destination
@@ -245,19 +237,16 @@ public fun AnimatedNavHost(
DialogHost(dialogNavigator)
}
-@ExperimentalAnimationApi
-internal val enterTransitions =
- mutableMapOf<String?,
- (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)?>()
+@OptIn(ExperimentalAnimationApi::class)
+internal typealias AnimatedScope = AnimatedContentTransitionScope<NavBackStackEntry>
@ExperimentalAnimationApi
-internal val exitTransitions =
- mutableMapOf<String?, (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)?>()
+internal val enterTransitions = mutableMapOf<String?, (AnimatedScope.() -> EnterTransition?)?>()
@ExperimentalAnimationApi
-internal val popEnterTransitions =
- mutableMapOf<String?, (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)?>()
+internal val exitTransitions = mutableMapOf<String?, (AnimatedScope.() -> ExitTransition?)?>()
+@ExperimentalAnimationApi
+internal val popEnterTransitions = mutableMapOf<String?, (AnimatedScope.() -> EnterTransition?)?>()
@ExperimentalAnimationApi
-internal val popExitTransitions =
- mutableMapOf<String?, (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)?>()
+internal val popExitTransitions = mutableMapOf<String?, (AnimatedScope.() -> ExitTransition?)?>()
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavGraphBuilder.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavGraphBuilder.kt
index 9e58603bbaff..bf92f5dda1a9 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavGraphBuilder.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavGraphBuilder.kt
@@ -16,7 +16,6 @@
package com.android.settingslib.spa.framework.compose
-import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
@@ -25,9 +24,7 @@ import androidx.compose.runtime.Composable
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDeepLink
-import androidx.navigation.NavGraph
import androidx.navigation.NavGraphBuilder
-import androidx.navigation.compose.navigation
import androidx.navigation.get
/**
@@ -47,14 +44,10 @@ public fun NavGraphBuilder.composable(
route: String,
arguments: List<NamedNavArgument> = emptyList(),
deepLinks: List<NavDeepLink> = emptyList(),
- enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)? = null,
- exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)? = null,
- popEnterTransition: (
- AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?
- )? = enterTransition,
- popExitTransition: (
- AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?
- )? = exitTransition,
+ enterTransition: (AnimatedScope.() -> EnterTransition?)? = null,
+ exitTransition: (AnimatedScope.() -> ExitTransition?)? = null,
+ popEnterTransition: (AnimatedScope.() -> EnterTransition?)? = enterTransition,
+ popExitTransition: (AnimatedScope.() -> ExitTransition?)? = exitTransition,
content: @Composable AnimatedVisibilityScope.(NavBackStackEntry) -> Unit
) {
addDestination(
@@ -76,43 +69,3 @@ public fun NavGraphBuilder.composable(
}
)
}
-
-/**
- * Construct a nested [NavGraph]
- *
- * @param startDestination the starting destination's route for this NavGraph
- * @param route the destination's unique route
- * @param arguments list of arguments to associate with destination
- * @param deepLinks list of deep links to associate with the destinations
- * @param enterTransition callback to define enter transitions for destination in this NavGraph
- * @param exitTransition callback to define exit transitions for destination in this NavGraph
- * @param popEnterTransition callback to define pop enter transitions for destination in this
- * NavGraph
- * @param popExitTransition callback to define pop exit transitions for destination in this NavGraph
- * @param builder the builder used to construct the graph
- *
- * @return the newly constructed nested NavGraph
- */
-@ExperimentalAnimationApi
-public fun NavGraphBuilder.navigation(
- startDestination: String,
- route: String,
- arguments: List<NamedNavArgument> = emptyList(),
- deepLinks: List<NavDeepLink> = emptyList(),
- enterTransition: (AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?)? = null,
- exitTransition: (AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?)? = null,
- popEnterTransition: (
- AnimatedContentScope<NavBackStackEntry>.() -> EnterTransition?
- )? = enterTransition,
- popExitTransition: (
- AnimatedContentScope<NavBackStackEntry>.() -> ExitTransition?
- )? = exitTransition,
- builder: NavGraphBuilder.() -> Unit
-) {
- navigation(startDestination, route, arguments, deepLinks, builder).apply {
- enterTransition?.let { enterTransitions[route] = enterTransition }
- exitTransition?.let { exitTransitions[route] = exitTransition }
- popEnterTransition?.let { popEnterTransitions[route] = popEnterTransition }
- popExitTransition?.let { popExitTransitions[route] = popExitTransition }
- }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
index 79635a0c8280..aa148b022b92 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsPager.kt
@@ -20,20 +20,12 @@ import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
-import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.TabRow
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.platform.LocalConfiguration
import com.android.settingslib.spa.framework.theme.SettingsDimension
import kotlin.math.absoluteValue
import kotlinx.coroutines.launch
@@ -49,7 +41,7 @@ fun SettingsPager(titles: List<String>, content: @Composable (page: Int) -> Unit
Column {
val coroutineScope = rememberCoroutineScope()
- val pagerState = rememberPageStateFixed()
+ val pagerState = rememberPagerState { titles.size }
TabRow(
selectedTabIndex = pagerState.currentPage,
@@ -72,46 +64,8 @@ fun SettingsPager(titles: List<String>, content: @Composable (page: Int) -> Unit
}
}
- HorizontalPager(pageCount = titles.size, state = pagerState) { page ->
+ HorizontalPager(state = pagerState) { page ->
content(page)
}
}
}
-
-/**
- * Gets the state of [PagerState].
- *
- * This is a work around.
- *
- * TODO: Remove this and replace with rememberPageState() after the Compose Foundation 1.5.0-alpha04
- * updated in the platform.
- */
-@Composable
-@OptIn(ExperimentalFoundationApi::class)
-private fun rememberPageStateFixed(): PagerState {
- var currentPage by rememberSaveable { mutableStateOf(0) }
- var targetPage by rememberSaveable { mutableStateOf(-1) }
- val pagerState = rememberPagerState()
- val configuration = LocalConfiguration.current
- var lastScreenWidthDp by rememberSaveable { mutableStateOf(-1) }
- val screenWidthDp = configuration.screenWidthDp
- LaunchedEffect(screenWidthDp) {
- // Reset pager state to fix an issue after configuration change.
- // When we declare android:configChanges in the manifest, the pager state is in a weird
- // state after configuration change.
- targetPage = currentPage
- lastScreenWidthDp = screenWidthDp
- }
- LaunchedEffect(targetPage) {
- if (targetPage != -1) {
- pagerState.scrollToPage(targetPage)
- targetPage = -1
- }
- }
- SideEffect {
- if (lastScreenWidthDp == screenWidthDp) {
- currentPage = pagerState.currentPage
- }
- }
- return pagerState
-}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
index 2b38b4cefe3e..657c391da7c2 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
@@ -75,6 +75,7 @@ internal class AppListRepositoryImpl(private val context: Context) : AppListRepo
packageManager.getInstalledModules(0)
.filter { it.isHidden }
.map { it.packageName }
+ .filterNotNull()
.toSet()
}
val hideWhenDisabledPackagesDeferred = async {
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt
index 69c6131679a9..92fd0cd07777 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/PackageManagers.kt
@@ -82,7 +82,8 @@ internal class PackageManagersImpl(
val packageInfo = getPackageInfoAsUser(packageName, PackageManager.GET_PERMISSIONS, userId)
val index = packageInfo?.requestedPermissions?.indexOf(permission) ?: return false
return index >= 0 &&
- packageInfo.requestedPermissionsFlags[index].hasFlag(REQUESTED_PERMISSION_GRANTED)
+ checkNotNull(packageInfo.requestedPermissionsFlags)[index]
+ .hasFlag(REQUESTED_PERMISSION_GRANTED)
}
override suspend fun getAppOpPermissionPackages(userId: Int, permission: String): Set<String> =
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt
index fab3ae8e510b..20beec73c958 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/EnterpriseRepository.kt
@@ -28,7 +28,7 @@ class EnterpriseRepository(private val context: Context) {
}
fun getEnterpriseString(updatableStringId: String, resId: Int): String =
- resources.getString(updatableStringId) { context.getString(resId) }
+ checkNotNull(resources.getString(updatableStringId) { context.getString(resId) })
fun getProfileTitle(isManagedProfile: Boolean): String = if (isManagedProfile) {
getEnterpriseString(WORK_CATEGORY_HEADER, R.string.category_work)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
index ae362c894e6d..481555651398 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
@@ -22,7 +22,6 @@ import android.os.UserHandle
import android.os.UserManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
-import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settingslib.RestrictedLockUtils
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
@@ -86,7 +85,6 @@ internal class RestrictionsProviderImpl(
emit(getRestrictedMode())
}.flowOn(Dispatchers.IO)
- @OptIn(ExperimentalLifecycleComposeApi::class)
@Composable
override fun restrictedModeState() =
restrictedMode.collectAsStateWithLifecycle(initialValue = null)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
index a0ff216875a2..55a438f1f1fd 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
@@ -55,7 +55,7 @@ class AppInfoProvider(private val packageInfo: PackageInfo) {
.semantics(mergeDescendants = true) {},
horizontalAlignment = Alignment.CenterHorizontally,
) {
- val app = packageInfo.applicationInfo
+ val app = checkNotNull(packageInfo.applicationInfo)
Box(modifier = Modifier.padding(SettingsDimension.itemPaddingAround)) {
AppIcon(app = app, size = SettingsDimension.appIconInfoSize)
}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
index 7c689c62427e..1a627409632e 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
@@ -144,7 +144,7 @@ internal fun TogglePermissionAppListModel<out AppRecord>.TogglePermissionAppInfo
footerContent = footerContent(),
packageManagers = packageManagers,
) {
- val model = createSwitchModel(applicationInfo)
+ val model = createSwitchModel(checkNotNull(applicationInfo))
val restrictions = Restrictions(userId, switchRestrictionKeys)
RestrictedSwitchPreference(model, restrictions, restrictionsProviderFactory)
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index b5e4fa38d244..af06d7304160 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -243,7 +243,9 @@ public class RestrictedSwitchPreference extends SwitchPreference {
return mHelper != null ? mHelper.packageName : null;
}
- public void updateState(@NonNull String packageName, int uid, boolean isEnabled) {
+ /** Updates enabled state based on associated package. */
+ public void updateState(
+ @NonNull String packageName, int uid, boolean isEnableAllowed, boolean isEnabled) {
mHelper.updatePackageDetails(packageName, uid);
if (mAppOpsManager == null) {
mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
@@ -254,7 +256,9 @@ public class RestrictedSwitchPreference extends SwitchPreference {
final boolean ecmEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enhancedConfirmationModeEnabled);
final boolean appOpsAllowed = !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED;
- if (isEnabled) {
+ if (!isEnableAllowed && !isEnabled) {
+ setEnabled(false);
+ } else if (isEnabled) {
setEnabled(true);
} else if (appOpsAllowed && isDisabledByAppOps()) {
setEnabled(true);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index cd6609ec463e..963bd9daa975 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -15,6 +15,8 @@
*/
package com.android.settingslib.media;
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
+
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
@@ -22,6 +24,7 @@ import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
+import android.media.RouteListingPreference;
import com.android.settingslib.R;
import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -39,7 +42,13 @@ public class BluetoothMediaDevice extends MediaDevice {
BluetoothMediaDevice(Context context, CachedBluetoothDevice device,
MediaRouter2Manager routerManager, MediaRoute2Info info, String packageName) {
- super(context, routerManager, info, packageName, null);
+ this(context, device, routerManager, info, packageName, null);
+ }
+
+ BluetoothMediaDevice(Context context, CachedBluetoothDevice device,
+ MediaRouter2Manager routerManager, MediaRoute2Info info, String packageName,
+ RouteListingPreference.Item item) {
+ super(context, routerManager, info, packageName, item);
mCachedDevice = device;
mAudioManager = context.getSystemService(AudioManager.class);
initDeviceRecord();
@@ -58,6 +67,12 @@ public class BluetoothMediaDevice extends MediaDevice {
}
@Override
+ public int getSelectionBehavior() {
+ // We don't allow apps to override the selection behavior of system routes.
+ return SELECTION_BEHAVIOR_TRANSFER;
+ }
+
+ @Override
public Drawable getIcon() {
return BluetoothUtils.isAdvancedUntetheredDevice(mCachedDevice.getDevice())
? mContext.getDrawable(R.drawable.ic_earbuds_advanced)
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 632120e77c87..b10d7946f57f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -19,6 +19,7 @@ import static android.media.MediaRoute2Info.TYPE_GROUP;
import static android.media.MediaRoute2Info.TYPE_REMOTE_CAR;
import static android.media.MediaRoute2Info.TYPE_REMOTE_COMPUTER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_GAME_CONSOLE;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_SMARTPHONE;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SMARTWATCH;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_TABLET;
@@ -103,6 +104,9 @@ public class InfoMediaDevice extends MediaDevice {
case TYPE_REMOTE_SMARTWATCH:
resId = R.drawable.ic_media_smartwatch;
break;
+ case TYPE_REMOTE_SMARTPHONE:
+ resId = R.drawable.ic_smartphone;
+ break;
case TYPE_REMOTE_SPEAKER:
default:
resId = R.drawable.ic_media_speaker_device;
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index ffc0479f01c3..1728e405fa29 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -26,6 +26,7 @@ import static android.media.MediaRoute2Info.TYPE_REMOTE_AUDIO_VIDEO_RECEIVER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_CAR;
import static android.media.MediaRoute2Info.TYPE_REMOTE_COMPUTER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_GAME_CONSOLE;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_SMARTPHONE;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SMARTWATCH;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_TABLET;
@@ -90,6 +91,7 @@ public class InfoMediaManager extends MediaManager {
MediaRouter2Manager mRouterManager;
@VisibleForTesting
String mPackageName;
+ boolean mIsScanning = false;
private MediaDevice mCurrentConnectedDevice;
private LocalBluetoothManager mBluetoothManager;
@@ -109,22 +111,29 @@ public class InfoMediaManager extends MediaManager {
@Override
public void startScan() {
- mMediaDevices.clear();
- mRouterManager.registerCallback(mExecutor, mMediaRouterCallback);
- mRouterManager.registerScanRequest();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
- && !TextUtils.isEmpty(mPackageName)) {
- RouteListingPreference routeListingPreference =
- mRouterManager.getRouteListingPreference(mPackageName);
- Api34Impl.onRouteListingPreferenceUpdated(routeListingPreference, mPreferenceItemMap);
+ if (!mIsScanning) {
+ mMediaDevices.clear();
+ mRouterManager.registerCallback(mExecutor, mMediaRouterCallback);
+ mRouterManager.registerScanRequest();
+ mIsScanning = true;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+ && !TextUtils.isEmpty(mPackageName)) {
+ RouteListingPreference routeListingPreference =
+ mRouterManager.getRouteListingPreference(mPackageName);
+ Api34Impl.onRouteListingPreferenceUpdated(routeListingPreference,
+ mPreferenceItemMap);
+ }
+ refreshDevices();
}
- refreshDevices();
}
@Override
public void stopScan() {
- mRouterManager.unregisterCallback(mMediaRouterCallback);
- mRouterManager.unregisterScanRequest();
+ if (mIsScanning) {
+ mRouterManager.unregisterCallback(mMediaRouterCallback);
+ mRouterManager.unregisterScanRequest();
+ mIsScanning = false;
+ }
}
/**
@@ -547,6 +556,7 @@ public class InfoMediaManager extends MediaManager {
case TYPE_REMOTE_GAME_CONSOLE:
case TYPE_REMOTE_CAR:
case TYPE_REMOTE_SMARTWATCH:
+ case TYPE_REMOTE_SMARTPHONE:
mediaDevice = new InfoMediaDevice(mContext, mRouterManager, route,
mPackageName, mPreferenceItemMap.get(route.getId()));
break;
@@ -558,8 +568,10 @@ public class InfoMediaManager extends MediaManager {
case TYPE_HDMI:
case TYPE_WIRED_HEADSET:
case TYPE_WIRED_HEADPHONES:
- mediaDevice =
- new PhoneMediaDevice(mContext, mRouterManager, route, mPackageName);
+ mediaDevice = mPreferenceItemMap.containsKey(route.getId()) ? new PhoneMediaDevice(
+ mContext, mRouterManager, route, mPackageName,
+ mPreferenceItemMap.get(route.getId())) : new PhoneMediaDevice(mContext,
+ mRouterManager, route, mPackageName);
break;
case TYPE_HEARING_AID:
case TYPE_BLUETOOTH_A2DP:
@@ -569,8 +581,11 @@ public class InfoMediaManager extends MediaManager {
final CachedBluetoothDevice cachedDevice =
mBluetoothManager.getCachedDeviceManager().findDevice(device);
if (cachedDevice != null) {
- mediaDevice = new BluetoothMediaDevice(mContext, cachedDevice, mRouterManager,
- route, mPackageName);
+ mediaDevice = mPreferenceItemMap.containsKey(route.getId())
+ ? new BluetoothMediaDevice(mContext, cachedDevice, mRouterManager,
+ route, mPackageName, mPreferenceItemMap.get(route.getId()))
+ : new BluetoothMediaDevice(mContext, cachedDevice, mRouterManager,
+ route, mPackageName);
}
break;
case TYPE_REMOTE_AUDIO_VIDEO_RECEIVER:
@@ -699,20 +714,19 @@ public class InfoMediaManager extends MediaManager {
List<MediaRoute2Info> selectedRouteInfos, List<MediaRoute2Info> infolist,
List<RouteListingPreference.Item> preferenceRouteListing) {
final List<MediaRoute2Info> sortedInfoList = new ArrayList<>(selectedRouteInfos);
+ infolist.removeAll(selectedRouteInfos);
+ sortedInfoList.addAll(infolist.stream().filter(
+ MediaRoute2Info::isSystemRoute).collect(Collectors.toList()));
for (RouteListingPreference.Item item : preferenceRouteListing) {
for (MediaRoute2Info info : infolist) {
if (item.getRouteId().equals(info.getId())
- && !selectedRouteInfos.contains(info)) {
+ && !selectedRouteInfos.contains(info)
+ && !info.isSystemRoute()) {
sortedInfoList.add(info);
break;
}
}
}
- if (sortedInfoList.size() != infolist.size()) {
- infolist.removeAll(sortedInfoList);
- sortedInfoList.addAll(infolist.stream().filter(
- MediaRoute2Info::isSystemRoute).collect(Collectors.toList()));
- }
return sortedInfoList;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 34519c993d27..accd88c2bfe3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -24,10 +24,13 @@ import static android.media.MediaRoute2Info.TYPE_USB_HEADSET;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
+
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
+import android.media.RouteListingPreference;
import androidx.annotation.VisibleForTesting;
@@ -51,7 +54,12 @@ public class PhoneMediaDevice extends MediaDevice {
PhoneMediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
String packageName) {
- super(context, routerManager, info, packageName, null);
+ this(context, routerManager, info, packageName, null);
+ }
+
+ PhoneMediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
+ String packageName, RouteListingPreference.Item item) {
+ super(context, routerManager, info, packageName, item);
mDeviceIconUtil = new DeviceIconUtil();
initDeviceRecord();
}
@@ -86,6 +94,12 @@ public class PhoneMediaDevice extends MediaDevice {
}
@Override
+ public int getSelectionBehavior() {
+ // We don't allow apps to override the selection behavior of system routes.
+ return SELECTION_BEHAVIOR_TRANSFER;
+ }
+
+ @Override
public String getSummary() {
return mSummary;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
index 67a045e9a449..19a3db25996e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
@@ -20,6 +20,7 @@ import static android.media.MediaRoute2Info.TYPE_GROUP;
import static android.media.MediaRoute2Info.TYPE_REMOTE_CAR;
import static android.media.MediaRoute2Info.TYPE_REMOTE_COMPUTER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_GAME_CONSOLE;
+import static android.media.MediaRoute2Info.TYPE_REMOTE_SMARTPHONE;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SMARTWATCH;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_TABLET;
@@ -143,5 +144,9 @@ public class InfoMediaDeviceTest {
assertThat(mInfoMediaDevice.getDrawableResIdByType()).isEqualTo(
R.drawable.ic_media_smartwatch);
+
+ when(mRouteInfo.getType()).thenReturn(TYPE_REMOTE_SMARTPHONE);
+
+ assertThat(mInfoMediaDevice.getDrawableResIdByType()).isEqualTo(R.drawable.ic_smartphone);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 39780f3a96ed..7b8815e7c05c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -114,6 +114,23 @@ public class InfoMediaManagerTest {
}
@Test
+ public void stopScan_notStartFirst_notCallsUnregister() {
+ mInfoMediaManager.mRouterManager = mRouterManager;
+ mInfoMediaManager.stopScan();
+
+ verify(mRouterManager, never()).unregisterScanRequest();
+ }
+
+ @Test
+ public void stopScan_startFirst_callsUnregister() {
+ mInfoMediaManager.mRouterManager = mRouterManager;
+ mInfoMediaManager.startScan();
+ mInfoMediaManager.stopScan();
+
+ verify(mRouterManager).unregisterScanRequest();
+ }
+
+ @Test
public void onRouteAdded_getAvailableRoutes_shouldAddMediaDevice() {
final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
final RoutingSessionInfo sessionInfo = mock(RoutingSessionInfo.class);
@@ -327,11 +344,12 @@ public class InfoMediaManagerTest {
routeListingPreference);
mInfoMediaManager.mMediaRouterCallback.onRoutesUpdated();
- assertThat(mInfoMediaManager.mMediaDevices).hasSize(3);
+ assertThat(mInfoMediaManager.mMediaDevices).hasSize(4);
assertThat(mInfoMediaManager.mMediaDevices.get(0).getId()).isEqualTo(TEST_ID);
- assertThat(mInfoMediaManager.mMediaDevices.get(1).getId()).isEqualTo(TEST_ID_4);
- assertThat(mInfoMediaManager.mMediaDevices.get(1).isSuggestedDevice()).isTrue();
- assertThat(mInfoMediaManager.mMediaDevices.get(2).getId()).isEqualTo(TEST_ID_3);
+ assertThat(mInfoMediaManager.mMediaDevices.get(1).getId()).isEqualTo(TEST_ID_1);
+ assertThat(mInfoMediaManager.mMediaDevices.get(2).getId()).isEqualTo(TEST_ID_4);
+ assertThat(mInfoMediaManager.mMediaDevices.get(2).isSuggestedDevice()).isTrue();
+ assertThat(mInfoMediaManager.mMediaDevices.get(3).getId()).isEqualTo(TEST_ID_3);
}
@Test
@@ -405,8 +423,13 @@ public class InfoMediaManagerTest {
when(availableInfo3.getClientPackageName()).thenReturn(packageName);
availableRoutes.add(availableInfo3);
- when(mRouterManager.getAvailableRoutes(packageName)).thenReturn(
- availableRoutes);
+ final MediaRoute2Info availableInfo4 = mock(MediaRoute2Info.class);
+ when(availableInfo4.getId()).thenReturn(TEST_ID_1);
+ when(availableInfo4.isSystemRoute()).thenReturn(true);
+ when(availableInfo4.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+ availableRoutes.add(availableInfo4);
+
+ when(mRouterManager.getAvailableRoutes(packageName)).thenReturn(availableRoutes);
return availableRoutes;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index c058a61a3e9e..f22e090fe7df 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -19,6 +19,9 @@ import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
+import static android.media.RouteListingPreference.Item.SELECTION_BEHAVIOR_GO_TO_APP;
+
+import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
import static com.google.common.truth.Truth.assertThat;
@@ -32,6 +35,7 @@ import android.content.Context;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import android.media.NearbyDevice;
+import android.media.RouteListingPreference;
import android.os.Parcel;
import com.android.settingslib.bluetooth.A2dpProfile;
@@ -110,6 +114,8 @@ public class MediaDeviceTest {
@Mock
private MediaRouter2Manager mMediaRouter2Manager;
+ private RouteListingPreference.Item mItem;
+
private BluetoothMediaDevice mBluetoothMediaDevice1;
private BluetoothMediaDevice mBluetoothMediaDevice2;
private BluetoothMediaDevice mBluetoothMediaDevice3;
@@ -497,4 +503,21 @@ public class MediaDeviceTest {
assertThat(mBluetoothMediaDevice1.getFeatures().size()).isEqualTo(0);
}
+
+ @Test
+ public void getSelectionBehavior_setItemWithSelectionBehaviorOnSystemRoute_returnTransfer() {
+ mItem = new RouteListingPreference.Item.Builder(DEVICE_ADDRESS_1)
+ .setSelectionBehavior(SELECTION_BEHAVIOR_GO_TO_APP)
+ .build();
+ mBluetoothMediaDevice1 = new BluetoothMediaDevice(mContext, mCachedDevice1,
+ mMediaRouter2Manager, null /* MediaRoute2Info */, TEST_PACKAGE_NAME, mItem);
+ mPhoneMediaDevice =
+ new PhoneMediaDevice(mContext, mMediaRouter2Manager, mPhoneRouteInfo,
+ TEST_PACKAGE_NAME, mItem);
+
+ assertThat(mBluetoothMediaDevice1.getSelectionBehavior()).isEqualTo(
+ SELECTION_BEHAVIOR_TRANSFER);
+ assertThat(mPhoneMediaDevice.getSelectionBehavior()).isEqualTo(
+ SELECTION_BEHAVIOR_TRANSFER);
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 48259e165670..9da1ab8ae69c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -38,6 +38,7 @@ import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.LocalePicker;
@@ -238,6 +239,7 @@ public class SettingsHelper {
// If we fail to apply the setting, by definition nothing happened
sendBroadcast = false;
sendBroadcastSystemUI = false;
+ Log.e(TAG, "Failed to restore setting name: " + name + " + value: " + value, e);
} finally {
// If this was an element of interest, send the "we just restored it"
// broadcast with the historical value now that the new value has
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 887f19b8bbb3..2762d8eb08e0 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1950,6 +1950,9 @@ public class SettingsProvider extends ContentProvider {
cacheName = Settings.System.ALARM_ALERT_CACHE;
}
if (cacheName != null) {
+ if (!isValidAudioUri(name, value)) {
+ return false;
+ }
final File cacheFile = new File(
getRingtoneCacheDir(owningUserId), cacheName);
cacheFile.delete();
@@ -1982,6 +1985,34 @@ public class SettingsProvider extends ContentProvider {
}
}
+ private boolean isValidAudioUri(String name, String uri) {
+ if (uri != null) {
+ Uri audioUri = Uri.parse(uri);
+ if (Settings.AUTHORITY.equals(
+ ContentProvider.getAuthorityWithoutUserId(audioUri.getAuthority()))) {
+ // Don't accept setting the default uri to self-referential URIs like
+ // Settings.System.DEFAULT_RINGTONE_URI, which is an alias to the value of this
+ // setting.
+ return false;
+ }
+ final String mimeType = getContext().getContentResolver().getType(audioUri);
+ if (mimeType == null) {
+ Slog.e(LOG_TAG,
+ "mutateSystemSetting for setting: " + name + " URI: " + audioUri
+ + " ignored: failure to find mimeType (no access from this context?)");
+ return false;
+ }
+ if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg")
+ || mimeType.equals("application/x-flac"))) {
+ Slog.e(LOG_TAG,
+ "mutateSystemSetting for setting: " + name + " URI: " + audioUri
+ + " ignored: associated mimeType: " + mimeType + " is not an audio type");
+ return false;
+ }
+ }
+ return true;
+ }
+
private boolean hasWriteSecureSettingsPermission() {
// Write secure settings is a more protected permission. If caller has it we are good.
return getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -3560,11 +3591,11 @@ public class SettingsProvider extends ContentProvider {
if (isSecureSettingsKey(key)) {
maybeNotifyProfiles(getTypeFromKey(key), userId, uri, name,
sSecureCloneToManagedSettings);
- maybeNotifyProfiles(SETTINGS_TYPE_SYSTEM, userId, uri, name,
- sSystemCloneFromParentOnDependency.values());
} else if (isSystemSettingsKey(key)) {
maybeNotifyProfiles(getTypeFromKey(key), userId, uri, name,
sSystemCloneToManagedSettings);
+ maybeNotifyProfiles(SETTINGS_TYPE_SYSTEM, userId, uri, name,
+ sSystemCloneFromParentOnDependency.keySet());
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 56e0643b1e20..809202fa024d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -320,6 +320,7 @@
<uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
+ <uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
<uses-permission android:name="android.permission.SUSPEND_APPS" />
<uses-permission android:name="android.permission.OBSERVE_APP_USAGE" />
<uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" />
@@ -336,6 +337,7 @@
<uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_WATCH" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_PROFILE_GLASSES" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_SELF_MANAGED" />
+ <uses-permission android:name="android.permission.USE_COMPANION_TRANSPORTS" />
<uses-permission android:name="android.permission.MANAGE_APPOPS" />
<uses-permission android:name="android.permission.WATCH_APPOPS" />
diff --git a/packages/StatementService/src/com/android/statementservice/utils/StatementUtils.kt b/packages/StatementService/src/com/android/statementservice/utils/StatementUtils.kt
index 92d752c83a9f..4837aad3a025 100644
--- a/packages/StatementService/src/com/android/statementservice/utils/StatementUtils.kt
+++ b/packages/StatementService/src/com/android/statementservice/utils/StatementUtils.kt
@@ -88,6 +88,7 @@ internal object StatementUtils {
} catch (e: Exception) {
return Result.Failure(e)
}
+ checkNotNull(signingInfo)
return if (signingInfo.hasMultipleSigners()) {
signingInfo.apkContentsSigners
} else {
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 01e6bf00a664..3af7a4502856 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -35,6 +35,9 @@
},
{
"exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
@@ -128,6 +131,9 @@
},
{
"exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
index d4a81f9c765d..ac1ef1509415 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
@@ -70,8 +70,10 @@ import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
-import androidx.lifecycle.ViewTreeLifecycleOwner
-import androidx.lifecycle.ViewTreeViewModelStoreOwner
+import androidx.lifecycle.findViewTreeLifecycleOwner
+import androidx.lifecycle.findViewTreeViewModelStoreOwner
+import androidx.lifecycle.setViewTreeLifecycleOwner
+import androidx.lifecycle.setViewTreeViewModelStoreOwner
import com.android.systemui.animation.Expandable
import com.android.systemui.animation.LaunchAnimator
import kotlin.math.max
@@ -368,13 +370,10 @@ private fun AnimatedContentInOverlay(
context,
overlay,
)
- ViewTreeLifecycleOwner.set(
- overlayViewGroup,
- ViewTreeLifecycleOwner.get(composeViewRoot),
- )
- ViewTreeViewModelStoreOwner.set(
- overlayViewGroup,
- ViewTreeViewModelStoreOwner.get(composeViewRoot),
+
+ overlayViewGroup.setViewTreeLifecycleOwner(composeViewRoot.findViewTreeLifecycleOwner())
+ overlayViewGroup.setViewTreeViewModelStoreOwner(
+ composeViewRoot.findViewTreeViewModelStoreOwner()
)
ViewTreeSavedStateRegistryOwner.set(
overlayViewGroup,
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index f66dbfa233bd..a05773dda175 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -401,6 +401,18 @@ open class ClockRegistry(
scope.launch(bgDispatcher) { mutateSetting { it.copy(seedColor = value) } }
}
+ // Returns currentClockId if clock is connected, otherwise DEFAULT_CLOCK_ID. Since this
+ // is dependent on which clocks are connected, it may change when a clock is installed or
+ // removed from the device (unlike currentClockId).
+ // TODO: Merge w/ CurrentClockId when we convert to a flow. We shouldn't need both behaviors.
+ val activeClockId: String
+ get() {
+ if (!availableClocks.containsKey(currentClockId)) {
+ return DEFAULT_CLOCK_ID
+ }
+ return currentClockId
+ }
+
init {
// Register default clock designs
for (clock in defaultClockProvider.getClocks()) {
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index 1811c02d549d..64c0f99f4ba7 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -128,6 +128,16 @@ public interface BcSmartspaceDataPlugin extends Plugin {
void setDozeAmount(float amount);
/**
+ * Set if dozing is true or false
+ */
+ default void setDozing(boolean dozing) {}
+
+ /**
+ * Set if split shade enabled
+ */
+ default void setSplitShadeEnabled(boolean enabled) {}
+
+ /**
* Set the current keyguard bypass enabled status.
*/
default void setKeyguardBypassEnabled(boolean enabled) {}
diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml
index 13f72af084b7..42733a20ffae 100644
--- a/packages/SystemUI/res-product/values/strings.xml
+++ b/packages/SystemUI/res-product/values/strings.xml
@@ -122,6 +122,44 @@
Try again in <xliff:g id="number">%3$d</xliff:g> seconds.
</string>
+ <!-- Title for notification & dialog that the user's phone last shut down because it got too hot. [CHAR LIMIT=40] -->
+ <string name="thermal_shutdown_title" product="default">Phone turned off due to heat</string>
+ <!-- Title for notification & dialog that the user's device last shut down because it got too hot. [CHAR LIMIT=40] -->
+ <string name="thermal_shutdown_title" product="device">Device turned off due to heat</string>
+ <!-- Title for notification & dialog that the user's tablet last shut down because it got too hot. [CHAR LIMIT=40] -->
+ <string name="thermal_shutdown_title" product="tablet">Tablet turned off due to heat</string>
+ <!-- Message body for notification that user's phone last shut down because it got too hot. [CHAR LIMIT=120] -->
+ <string name="thermal_shutdown_message" product="default">Your phone is now running normally.\nTap for more info</string>
+ <!-- Message body for notification that user's device last shut down because it got too hot. [CHAR LIMIT=120] -->
+ <string name="thermal_shutdown_message" product="device">Your device is now running normally.\nTap for more info</string>
+ <!-- Message body for notification that user's tablet last shut down because it got too hot. [CHAR LIMIT=120] -->
+ <string name="thermal_shutdown_message" product="tablet">Your tablet is now running normally.\nTap for more info</string>
+ <!-- Text body for dialog alerting user that their phone last shut down because it got too hot. [CHAR LIMIT=500] -->
+ <string name="thermal_shutdown_dialog_message" product="default">Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n\t&#8226; Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t&#8226; Download or upload large files\n\t&#8226; Use your phone in high temperatures</string>
+ <!-- Text body for dialog alerting user that their device last shut down because it got too hot. [CHAR LIMIT=500] -->
+ <string name="thermal_shutdown_dialog_message" product="device">Your device was too hot, so it turned off to cool down. Your device is now running normally.\n\nYour device may get too hot if you:\n\t&#8226; Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t&#8226; Download or upload large files\n\t&#8226; Use your device in high temperatures</string>
+ <!-- Text body for dialog alerting user that their tablet last shut down because it got too hot. [CHAR LIMIT=500] -->
+ <string name="thermal_shutdown_dialog_message" product="tablet">Your tablet was too hot, so it turned off to cool down. Your tablet is now running normally.\n\nYour tablet may get too hot if you:\n\t&#8226; Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t&#8226; Download or upload large files\n\t&#8226; Use your tablet in high temperatures</string>
+
+ <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
+ <string name="high_temp_title" product="default">Phone is getting warm</string>
+ <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
+ <string name="high_temp_title" product="device">Device is getting warm</string>
+ <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
+ <string name="high_temp_title" product="tablet">Tablet is getting warm</string>
+ <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=120] -->
+ <string name="high_temp_notif_message" product="default">Some features limited while phone cools down.\nTap for more info</string>
+ <!-- Message body for notification that user's device has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=120] -->
+ <string name="high_temp_notif_message" product="device">Some features limited while device cools down.\nTap for more info</string>
+ <!-- Message body for notification that user's tablet has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=120] -->
+ <string name="high_temp_notif_message" product="tablet">Some features limited while tablet cools down.\nTap for more info</string>
+ <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=350] -->
+ <string name="high_temp_dialog_message" product="default">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
+ <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=350] -->
+ <string name="high_temp_dialog_message" product="device">Your device will automatically try to cool down. You can still use your device, but it may run slower.\n\nOnce your device has cooled down, it will run normally.</string>
+ <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=350] -->
+ <string name="high_temp_dialog_message" product="tablet">Your tablet will automatically try to cool down. You can still use your tablet, but it may run slower.\n\nOnce your tablet has cooled down, it will run normally.</string>
+
<!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (tablet) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.</string>
<!-- Content description of the fingerprint icon when the system-provided fingerprint dialog is showing, to locate the sensor (device) for accessibility (not shown on the screen). [CHAR LIMIT=NONE]-->
diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
index 87b5a4c2fc5b..32dc4b335f7e 100644
--- a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
+++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
@@ -20,7 +20,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/>
<size
android:width="@dimen/keyguard_affordance_fixed_width"
android:height="@dimen/keyguard_affordance_fixed_height"/>
diff --git a/packages/SystemUI/res/layout/activity_rear_display_education.xml b/packages/SystemUI/res/layout/activity_rear_display_education.xml
index c295cfe7a2e0..1b6247f29922 100644
--- a/packages/SystemUI/res/layout/activity_rear_display_education.xml
+++ b/packages/SystemUI/res/layout/activity_rear_display_education.xml
@@ -28,7 +28,7 @@
app:cardCornerRadius="28dp"
app:cardBackgroundColor="@color/rear_display_overlay_animation_background_color">
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.reardisplay.RearDisplayEducationLottieViewWrapper
android:id="@+id/rear_display_folded_animation"
android:importantForAccessibility="no"
android:layout_width="@dimen/rear_display_animation_width"
diff --git a/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml b/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
index 0e6b2812a8a9..bded0127ec84 100644
--- a/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
+++ b/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
@@ -29,7 +29,7 @@
app:cardCornerRadius="28dp"
app:cardBackgroundColor="@color/rear_display_overlay_animation_background_color">
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.reardisplay.RearDisplayEducationLottieViewWrapper
android:id="@+id/rear_display_folded_animation"
android:importantForAccessibility="no"
android:layout_width="@dimen/rear_display_animation_width_opened"
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index efc661a6e974..50b3bec93731 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -57,7 +57,7 @@
<include layout="@layout/auth_biometric_icon"/>
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
android:id="@+id/biometric_icon_overlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/biometric_prompt_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
index 05ff1b1c2e6f..595cea8b9018 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
@@ -59,7 +59,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center">
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
android:id="@+id/biometric_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -67,7 +67,7 @@
android:contentDescription="@null"
android:scaleType="fitXY" />
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
android:id="@+id/biometric_icon_overlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
index 50dcaf333ea1..bb32022a0b5f 100644
--- a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
@@ -57,7 +57,6 @@
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
- android:layout_marginTop="@dimen/dream_overlay_status_bar_marginTop"
android:src="@drawable/ic_alarm"
android:tint="@android:color/white"
android:visibility="gone"
@@ -68,7 +67,6 @@
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
- android:layout_marginTop="@dimen/dream_overlay_status_bar_marginTop"
android:src="@drawable/ic_qs_dnd_on"
android:tint="@android:color/white"
android:visibility="gone"
@@ -79,7 +77,6 @@
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
- android:layout_marginTop="@dimen/dream_overlay_status_bar_marginTop"
android:src="@drawable/ic_signal_wifi_off"
android:visibility="gone"
android:contentDescription="@string/dream_overlay_status_bar_wifi_off" />
diff --git a/packages/SystemUI/res/layout/media_output_list_item_advanced.xml b/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
index 7105721aff70..21e0d2c0b8d7 100644
--- a/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
@@ -164,7 +164,6 @@
/>
<ImageView
android:id="@+id/media_output_item_end_click_icon"
- android:src="@drawable/media_output_status_edit_session"
android:layout_width="24dp"
android:layout_height="24dp"
android:focusable="false"
diff --git a/packages/SystemUI/res/layout/sidefps_view.xml b/packages/SystemUI/res/layout/sidefps_view.xml
index 73050c253d72..4d952209da6f 100644
--- a/packages/SystemUI/res/layout/sidefps_view.xml
+++ b/packages/SystemUI/res/layout/sidefps_view.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.airbnb.lottie.LottieAnimationView
+<com.android.systemui.biometrics.SideFpsLottieViewWrapper
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sidefps_animation"
diff --git a/packages/SystemUI/res/layout/udfps_keyguard_preview.xml b/packages/SystemUI/res/layout/udfps_keyguard_preview.xml
index c068b7bc46a9..0964a21aeb36 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_preview.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_preview.xml
@@ -24,7 +24,7 @@
android:background="@drawable/fingerprint_bg">
<!-- LockScreen fingerprint icon from 0 stroke width to full width -->
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.keyguard.ui.view.UdfpsLottieViewWrapper
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml b/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml
index 191158e4e8c2..1d6147cd2169 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml
@@ -32,7 +32,7 @@
<!-- Fingerprint -->
<!-- AOD dashed fingerprint icon with moving dashes -->
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.keyguard.ui.view.UdfpsLottieViewWrapper
android:id="@+id/udfps_aod_fp"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -43,7 +43,7 @@
app:lottie_rawRes="@raw/udfps_aod_fp"/>
<!-- LockScreen fingerprint icon from 0 stroke width to full width -->
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.keyguard.ui.view.UdfpsLottieViewWrapper
android:id="@+id/udfps_lockscreen_fp"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4f768cc39b40..44a5c07502ac 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1781,7 +1781,6 @@
<dimen name="dream_overlay_status_bar_ambient_text_shadow_dy">0.5dp</dimen>
<dimen name="dream_overlay_status_bar_ambient_text_shadow_radius">2dp</dimen>
<dimen name="dream_overlay_icon_inset_dimen">0dp</dimen>
- <dimen name="dream_overlay_status_bar_marginTop">22dp</dimen>
<!-- Default device corner radius, used for assist UI -->
<dimen name="config_rounded_mask_size">0px</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 663efea1944b..070748cb92f8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2089,23 +2089,11 @@
<!-- Tuner string -->
<!-- Tuner string -->
- <!-- Title for notification & dialog that the user's phone last shut down because it got too hot. [CHAR LIMIT=40] -->
- <string name="thermal_shutdown_title">Phone turned off due to heat</string>
- <!-- Message body for notification that user's phone last shut down because it got too hot. [CHAR LIMIT=120] -->
- <string name="thermal_shutdown_message">Your phone is now running normally.\nTap for more info</string>
- <!-- Text body for dialog alerting user that their phone last shut down because it got too hot. [CHAR LIMIT=500] -->
- <string name="thermal_shutdown_dialog_message">Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n\t&#8226; Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t&#8226; Download or upload large files\n\t&#8226; Use your phone in high temperatures</string>
<!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] -->
<string name="thermal_shutdown_dialog_help_text">See care steps</string>
<!-- URL for care instructions for overheating devices -->
<string name="thermal_shutdown_dialog_help_url" translatable="false"></string>
- <!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
- <string name="high_temp_title">Phone is getting warm</string>
- <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=120] -->
- <string name="high_temp_notif_message">Some features limited while phone cools down.\nTap for more info</string>
- <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=350] -->
- <string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
<!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] -->
<string name="high_temp_dialog_help_text">See care steps</string>
<!-- URL for care instructions for overheating devices -->
diff --git a/packages/SystemUI/res/xml/large_screen_shade_header.xml b/packages/SystemUI/res/xml/large_screen_shade_header.xml
index bf576dc5790b..3881e8c1c4cc 100644
--- a/packages/SystemUI/res/xml/large_screen_shade_header.xml
+++ b/packages/SystemUI/res/xml/large_screen_shade_header.xml
@@ -60,7 +60,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintEnd_toEndOf="@id/carrier_group"/>
+ app:layout_constraintStart_toEndOf="@id/carrier_group"/>
<PropertySet android:alpha="1" />
</Constraint>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt
index 635f0fa44234..1cb8e43cf2c8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt
@@ -13,7 +13,8 @@ class KeyguardClockFrame(
private var drawAlpha: Int = 255
protected override fun onSetAlpha(alpha: Int): Boolean {
- drawAlpha = alpha
+ // Ignore alpha passed from View, prefer to compute it from set values
+ drawAlpha = (255 * this.alpha * transitionAlpha).toInt()
return true
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 885b53d7e5d6..b4fb88701634 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -330,7 +330,6 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
});
- in.setAlpha(0);
in.setVisibility(View.VISIBLE);
mClockInAnim = new AnimatorSet();
mClockInAnim.setDuration(CLOCK_IN_MILLIS);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 41c1eda42e83..a0261309d61a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -352,6 +352,13 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
/**
+ * Set if the split shade is enabled
+ */
+ public void setSplitShadeEnabled(boolean splitShadeEnabled) {
+ mSmartspaceController.setSplitShadeEnabled(splitShadeEnabled);
+ }
+
+ /**
* Set which clock should be displayed on the keyguard. The other one will be automatically
* hidden.
*/
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 2b71728f3391..f446e523afa9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -786,8 +786,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
void reloadColors() {
mViewMode.reloadColors();
- setBackgroundColor(Utils.getColorAttrDefaultColor(getContext(),
- com.android.internal.R.attr.materialColorSurface));
}
/** Handles density or font scale changes. */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 74b29a77aad4..e18050d77847 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -80,6 +80,7 @@ import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.ViewController;
@@ -362,6 +363,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
showPrimarySecurityScreen(false);
}
};
+ private final DeviceProvisionedController mDeviceProvisionedController;
@Inject
public KeyguardSecurityContainerController(KeyguardSecurityContainer view,
@@ -377,6 +379,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
FalsingCollector falsingCollector,
FalsingManager falsingManager,
UserSwitcherController userSwitcherController,
+ DeviceProvisionedController deviceProvisionedController,
FeatureFlags featureFlags,
GlobalSettings globalSettings,
SessionTracker sessionTracker,
@@ -411,6 +414,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mViewMediatorCallback = viewMediatorCallback;
mAudioManager = audioManager;
mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
+ mDeviceProvisionedController = deviceProvisionedController;
}
@Override
@@ -763,8 +767,11 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
case SimPuk:
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
- KeyguardUpdateMonitor.getCurrentUser())) {
+ boolean isLockscreenDisabled = mLockPatternUtils.isLockScreenDisabled(
+ KeyguardUpdateMonitor.getCurrentUser())
+ || !mDeviceProvisionedController.isUserSetup(targetUserId);
+
+ if (securityMode == SecurityMode.None && isLockscreenDisabled) {
finish = true;
eventSubtype = BOUNCER_DISMISS_SIM;
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 00500d617766..6854c97c3415 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -323,6 +323,13 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
/**
+ * Set if the split shade is enabled
+ */
+ public void setSplitShadeEnabled(boolean enabled) {
+ mKeyguardClockSwitchController.setSplitShadeEnabled(enabled);
+ }
+
+ /**
* Updates the alignment of the KeyguardStatusView and animates the transition if requested.
*/
public void updateAlignment(
@@ -350,6 +357,9 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
mInteractionJankMonitor.begin(mView, CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION);
+ /* This transition blocks any layout changes while running. For that reason
+ * special logic with setting visibility was added to {@link BcSmartspaceView#setDozing}
+ * for split shade to avoid jump of the media object. */
ChangeBounds transition = new ChangeBounds();
if (splitShadeEnabled) {
// Excluding media from the transition on split-shade, as it doesn't transition
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ae061c032429..de24024aaa2f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -296,6 +296,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private static final ComponentName FALLBACK_HOME_COMPONENT = new ComponentName(
"com.android.settings", "com.android.settings.FallbackHome");
+ private static final List<Integer> ABSENT_SIM_STATE_LIST = Arrays.asList(
+ TelephonyManager.SIM_STATE_ABSENT,
+ TelephonyManager.SIM_STATE_UNKNOWN,
+ TelephonyManager.SIM_STATE_NOT_READY);
+
private final Context mContext;
private final UserTracker mUserTracker;
private final KeyguardUpdateMonitorLogger mLogger;
@@ -3698,8 +3703,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mLogger.logSimState(subId, slotId, state);
boolean becameAbsent = false;
- if (!SubscriptionManager.isValidSubscriptionId(subId)
- && state != TelephonyManager.SIM_STATE_UNKNOWN) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
mLogger.w("invalid subId in handleSimStateChange()");
/* Only handle No SIM(ABSENT) and Card Error(CARD_IO_ERROR) due to
* handleServiceStateChange() handle other case */
@@ -3717,11 +3721,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
} else if (state == TelephonyManager.SIM_STATE_CARD_IO_ERROR) {
updateTelephonyCapable(true);
- } else {
- return;
}
}
+ becameAbsent |= ABSENT_SIM_STATE_LIST.contains(state);
+
SimData data = mSimDatas.get(subId);
final boolean changed;
if (data == null) {
@@ -3734,7 +3738,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
data.subId = subId;
data.slotId = slotId;
}
- if ((changed || becameAbsent) || state == TelephonyManager.SIM_STATE_UNKNOWN) {
+ if ((changed || becameAbsent)) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 239a0cc01c45..9003c43b5cc9 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -62,6 +62,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -112,6 +113,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@NonNull private final VibratorHelper mVibrator;
@Nullable private final AuthRippleController mAuthRippleController;
@NonNull private final FeatureFlags mFeatureFlags;
+ @NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
@NonNull private final KeyguardTransitionInteractor mTransitionInteractor;
@NonNull private final KeyguardInteractor mKeyguardInteractor;
@@ -180,7 +182,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@NonNull @Main Resources resources,
@NonNull KeyguardTransitionInteractor transitionInteractor,
@NonNull KeyguardInteractor keyguardInteractor,
- @NonNull FeatureFlags featureFlags
+ @NonNull FeatureFlags featureFlags,
+ PrimaryBouncerInteractor primaryBouncerInteractor
) {
super(view);
mStatusBarStateController = statusBarStateController;
@@ -197,6 +200,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mTransitionInteractor = transitionInteractor;
mKeyguardInteractor = keyguardInteractor;
mFeatureFlags = featureFlags;
+ mPrimaryBouncerInteractor = primaryBouncerInteractor;
mMaxBurnInOffsetX = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
mMaxBurnInOffsetY = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
@@ -325,8 +329,14 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mView.setContentDescription(null);
}
+ boolean accessibilityEnabled =
+ !mPrimaryBouncerInteractor.isAnimatingAway() && mView.isVisibleToUser();
+ mView.setImportantForAccessibility(
+ accessibilityEnabled ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
+ : View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+
if (!Objects.equals(prevContentDescription, mView.getContentDescription())
- && mView.getContentDescription() != null && mView.isVisibleToUser()) {
+ && mView.getContentDescription() != null && accessibilityEnabled) {
mView.announceForAccessibility(mView.getContentDescription());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricPromptLottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricPromptLottieViewWrapper.kt
new file mode 100644
index 000000000000..e48e6e2dfdc6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricPromptLottieViewWrapper.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import android.content.Context
+import android.util.AttributeSet
+import com.android.systemui.util.wrapper.LottieViewWrapper
+
+class BiometricPromptLottieViewWrapper
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 7c412237650c..240390e369f8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -117,6 +117,8 @@ constructor(
private var overlayView: View? = null
set(value) {
field?.let { oldView ->
+ val lottie = oldView.findViewById(R.id.sidefps_animation) as LottieAnimationView
+ lottie.pauseAnimation()
windowManager.removeView(oldView)
orientationListener.disable()
}
@@ -193,7 +195,9 @@ constructor(
requests.add(request)
mainExecutor.execute {
if (overlayView == null) {
- traceSection("SideFpsController#show(request=${request.name}, reason=$reason") {
+ traceSection(
+ "SideFpsController#show(request=${request.name}, reason=$reason)"
+ ) {
createOverlayForDisplay(reason)
}
} else {
@@ -208,7 +212,7 @@ constructor(
requests.remove(request)
mainExecutor.execute {
if (requests.isEmpty()) {
- traceSection("SideFpsController#hide(${request.name}") { overlayView = null }
+ traceSection("SideFpsController#hide(${request.name})") { overlayView = null }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
new file mode 100644
index 000000000000..e98f6db12d34
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.biometrics
+
+import android.content.Context
+import android.util.AttributeSet
+import com.android.systemui.util.wrapper.LottieViewWrapper
+
+class SideFpsLottieViewWrapper
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 2eb533029cf5..10e45dadee60 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -589,6 +589,13 @@ public class UdfpsController implements DozeReceiver, Dumpable {
// Pilfer if valid overlap, don't allow following events to reach keyguard
shouldPilfer = true;
+
+ // Touch is a valid UDFPS touch. Inform the falsing manager so that the touch
+ // isn't counted against the falsing algorithm as an accidental touch.
+ // We do this on the DOWN event instead of CANCEL/UP because the CANCEL/UP events
+ // get sent too late to this receiver (after the actual cancel/up motions occur),
+ // and therefore wouldn't end up being used as part of the falsing algo.
+ mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
break;
case UP:
@@ -608,7 +615,6 @@ public class UdfpsController implements DozeReceiver, Dumpable {
data.getTime(),
data.getGestureStart(),
mStatusBarStateController.isDozing());
- mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
break;
case UNCHANGED:
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 3eb58bba1ca4..ec76f433b23b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -38,6 +38,7 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.controls.ControlInterface
+import com.android.systemui.controls.ui.CanUseIconPredicate
import com.android.systemui.controls.ui.RenderInfo
private typealias ModelFavoriteChanger = (String, Boolean) -> Unit
@@ -51,7 +52,8 @@ private typealias ModelFavoriteChanger = (String, Boolean) -> Unit
* @property elevation elevation of each control view
*/
class ControlAdapter(
- private val elevation: Float
+ private val elevation: Float,
+ private val currentUserId: Int,
) : RecyclerView.Adapter<Holder>() {
companion object {
@@ -107,7 +109,8 @@ class ControlAdapter(
background = parent.context.getDrawable(
R.drawable.control_background_ripple)
},
- model?.moveHelper // Indicates that position information is needed
+ currentUserId,
+ model?.moveHelper, // Indicates that position information is needed
) { id, favorite ->
model?.changeFavoriteStatus(id, favorite)
}
@@ -212,8 +215,9 @@ private class ZoneHolder(view: View) : Holder(view) {
*/
internal class ControlHolder(
view: View,
+ currentUserId: Int,
val moveHelper: ControlsModel.MoveHelper?,
- val favoriteCallback: ModelFavoriteChanger
+ val favoriteCallback: ModelFavoriteChanger,
) : Holder(view) {
private val favoriteStateDescription =
itemView.context.getString(R.string.accessibility_control_favorite)
@@ -228,6 +232,7 @@ internal class ControlHolder(
visibility = View.VISIBLE
}
+ private val canUseIconPredicate = CanUseIconPredicate(currentUserId)
private val accessibilityDelegate = ControlHolderAccessibilityDelegate(
this::stateDescription,
this::getLayoutPosition,
@@ -287,7 +292,9 @@ internal class ControlHolder(
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
icon.imageTintList = null
- ci.customIcon?.let {
+ ci.customIcon
+ ?.takeIf(canUseIconPredicate)
+ ?.let {
icon.setImageIcon(it)
} ?: run {
icon.setImageDrawable(ri.icon)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index d629e3ea365e..b387e4a66bd2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -154,7 +154,7 @@ open class ControlsEditingActivity @Inject constructor(
private fun bindViews() {
setContentView(R.layout.controls_management)
- getLifecycle().addObserver(
+ lifecycle.addObserver(
ControlsAnimations.observerForAnimations(
requireViewById<ViewGroup>(R.id.controls_management_root),
window,
@@ -250,7 +250,7 @@ open class ControlsEditingActivity @Inject constructor(
val elevation = resources.getFloat(R.dimen.control_card_elevation)
val recyclerView = requireViewById<RecyclerView>(R.id.list)
recyclerView.alpha = 0.0f
- val adapter = ControlAdapter(elevation).apply {
+ val adapter = ControlAdapter(elevation, userTracker.userId).apply {
registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
var hasAnimated = false
override fun onChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index d3ffc9585335..59fa7f53fc17 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -197,7 +197,7 @@ open class ControlsFavoritingActivity @Inject constructor(
}
executor.execute {
- structurePager.adapter = StructureAdapter(listOfStructures)
+ structurePager.adapter = StructureAdapter(listOfStructures, userTracker.userId)
structurePager.setCurrentItem(structureIndex)
if (error) {
statusText.text = resources.getString(R.string.controls_favorite_load_error,
@@ -243,7 +243,7 @@ open class ControlsFavoritingActivity @Inject constructor(
structurePager.alpha = 0.0f
pageIndicator.alpha = 0.0f
structurePager.apply {
- adapter = StructureAdapter(emptyList())
+ adapter = StructureAdapter(emptyList(), userTracker.userId)
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
@@ -268,7 +268,7 @@ open class ControlsFavoritingActivity @Inject constructor(
private fun bindViews() {
setContentView(R.layout.controls_management)
- getLifecycle().addObserver(
+ lifecycle.addObserver(
ControlsAnimations.observerForAnimations(
requireViewById<ViewGroup>(R.id.controls_management_root),
window,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index fb19ac99d19e..d5b8693af42d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -91,7 +91,7 @@ open class ControlsProviderSelectorActivity @Inject constructor(
setContentView(R.layout.controls_management)
- getLifecycle().addObserver(
+ lifecycle.addObserver(
ControlsAnimations.observerForAnimations(
requireViewById<ViewGroup>(R.id.controls_management_root),
window,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
index 747bcbe1c229..5977d379acde 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
@@ -24,13 +24,15 @@ import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
class StructureAdapter(
- private val models: List<StructureContainer>
+ private val models: List<StructureContainer>,
+ private val currentUserId: Int,
) : RecyclerView.Adapter<StructureAdapter.StructureHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): StructureHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return StructureHolder(
- layoutInflater.inflate(R.layout.controls_structure_page, parent, false)
+ layoutInflater.inflate(R.layout.controls_structure_page, parent, false),
+ currentUserId,
)
}
@@ -40,7 +42,8 @@ class StructureAdapter(
holder.bind(models[index].model)
}
- class StructureHolder(view: View) : RecyclerView.ViewHolder(view) {
+ class StructureHolder(view: View, currentUserId: Int) :
+ RecyclerView.ViewHolder(view) {
private val recyclerView: RecyclerView
private val controlAdapter: ControlAdapter
@@ -48,7 +51,7 @@ class StructureAdapter(
init {
recyclerView = itemView.requireViewById<RecyclerView>(R.id.listAll)
val elevation = itemView.context.resources.getFloat(R.dimen.control_card_elevation)
- controlAdapter = ControlAdapter(elevation)
+ controlAdapter = ControlAdapter(elevation, currentUserId)
setUpRecyclerView()
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt
new file mode 100644
index 000000000000..61c21237144d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.ui
+
+import android.content.ContentProvider
+import android.graphics.drawable.Icon
+
+class CanUseIconPredicate(private val currentUserId: Int) : (Icon) -> Boolean {
+
+ override fun invoke(icon: Icon): Boolean =
+ if (icon.type == Icon.TYPE_URI || icon.type == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ ContentProvider.getUserIdFromUri(icon.uri, currentUserId) == currentUserId
+ } else {
+ true
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index e6361f46c8ad..c04bc8792223 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -68,7 +68,8 @@ class ControlViewHolder(
val bgExecutor: DelayableExecutor,
val controlActionCoordinator: ControlActionCoordinator,
val controlsMetricsLogger: ControlsMetricsLogger,
- val uid: Int
+ val uid: Int,
+ val currentUserId: Int,
) {
companion object {
@@ -85,29 +86,9 @@ class ControlViewHolder(
private val ATTR_DISABLED = intArrayOf(-android.R.attr.state_enabled)
const val MIN_LEVEL = 0
const val MAX_LEVEL = 10000
-
- fun findBehaviorClass(
- status: Int,
- template: ControlTemplate,
- deviceType: Int
- ): Supplier<out Behavior> {
- return when {
- status != Control.STATUS_OK -> Supplier { StatusBehavior() }
- template == ControlTemplate.NO_TEMPLATE -> Supplier { TouchBehavior() }
- template is ThumbnailTemplate -> Supplier { ThumbnailBehavior() }
-
- // Required for legacy support, or where cameras do not use the new template
- deviceType == DeviceTypes.TYPE_CAMERA -> Supplier { TouchBehavior() }
- template is ToggleTemplate -> Supplier { ToggleBehavior() }
- template is StatelessTemplate -> Supplier { TouchBehavior() }
- template is ToggleRangeTemplate -> Supplier { ToggleRangeBehavior() }
- template is RangeTemplate -> Supplier { ToggleRangeBehavior() }
- template is TemperatureControlTemplate -> Supplier { TemperatureControlBehavior() }
- else -> Supplier { DefaultBehavior() }
- }
- }
}
+ private val canUseIconPredicate = CanUseIconPredicate(currentUserId)
private val toggleBackgroundIntensity: Float = layout.context.resources
.getFraction(R.fraction.controls_toggle_bg_intensity, 1, 1)
private var stateAnimator: ValueAnimator? = null
@@ -147,6 +128,27 @@ class ControlViewHolder(
status.setSelected(true)
}
+ fun findBehaviorClass(
+ status: Int,
+ template: ControlTemplate,
+ deviceType: Int
+ ): Supplier<out Behavior> {
+ return when {
+ status != Control.STATUS_OK -> Supplier { StatusBehavior() }
+ template == ControlTemplate.NO_TEMPLATE -> Supplier { TouchBehavior() }
+ template is ThumbnailTemplate -> Supplier { ThumbnailBehavior(currentUserId) }
+
+ // Required for legacy support, or where cameras do not use the new template
+ deviceType == DeviceTypes.TYPE_CAMERA -> Supplier { TouchBehavior() }
+ template is ToggleTemplate -> Supplier { ToggleBehavior() }
+ template is StatelessTemplate -> Supplier { TouchBehavior() }
+ template is ToggleRangeTemplate -> Supplier { ToggleRangeBehavior() }
+ template is RangeTemplate -> Supplier { ToggleRangeBehavior() }
+ template is TemperatureControlTemplate -> Supplier { TemperatureControlBehavior() }
+ else -> Supplier { DefaultBehavior() }
+ }
+ }
+
fun bindData(cws: ControlWithState, isLocked: Boolean) {
// If an interaction is in progress, the update may visually interfere with the action the
// action the user wants to make. Don't apply the update, and instead assume a new update
@@ -473,7 +475,9 @@ class ControlViewHolder(
status.setTextColor(color)
- control?.getCustomIcon()?.let {
+ control?.customIcon
+ ?.takeIf(canUseIconPredicate)
+ ?.let {
icon.setImageIcon(it)
icon.imageTintList = it.tintList
} ?: run {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
index 4a22e4eecc2b..557dcf4accc7 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
@@ -72,7 +72,7 @@ open class ControlsActivity @Inject constructor(
setContentView(R.layout.controls_fullscreen)
- getLifecycle().addObserver(
+ lifecycle.addObserver(
ControlsAnimations.observerForAnimations(
requireViewById(R.id.control_detail_root),
window,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index d73c85b0803b..631ed3c26496 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -279,7 +279,7 @@ class ControlsUiControllerImpl @Inject constructor (
controlsListingController.get().removeCallback(listingCallback)
controlsController.get().unsubscribe()
- taskViewController?.dismiss()
+ taskViewController?.removeTask()
taskViewController = null
val fadeAnim = ObjectAnimator.ofFloat(parent, "alpha", 1.0f, 0.0f)
@@ -690,7 +690,8 @@ class ControlsUiControllerImpl @Inject constructor (
bgExecutor,
controlActionCoordinator,
controlsMetricsLogger,
- selected.uid
+ selected.uid,
+ controlsController.get().currentUserId,
)
cvh.bindData(it, false /* isLocked, will be ignored on initial load */)
controlViewsById.put(key, cvh)
@@ -777,7 +778,7 @@ class ControlsUiControllerImpl @Inject constructor (
closeDialogs(true)
controlsController.get().unsubscribe()
- taskViewController?.dismiss()
+ taskViewController?.removeTask()
taskViewController = null
controlsById.clear()
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
index 025d7e40201e..db009dc46d89 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
@@ -18,7 +18,6 @@
package com.android.systemui.controls.ui
import android.app.ActivityOptions
-import android.app.ActivityTaskManager
import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.app.PendingIntent
import android.content.ComponentName
@@ -28,6 +27,7 @@ import android.graphics.Color
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.os.Trace
+import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.util.boundsOnScreen
import com.android.wm.shell.taskview.TaskView
@@ -54,12 +54,6 @@ class PanelTaskViewController(
addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
}
- private fun removeDetailTask() {
- if (detailTaskId == INVALID_TASK_ID) return
- ActivityTaskManager.getInstance().removeTask(detailTaskId)
- detailTaskId = INVALID_TASK_ID
- }
-
private val stateCallback =
object : TaskView.Listener {
override fun onInitialized() {
@@ -95,7 +89,7 @@ class PanelTaskViewController(
override fun onTaskRemovalStarted(taskId: Int) {
detailTaskId = INVALID_TASK_ID
- dismiss()
+ release()
}
override fun onTaskCreated(taskId: Int, name: ComponentName?) {
@@ -103,12 +97,7 @@ class PanelTaskViewController(
taskView.alpha = 1f
}
- override fun onReleased() {
- removeDetailTask()
- }
-
override fun onBackPressedOnTaskRoot(taskId: Int) {
- dismiss()
hide()
}
}
@@ -117,10 +106,17 @@ class PanelTaskViewController(
taskView.onLocationChanged()
}
- fun dismiss() {
+ /** Call when the taskView is no longer being used, shouldn't be called before removeTask. */
+ @VisibleForTesting
+ fun release() {
taskView.release()
}
+ /** Call to explicitly remove the task from window manager. */
+ fun removeTask() {
+ taskView.removeTask()
+ }
+
fun launchTaskView() {
taskView.setListener(uiExecutor, stateCallback)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
index a7dc09bb17e5..39d69704d817 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
@@ -63,7 +63,7 @@ class TemperatureControlBehavior : Behavior {
// interactions (touch, range)
subBehavior = cvh.bindBehavior(
subBehavior,
- ControlViewHolder.findBehaviorClass(
+ cvh.findBehaviorClass(
control.status,
subTemplate,
control.deviceType
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
index c2168aa8d9d9..0b57e792f9f7 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
@@ -33,7 +33,7 @@ import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL
* Supports display of static images on the background of the tile. When marked active, the title
* and subtitle will not be visible. To be used with {@link Thumbnailtemplate} only.
*/
-class ThumbnailBehavior : Behavior {
+class ThumbnailBehavior(currentUserId: Int) : Behavior {
lateinit var template: ThumbnailTemplate
lateinit var control: Control
lateinit var cvh: ControlViewHolder
@@ -42,6 +42,7 @@ class ThumbnailBehavior : Behavior {
private var shadowRadius: Float = 0f
private var shadowColor: Int = 0
+ private val canUseIconPredicate = CanUseIconPredicate(currentUserId)
private val enabled: Boolean
get() = template.isActive()
@@ -80,11 +81,16 @@ class ThumbnailBehavior : Behavior {
cvh.status.setShadowLayer(shadowOffsetX, shadowOffsetY, shadowRadius, shadowColor)
cvh.bgExecutor.execute {
- val drawable = template.getThumbnail().loadDrawable(cvh.context)
+ val drawable = template.thumbnail
+ ?.takeIf(canUseIconPredicate)
+ ?.loadDrawable(cvh.context)
cvh.uiExecutor.execute {
val radius = cvh.context.getResources()
.getDimensionPixelSize(R.dimen.control_corner_radius).toFloat()
- clipLayer.setDrawable(CornerDrawable(drawable, radius))
+ // TODO(b/290037843): Add a placeholder
+ drawable?.let {
+ clipLayer.drawable = CornerDrawable(it, radius)
+ }
clipLayer.setColorFilter(BlendModeColorFilter(cvh.context.resources
.getColor(R.color.control_thumbnail_tint), BlendMode.LUMINOSITY))
cvh.applyRenderInfo(enabled, colorOffset)
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt
index 83253563e969..003d2c73fa06 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayLifecycleOwner.kt
@@ -28,7 +28,8 @@ import javax.inject.Inject
class DreamOverlayLifecycleOwner @Inject constructor() : LifecycleOwner {
val registry: LifecycleRegistry = LifecycleRegistry(this)
- override fun getLifecycle(): Lifecycle {
- return registry
- }
+ override val lifecycle: Lifecycle
+ get() {
+ return registry
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 951d077808c9..366056af7ab3 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -683,11 +683,11 @@ object Flags {
// TODO(b/283071711): Tracking bug
@JvmField
val TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK =
- releasedFlag(2401, "trim_resources_with_background_trim_on_lock")
+ unreleasedFlag(2401, "trim_resources_with_background_trim_on_lock")
// TODO:(b/283203305): Tracking bug
@JvmField
- val TRIM_FONT_CACHES_AT_UNLOCK = releasedFlag(2402, "trim_font_caches_on_unlock")
+ val TRIM_FONT_CACHES_AT_UNLOCK = unreleasedFlag(2402, "trim_font_caches_on_unlock")
// 2700 - unfold transitions
// TODO(b/265764985): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index bc41ab3156df..1a06b0184bc5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -99,6 +99,7 @@ import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -139,6 +140,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.flags.SystemPropertiesHelper;
import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -166,6 +168,8 @@ import com.android.wm.shell.keyguard.KeyguardTransitions;
import dagger.Lazy;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
@@ -250,6 +254,22 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private static final int SYSTEM_READY = 18;
private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19;
+ /** Enum for reasons behind updating wakeAndUnlock state. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ value = {
+ WakeAndUnlockUpdateReason.HIDE,
+ WakeAndUnlockUpdateReason.SHOW,
+ WakeAndUnlockUpdateReason.FULFILL,
+ WakeAndUnlockUpdateReason.WAKE_AND_UNLOCK,
+ })
+ @interface WakeAndUnlockUpdateReason {
+ int HIDE = 0;
+ int SHOW = 1;
+ int FULFILL = 2;
+ int WAKE_AND_UNLOCK = 3;
+ }
+
/**
* The default amount of time we stay awake (used for all key input)
*/
@@ -432,6 +452,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private final LockPatternUtils mLockPatternUtils;
private final BroadcastDispatcher mBroadcastDispatcher;
private boolean mKeyguardDonePending = false;
+ private boolean mUnlockingAndWakingFromDream = false;
private boolean mHideAnimationRun = false;
private boolean mHideAnimationRunning = false;
@@ -538,6 +559,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private CentralSurfaces mCentralSurfaces;
+ private IRemoteAnimationFinishedCallback mUnoccludeFromDreamFinishedCallback;
+
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() {
@Override
@@ -642,6 +665,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
switch (simState) {
case TelephonyManager.SIM_STATE_NOT_READY:
case TelephonyManager.SIM_STATE_ABSENT:
+ case TelephonyManager.SIM_STATE_UNKNOWN:
+ mPendingPinLock = false;
// only force lock screen in case of missing sim if user hasn't
// gone through setup wizard
synchronized (KeyguardViewMediator.this) {
@@ -706,9 +731,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
}
break;
- case TelephonyManager.SIM_STATE_UNKNOWN:
- mPendingPinLock = false;
- break;
default:
if (DEBUG_SIM_STATES) Log.v(TAG, "Unspecific state: " + simState);
break;
@@ -804,6 +826,25 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false);
mKeyguardDisplayManager.hide();
mUpdateMonitor.startBiometricWatchdog();
+
+ // It's possible that the device was unlocked (via BOUNCER or Fingerprint) while
+ // dreaming. It's time to wake up.
+ if (mUnlockingAndWakingFromDream) {
+ Log.d(TAG, "waking from dream after unlock");
+ setUnlockAndWakeFromDream(false, WakeAndUnlockUpdateReason.FULFILL);
+
+ if (mKeyguardStateController.isShowing()) {
+ Log.d(TAG, "keyguard showing after keyguardGone, dismiss");
+ mKeyguardViewControllerLazy.get()
+ .notifyKeyguardAuthenticated(!mWakeAndUnlocking);
+ } else {
+ Log.d(TAG, "keyguard gone, waking up from dream");
+ mPM.wakeUp(SystemClock.uptimeMillis(),
+ mWakeAndUnlocking ? PowerManager.WAKE_REASON_BIOMETRIC
+ : PowerManager.WAKE_REASON_GESTURE,
+ "com.android.systemui:UNLOCK_DREAMING");
+ }
+ }
Trace.endSection();
}
@@ -1165,6 +1206,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
getRemoteSurfaceAlphaApplier().accept(0.0f);
mDreamingToLockscreenTransitionViewModel.get()
.startTransition();
+ mUnoccludeFromDreamFinishedCallback = finishedCallback;
return;
}
@@ -1244,6 +1286,19 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
};
}
+ private Consumer<TransitionStep> getFinishedCallbackConsumer() {
+ return (TransitionStep step) -> {
+ if (mUnoccludeFromDreamFinishedCallback == null) return;
+ try {
+ mUnoccludeFromDreamFinishedCallback.onAnimationFinished();
+ mUnoccludeFromDreamFinishedCallback = null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Wasn't able to callback", e);
+ }
+ mInteractionJankMonitor.end(CUJ_LOCKSCREEN_OCCLUSION);
+ };
+ }
+
private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters;
@@ -1503,6 +1558,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
collectFlow(viewRootImpl.getView(),
mDreamingToLockscreenTransitionViewModel.get().getDreamOverlayAlpha(),
getRemoteSurfaceAlphaApplier(), mMainDispatcher);
+ collectFlow(viewRootImpl.getView(),
+ mDreamingToLockscreenTransitionViewModel.get().getTransitionEnded(),
+ getFinishedCallbackConsumer(), mMainDispatcher);
}
}
// Most services aren't available until the system reaches the ready state, so we
@@ -2615,6 +2673,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mKeyguardExitAnimationRunner = null;
mWakeAndUnlocking = false;
+ setUnlockAndWakeFromDream(false, WakeAndUnlockUpdateReason.SHOW);
setPendingLock(false);
// Force if we we're showing in the middle of hiding, to ensure we end up in the correct
@@ -2720,6 +2779,51 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
tryKeyguardDone();
};
+ private void setUnlockAndWakeFromDream(boolean updatedValue,
+ @WakeAndUnlockUpdateReason int reason) {
+ if (updatedValue == mUnlockingAndWakingFromDream) {
+ return;
+ }
+
+ final String reasonDescription;
+
+ switch(reason) {
+ case WakeAndUnlockUpdateReason.FULFILL:
+ reasonDescription = "fulfilling existing request";
+ break;
+ case WakeAndUnlockUpdateReason.HIDE:
+ reasonDescription = "hiding keyguard";
+ break;
+ case WakeAndUnlockUpdateReason.SHOW:
+ reasonDescription = "showing keyguard";
+ break;
+ case WakeAndUnlockUpdateReason.WAKE_AND_UNLOCK:
+ reasonDescription = "waking to unlock";
+ break;
+ default:
+ throw new IllegalStateException("Unexpected value: " + reason);
+ }
+
+ final boolean unsetUnfulfilled = !updatedValue
+ && reason != WakeAndUnlockUpdateReason.FULFILL;
+
+ mUnlockingAndWakingFromDream = updatedValue;
+
+ final String description;
+
+ if (unsetUnfulfilled) {
+ description = "Interrupting request to wake and unlock";
+ } else if (mUnlockingAndWakingFromDream) {
+ description = "Initiating request to wake and unlock";
+ } else {
+ description = "Fulfilling request to wake and unlock";
+ }
+
+ Log.d(TAG, String.format(
+ "Updating waking and unlocking request to %b. description:[%s]. reason:[%s]",
+ mUnlockingAndWakingFromDream, description, reasonDescription));
+ }
+
/**
* Handle message sent by {@link #hideLocked()}
* @see #HIDE
@@ -2739,7 +2843,16 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mHiding = true;
- if (mShowing && !mOccluded) {
+ // If waking and unlocking, waking from dream has been set properly.
+ if (!mWakeAndUnlocking) {
+ setUnlockAndWakeFromDream(mStatusBarStateController.isDreaming()
+ && mPM.isInteractive(), WakeAndUnlockUpdateReason.HIDE);
+ }
+
+ if ((mShowing && !mOccluded) || mUnlockingAndWakingFromDream) {
+ if (mUnlockingAndWakingFromDream) {
+ Log.d(TAG, "hiding keyguard before waking from dream");
+ }
mKeyguardGoingAwayRunnable.run();
} else {
// TODO(bc-unlock): Fill parameters
@@ -2750,13 +2863,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
null /* nonApps */, null /* finishedCallback */);
});
}
-
- // It's possible that the device was unlocked (via BOUNCER or Fingerprint) while
- // dreaming. It's time to wake up.
- if (mDreamOverlayShowing) {
- mPM.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
- "com.android.systemui:UNLOCK_DREAMING");
- }
}
Trace.endSection();
}
@@ -2926,6 +3032,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
private void onKeyguardExitFinished() {
+ if (DEBUG) Log.d(TAG, "onKeyguardExitFinished()");
// only play "unlock" noises if not on a call (since the incall UI
// disables the keyguard)
if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {
@@ -3147,13 +3254,14 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
flags |= StatusBarManager.DISABLE_RECENT;
}
- if (mPowerGestureIntercepted) {
+ if (mPowerGestureIntercepted && mOccluded && isSecure()) {
flags |= StatusBarManager.DISABLE_RECENT;
}
if (DEBUG) {
Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mOccluded=" + mOccluded
+ " isSecure=" + isSecure() + " force=" + forceHideHomeRecentsButtons
+ + " mPowerGestureIntercepted=" + mPowerGestureIntercepted
+ " --> flags=0x" + Integer.toHexString(flags));
}
@@ -3241,9 +3349,14 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
}
- public void onWakeAndUnlocking() {
+ /**
+ * Informs the keyguard view mediator that the device is waking and unlocking.
+ * @param fromDream Whether waking and unlocking is happening over an interactive dream.
+ */
+ public void onWakeAndUnlocking(boolean fromDream) {
Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
mWakeAndUnlocking = true;
+ setUnlockAndWakeFromDream(fromDream, WakeAndUnlockUpdateReason.WAKE_AND_UNLOCK);
mKeyguardViewControllerLazy.get().notifyKeyguardAuthenticated(/* primaryAuth */ false);
userActivity();
@@ -3381,6 +3494,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
pw.print(" mPendingLock: "); pw.println(mPendingLock);
pw.print(" wakeAndUnlocking: "); pw.println(mWakeAndUnlocking);
pw.print(" mPendingPinLock: "); pw.println(mPendingPinLock);
+ pw.print(" mPowerGestureIntercepted: "); pw.println(mPowerGestureIntercepted);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 42f12f82d9a7..41a81a83d06d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -49,11 +49,15 @@ constructor(
) {
/** (any)->GONE transition information */
val anyStateToGoneTransition: Flow<TransitionStep> =
- repository.transitions.filter { step -> step.to == KeyguardState.GONE }
+ repository.transitions.filter { step -> step.to == GONE }
/** (any)->AOD transition information */
val anyStateToAodTransition: Flow<TransitionStep> =
- repository.transitions.filter { step -> step.to == KeyguardState.AOD }
+ repository.transitions.filter { step -> step.to == AOD }
+
+ /** DREAMING->(any) transition information. */
+ val fromDreamingTransition: Flow<TransitionStep> =
+ repository.transitions.filter { step -> step.from == DREAMING }
/** AOD->LOCKSCREEN transition information. */
val aodToLockscreenTransition: Flow<TransitionStep> = repository.transition(AOD, LOCKSCREEN)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index a8d662c96284..5ad6e5196f66 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -377,9 +377,9 @@ object KeyguardBottomAreaViewBinder {
Utils.getColorAttrDefaultColor(
view.context,
if (viewModel.isActivated) {
- com.android.internal.R.attr.textColorPrimaryInverse
+ com.android.internal.R.attr.materialColorOnPrimaryFixed
} else {
- com.android.internal.R.attr.textColorPrimary
+ com.android.internal.R.attr.materialColorOnSurface
},
)
)
@@ -389,9 +389,9 @@ object KeyguardBottomAreaViewBinder {
Utils.getColorAttr(
view.context,
if (viewModel.isActivated) {
- com.android.internal.R.attr.colorAccentPrimary
+ com.android.internal.R.attr.materialColorPrimaryFixed
} else {
- com.android.internal.R.attr.colorSurface
+ com.android.internal.R.attr.materialColorSurfaceContainerHigh
}
)
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 1c2e85b0fd3a..b92d10474ccd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -346,6 +346,10 @@ constructor(
?.largeClock
?.events
?.onTargetRegionChanged(KeyguardClockSwitch.getLargeClockRegion(parentView))
+ clockController.clock
+ ?.smallClock
+ ?.events
+ ?.onTargetRegionChanged(KeyguardClockSwitch.getSmallClockRegion(parentView))
}
}
parentView.addOnLayoutChangeListener(layoutChangeListener)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/UdfpsLottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/UdfpsLottieViewWrapper.kt
new file mode 100644
index 000000000000..3a2c3c70a452
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/UdfpsLottieViewWrapper.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.keyguard.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import com.android.systemui.util.wrapper.LottieViewWrapper
+
+class UdfpsLottieViewWrapper
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index 9ca4bd62b6fe..e24d326850e0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -48,7 +48,7 @@ constructor(
)
val transitionEnded =
- keyguardTransitionInteractor.dreamingToLockscreenTransition.filter { step ->
+ keyguardTransitionInteractor.fromDreamingTransition.filter { step ->
step.transitionState == TransitionState.FINISHED ||
step.transitionState == TransitionState.CANCELED
}
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
index 34a67403fc84..e06483990c90 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
@@ -167,9 +167,10 @@ class ViewLifecycleOwner(
registry.currentState = Lifecycle.State.DESTROYED
}
- override fun getLifecycle(): Lifecycle {
- return registry
- }
+ override val lifecycle: Lifecycle
+ get() {
+ return registry
+ }
private fun updateState() {
registry.currentState =
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
index b0389b50cd7d..23ee00d88fdc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
@@ -122,9 +122,9 @@ constructor(
Log.e(TAG, "Error getting package information", e)
}
- Log.d(TAG, "Adding resume controls $desc")
+ Log.d(TAG, "Adding resume controls for ${browser.userId}: $desc")
mediaDataManager.addResumptionControls(
- currentUserId,
+ browser.userId,
desc,
resumeAction,
token,
@@ -196,7 +196,11 @@ constructor(
}
resumeComponents.add(component to lastPlayed)
}
- Log.d(TAG, "loaded resume components ${resumeComponents.toArray().contentToString()}")
+ Log.d(
+ TAG,
+ "loaded resume components for $currentUserId: " +
+ "${resumeComponents.toArray().contentToString()}"
+ )
if (needsUpdate) {
// Save any missing times that we had to fill in
@@ -210,11 +214,21 @@ constructor(
return
}
+ val pm = context.packageManager
val now = systemClock.currentTimeMillis()
resumeComponents.forEach {
if (now.minus(it.second) <= RESUME_MEDIA_TIMEOUT) {
- val browser = mediaBrowserFactory.create(mediaBrowserCallback, it.first)
- browser.findRecentMedia()
+ // Verify that the service exists for this user
+ val intent = Intent(MediaBrowserService.SERVICE_INTERFACE)
+ intent.component = it.first
+ val inf = pm.resolveServiceAsUser(intent, 0, currentUserId)
+ if (inf != null) {
+ val browser =
+ mediaBrowserFactory.create(mediaBrowserCallback, it.first, currentUserId)
+ browser.findRecentMedia()
+ } else {
+ Log.d(TAG, "User $currentUserId does not have component ${it.first}")
+ }
}
}
}
@@ -244,7 +258,7 @@ constructor(
Log.d(TAG, "Checking for service component for " + data.packageName)
val pm = context.packageManager
val serviceIntent = Intent(MediaBrowserService.SERVICE_INTERFACE)
- val resumeInfo = pm.queryIntentServices(serviceIntent, 0)
+ val resumeInfo = pm.queryIntentServicesAsUser(serviceIntent, 0, currentUserId)
val inf = resumeInfo?.filter { it.serviceInfo.packageName == data.packageName }
if (inf != null && inf.size > 0) {
@@ -280,13 +294,17 @@ constructor(
browser: ResumeMediaBrowser
) {
// Since this is a test, just save the component for later
- Log.d(TAG, "Can get resumable media from $componentName")
+ Log.d(
+ TAG,
+ "Can get resumable media for ${browser.userId} from $componentName"
+ )
mediaDataManager.setResumeAction(key, getResumeAction(componentName))
updateResumptionList(componentName)
mediaBrowser = null
}
},
- componentName
+ componentName,
+ currentUserId
)
mediaBrowser?.testConnection()
}
@@ -326,7 +344,7 @@ constructor(
/** Get a runnable which will resume media playback */
private fun getResumeAction(componentName: ComponentName): Runnable {
return Runnable {
- mediaBrowser = mediaBrowserFactory.create(null, componentName)
+ mediaBrowser = mediaBrowserFactory.create(null, componentName, currentUserId)
mediaBrowser?.restart()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
index d460b5b5d782..ceaccafd8f40 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowser.java
@@ -17,6 +17,7 @@
package com.android.systemui.media.controls.resume;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -53,6 +54,7 @@ public class ResumeMediaBrowser {
private final ResumeMediaBrowserLogger mLogger;
private final ComponentName mComponentName;
private final MediaController.Callback mMediaControllerCallback = new SessionDestroyCallback();
+ @UserIdInt private final int mUserId;
private MediaBrowser mMediaBrowser;
@Nullable private MediaController mMediaController;
@@ -62,18 +64,21 @@ public class ResumeMediaBrowser {
* @param context the context
* @param callback used to report media items found
* @param componentName Component name of the MediaBrowserService this browser will connect to
+ * @param userId ID of the current user
*/
public ResumeMediaBrowser(
Context context,
@Nullable Callback callback,
ComponentName componentName,
MediaBrowserFactory browserFactory,
- ResumeMediaBrowserLogger logger) {
+ ResumeMediaBrowserLogger logger,
+ @UserIdInt int userId) {
mContext = context;
mCallback = callback;
mComponentName = componentName;
mBrowserFactory = browserFactory;
mLogger = logger;
+ mUserId = userId;
}
/**
@@ -285,6 +290,14 @@ public class ResumeMediaBrowser {
}
/**
+ * Get the ID of the user associated with this broswer
+ * @return the user ID
+ */
+ public @UserIdInt int getUserId() {
+ return mUserId;
+ }
+
+ /**
* Get the media session token
* @return the token, or null if the MediaBrowser is null or disconnected
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserFactory.java b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserFactory.java
index c558227df0b5..e37419127f5b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserFactory.java
@@ -16,6 +16,7 @@
package com.android.systemui.media.controls.resume;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
@@ -42,10 +43,12 @@ public class ResumeMediaBrowserFactory {
*
* @param callback will be called on connection or error, and addTrack when media item found
* @param componentName component to browse
+ * @param userId ID of the current user
* @return
*/
public ResumeMediaBrowser create(ResumeMediaBrowser.Callback callback,
- ComponentName componentName) {
- return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory, mLogger);
+ ComponentName componentName, @UserIdInt int userId) {
+ return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory, mLogger,
+ userId);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
index 30ee147e302a..2883210805d3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
@@ -128,6 +128,15 @@ constructor(
var visibilityChangedListener: ((Boolean) -> Unit)? = null
+ /**
+ * Whether the doze wake up animation is delayed and we are currently waiting for it to start.
+ */
+ var isDozeWakeUpAnimationWaiting: Boolean = false
+ set(value) {
+ field = value
+ refreshMediaPosition()
+ }
+
/** single pane media container placed at the top of the notifications list */
var singlePaneContainer: MediaContainerView? = null
private set
@@ -221,7 +230,13 @@ constructor(
// by the clock. This is not the case for single-line clock though.
// For single shade, we don't need to do it, because media is a child of NSSL, which already
// gets hidden on AOD.
- return !statusBarStateController.isDozing
+ // Media also has to be hidden when waking up from dozing, and the doze wake up animation is
+ // delayed and waiting to be started.
+ // This is to stay in sync with the delaying of the horizontal alignment of the rest of the
+ // keyguard container, that is also delayed until the "wait" is over.
+ // If we show media during this waiting period, the shade will still be centered, and using
+ // the entire width of the screen, and making media show fully stretched.
+ return !statusBarStateController.isDozing && !isDozeWakeUpAnimationWaiting
}
private fun showMediaPlayer() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 318cd99a06ed..26a7d048cf27 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -20,6 +20,7 @@ import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECT
import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_NONE;
import static com.android.settingslib.media.MediaDevice.SelectionBehavior.SELECTION_BEHAVIOR_TRANSFER;
+import android.annotation.DrawableRes;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.AnimatedVectorDrawable;
@@ -181,27 +182,23 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mController.getSelectedMediaDevice(), device)));
boolean isHost = device.isHostForOngoingSession()
&& isActiveWithOngoingSession;
- if (isHost) {
+ if (isActiveWithOngoingSession) {
mCurrentActivePosition = position;
updateTitleIcon(R.drawable.media_output_icon_volume,
mController.getColorItemContent());
mSubTitleText.setText(device.getSubtextString());
updateTwoLineLayoutContentAlpha(DEVICE_CONNECTED_ALPHA);
- updateEndClickAreaAsSessionEditing(device);
+ updateEndClickAreaAsSessionEditing(device,
+ isHost ? R.drawable.media_output_status_edit_session
+ : R.drawable.ic_sound_bars_anim);
setTwoLineLayout(device, null /* title */, true /* bFocused */,
true /* showSeekBar */, false /* showProgressBar */,
true /* showSubtitle */, false /* showStatus */,
true /* showEndTouchArea */, false /* isFakeActive */);
initSeekbar(device, isCurrentSeekbarInvisible);
} else {
- if (isActiveWithOngoingSession) {
- //Selected device which has ongoing session, disable seekbar since we
- //only allow volume control on Host
+ if (currentlyConnected) {
mCurrentActivePosition = position;
- }
- boolean showSeekbar =
- (!device.hasOngoingSession() && currentlyConnected);
- if (showSeekbar) {
updateTitleIcon(R.drawable.media_output_icon_volume,
mController.getColorItemContent());
initSeekbar(device, isCurrentSeekbarInvisible);
@@ -222,10 +219,10 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
updateClickActionBasedOnSelectionBehavior(device)
? DEVICE_CONNECTED_ALPHA : DEVICE_DISCONNECTED_ALPHA);
setTwoLineLayout(device, currentlyConnected /* bFocused */,
- showSeekbar /* showSeekBar */,
+ currentlyConnected /* showSeekBar */,
false /* showProgressBar */, true /* showSubtitle */,
deviceStatusIcon != null /* showStatus */,
- isActiveWithOngoingSession /* isFakeActive */);
+ false /* isFakeActive */);
}
} else if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
setUpDeviceIcon(device);
@@ -267,25 +264,16 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
setSingleLineLayout(getItemTitle(device));
} else if (device.hasOngoingSession()) {
mCurrentActivePosition = position;
- if (device.isHostForOngoingSession()) {
- updateTitleIcon(R.drawable.media_output_icon_volume,
- mController.getColorItemContent());
- updateEndClickAreaAsSessionEditing(device);
- mEndClickIcon.setVisibility(View.VISIBLE);
- setSingleLineLayout(getItemTitle(device), true /* showSeekBar */,
- false /* showProgressBar */, false /* showCheckBox */,
- true /* showEndTouchArea */);
- initSeekbar(device, isCurrentSeekbarInvisible);
- } else {
- updateDeviceStatusIcon(mContext.getDrawable(
- R.drawable.ic_sound_bars_anim));
- mStatusIcon.setVisibility(View.VISIBLE);
- updateSingleLineLayoutContentAlpha(
- updateClickActionBasedOnSelectionBehavior(device)
- ? DEVICE_CONNECTED_ALPHA : DEVICE_DISCONNECTED_ALPHA);
- setSingleLineLayout(getItemTitle(device));
- initFakeActiveDevice();
- }
+ updateTitleIcon(R.drawable.media_output_icon_volume,
+ mController.getColorItemContent());
+ updateEndClickAreaAsSessionEditing(device, device.isHostForOngoingSession()
+ ? R.drawable.media_output_status_edit_session
+ : R.drawable.ic_sound_bars_anim);
+ mEndClickIcon.setVisibility(View.VISIBLE);
+ setSingleLineLayout(getItemTitle(device), true /* showSeekBar */,
+ false /* showProgressBar */, false /* showCheckBox */,
+ true /* showEndTouchArea */);
+ initSeekbar(device, isCurrentSeekbarInvisible);
} else if (mController.isCurrentConnectedDeviceRemote()
&& !mController.getSelectableMediaDevice().isEmpty()) {
//If device is connected and there's other selectable devices, layout as
@@ -362,7 +350,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mStatusIcon.setAlpha(alphaValue);
}
- private void updateEndClickAreaAsSessionEditing(MediaDevice device) {
+ private void updateEndClickAreaAsSessionEditing(MediaDevice device, @DrawableRes int id) {
mEndClickIcon.setOnClickListener(null);
mEndTouchArea.setOnClickListener(null);
updateEndClickAreaColor(mController.getColorSeekbarProgress());
@@ -371,6 +359,11 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mEndClickIcon.setOnClickListener(
v -> mController.tryToLaunchInAppRoutingIntent(device.getId(), v));
mEndTouchArea.setOnClickListener(v -> mEndClickIcon.performClick());
+ Drawable drawable = mContext.getDrawable(id);
+ mEndClickIcon.setImageDrawable(drawable);
+ if (drawable instanceof AnimatedVectorDrawable) {
+ ((AnimatedVectorDrawable) drawable).start();
+ }
}
public void updateEndClickAreaColor(int color) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
index c70cce9fec26..2fafba1f188a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
@@ -120,6 +120,7 @@ class AutoAddTracker @VisibleForTesting constructor(
val tilesToRemove = restoredAutoAdded.filter { it !in restoredTiles }
if (tilesToRemove.isNotEmpty()) {
+ Log.d(TAG, "Removing tiles: $tilesToRemove")
qsHost.removeTiles(tilesToRemove)
}
val tiles = synchronized(autoAdded) {
@@ -255,6 +256,7 @@ class AutoAddTracker @VisibleForTesting constructor(
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.println("Current user: $userId")
+ pw.println("Restored tiles: $restoredTiles")
pw.println("Added tiles: $autoAdded")
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 59b94b7c4bd4..868dbfa58156 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -302,7 +302,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
if (tile != null && (!(tile instanceof CustomTile)
|| ((CustomTile) tile).getUser() == currentUser)) {
if (tile.isAvailable()) {
- if (DEBUG) Log.d(TAG, "Adding " + tile);
+ Log.d(TAG, "Adding " + tile);
tile.removeCallbacks();
if (!(tile instanceof CustomTile) && mCurrentUser != currentUser) {
tile.userSwitch(currentUser);
@@ -421,6 +421,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
// When calling this, you may want to modify mTilesListDirty accordingly.
@MainThread
private void saveTilesToSettings(List<String> tileSpecs) {
+ Log.d(TAG, "Saving tiles: " + tileSpecs + " for user: " + mCurrentUser);
mSecureSettings.putStringForUser(TILES_SETTING, TextUtils.join(",", tileSpecs),
null /* tag */, false /* default */, mCurrentUser,
true /* overrideable by restore */);
@@ -494,7 +495,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
lifecycleManager.flushMessagesAndUnbind();
}
}
- if (DEBUG) Log.d(TAG, "saveCurrentTiles " + newTiles);
+ Log.d(TAG, "saveCurrentTiles " + newTiles);
mTilesListDirty = true;
saveTilesToSettings(newTiles);
}
@@ -565,9 +566,9 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
if (TextUtils.isEmpty(tileList)) {
tileList = res.getString(R.string.quick_settings_tiles);
- if (DEBUG) Log.d(TAG, "Loaded tile specs from default config: " + tileList);
+ Log.d(TAG, "Loaded tile specs from default config: " + tileList);
} else {
- if (DEBUG) Log.d(TAG, "Loaded tile specs from setting: " + tileList);
+ Log.d(TAG, "Loaded tile specs from setting: " + tileList);
}
final ArrayList<String> tiles = new ArrayList<String>();
boolean addedDefault = false;
@@ -613,6 +614,10 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, P
@Override
public void dump(PrintWriter pw, String[] args) {
pw.println("QSTileHost:");
+ pw.println("tile specs: " + mTileSpecs);
+ pw.println("current user: " + mCurrentUser);
+ pw.println("is dirty: " + mTilesListDirty);
+ pw.println("tiles:");
mTiles.values().stream().filter(obj -> obj instanceof Dumpable)
.forEach(o -> ((Dumpable) o).dump(pw, args));
}
diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayEducationLottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayEducationLottieViewWrapper.kt
new file mode 100644
index 000000000000..716a4d649665
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayEducationLottieViewWrapper.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.reardisplay
+
+import android.content.Context
+import android.util.AttributeSet
+import com.android.systemui.util.wrapper.LottieViewWrapper
+
+class RearDisplayEducationLottieViewWrapper
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 776a90d75a75..267b147fa09a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1172,6 +1172,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();
mKeyguardStatusViewController.init();
+ mKeyguardStatusViewController.setSplitShadeEnabled(mSplitShadeEnabled);
updateClockAppearance();
if (mKeyguardUserSwitcherController != null) {
@@ -1224,6 +1225,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
private void onSplitShadeEnabledChanged() {
mShadeLog.logSplitShadeChanged(mSplitShadeEnabled);
+ mKeyguardStatusViewController.setSplitShadeEnabled(mSplitShadeEnabled);
// Reset any left over overscroll state. It is a rare corner case but can happen.
mQsController.setOverScrollAmount(0);
mScrimController.setNotificationsOverScrollAmount(0);
@@ -1619,6 +1621,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mWillPlayDelayedDozeAmountAnimation = willPlay;
mWakeUpCoordinator.logDelayingClockWakeUpAnimation(willPlay);
+ mKeyguardMediaController.setDozeWakeUpAnimationWaiting(willPlay);
// Once changing this value, see if we should move the clock.
positionClockAndNotifications();
@@ -3560,6 +3563,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
private void endMotionEvent(MotionEvent event, float x, float y, boolean forceCancel) {
+ mShadeLog.logEndMotionEvent("endMotionEvent called", forceCancel, false);
mTrackingPointer = -1;
mAmbientState.setSwipingUp(false);
if ((mTracking && mTouchSlopExceeded) || Math.abs(x - mInitialExpandX) > mTouchSlop
@@ -3581,15 +3585,19 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
} else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
if (onKeyguard) {
expand = true;
+ mShadeLog.logEndMotionEvent("endMotionEvent: cancel while on keyguard",
+ forceCancel, expand);
} else if (mCentralSurfaces.isBouncerShowingOverDream()) {
expand = false;
} else {
// If we get a cancel, put the shade back to the state it was in when the
// gesture started
expand = !mPanelClosedOnDown;
+ mShadeLog.logEndMotionEvent("endMotionEvent: cancel", forceCancel, expand);
}
} else {
expand = flingExpands(vel, vectorVel, x, y);
+ mShadeLog.logEndMotionEvent("endMotionEvent: flingExpands", forceCancel, expand);
}
mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
@@ -4685,6 +4693,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mTouchSlopExceeded = mTouchSlopExceededBeforeDown;
mMotionAborted = false;
mPanelClosedOnDown = isFullyCollapsed();
+ mShadeLog.logPanelClosedOnDown("intercept down touch", mPanelClosedOnDown,
+ mExpandedFraction);
mCollapsedAndHeadsUpOnDown = false;
mHasLayoutedSinceDown = false;
mUpdateFlingOnLayout = false;
@@ -4898,6 +4908,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
mMinExpandHeight = 0.0f;
mPanelClosedOnDown = isFullyCollapsed();
+ mShadeLog.logPanelClosedOnDown("handle down touch", mPanelClosedOnDown,
+ mExpandedFraction);
mHasLayoutedSinceDown = false;
mUpdateFlingOnLayout = false;
mMotionAborted = false;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index 2da8d5f4d921..4fdd6e19cc4c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -90,7 +90,7 @@ class ShadeLogger @Inject constructor(@ShadeLog private val buffer: LogBuffer) {
double1 = event.y.toDouble()
},
{
- "$str1\neventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2"
+ "$str1: eventTime=$long1,downTime=$long2,y=$double1,action=$int1,class=$int2"
}
)
}
@@ -280,6 +280,42 @@ class ShadeLogger @Inject constructor(@ShadeLog private val buffer: LogBuffer) {
)
}
+ fun logEndMotionEvent(
+ msg: String,
+ forceCancel: Boolean,
+ expand: Boolean,
+ )
+ {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = msg
+ bool1 = forceCancel
+ bool2 = expand
+ },
+ { "$str1; force=$bool1; expand=$bool2" }
+ )
+ }
+
+ fun logPanelClosedOnDown(
+ msg: String,
+ panelClosedOnDown: Boolean,
+ expandFraction: Float,
+ )
+ {
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = msg
+ bool1 = panelClosedOnDown
+ double1 = expandFraction.toDouble()
+ },
+ { "$str1; mPanelClosedOnDown=$bool1; mExpandedFraction=$double1" }
+ )
+ }
+
fun flingQs(flingType: Int, isClick: Boolean) {
buffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
index 06f43f1eeaa5..906c5ed0fb89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -534,19 +534,7 @@ public final class KeyboardShortcutListSearch {
new ShortcutKeyGroupMultiMappingInfo(
context.getString(R.string.group_system_access_google_assistant),
Arrays.asList(
- Pair.create(KeyEvent.KEYCODE_A, KeyEvent.META_META_ON))),
- /* Lock screen: Meta + L */
- new ShortcutKeyGroupMultiMappingInfo(
- context.getString(R.string.group_system_lock_screen),
- Arrays.asList(
- Pair.create(KeyEvent.KEYCODE_L, KeyEvent.META_META_ON))),
- /* Pull up Notes app for quick memo: Meta + Ctrl + N */
- new ShortcutKeyGroupMultiMappingInfo(
- context.getString(R.string.group_system_quick_memo),
- Arrays.asList(
- Pair.create(
- KeyEvent.KEYCODE_N,
- KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON)))
+ Pair.create(KeyEvent.KEYCODE_A, KeyEvent.META_META_ON)))
);
for (ShortcutKeyGroupMultiMappingInfo info : infoList) {
systemGroup.addItem(info.getShortcutMultiMappingInfo());
@@ -588,21 +576,12 @@ public final class KeyboardShortcutListSearch {
new ArrayList<>());
// System multitasking shortcuts:
- // Enter Split screen with current app to RHS: Meta + Ctrl + Right arrow
- // Enter Split screen with current app to LHS: Meta + Ctrl + Left arrow
// Switch from Split screen to full screen: Meta + Ctrl + Up arrow
- // During Split screen: replace an app from one to another: Meta + Ctrl + Down arrow
String[] shortcutLabels = {
- context.getString(R.string.system_multitasking_rhs),
- context.getString(R.string.system_multitasking_lhs),
context.getString(R.string.system_multitasking_full_screen),
- context.getString(R.string.system_multitasking_replace)
};
int[] keyCodes = {
- KeyEvent.KEYCODE_DPAD_RIGHT,
- KeyEvent.KEYCODE_DPAD_LEFT,
KeyEvent.KEYCODE_DPAD_UP,
- KeyEvent.KEYCODE_DPAD_DOWN
};
for (int i = 0; i < shortcutLabels.length; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index fb88a96c38c2..763400b307fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -27,10 +27,12 @@ import android.app.Notification;
import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.hardware.display.DisplayManager;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSession;
@@ -41,6 +43,7 @@ import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.Log;
+import android.view.Display;
import android.view.View;
import android.widget.ImageView;
@@ -74,11 +77,15 @@ import com.android.systemui.util.concurrency.DelayableExecutor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Comparator;
import java.util.HashSet;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
import dagger.Lazy;
@@ -138,6 +145,14 @@ public class NotificationMediaManager implements Dumpable {
private BackDropView mBackdrop;
private ImageView mBackdropFront;
private ImageView mBackdropBack;
+ private final Point mTmpDisplaySize = new Point();
+
+ private final DisplayManager mDisplayManager;
+ @Nullable
+ private List<String> mSmallerInternalDisplayUids;
+ private Display mCurrentDisplay;
+
+ private LockscreenWallpaper.WallpaperDrawable mWallapperDrawable;
private final MediaController.Callback mMediaListener = new MediaController.Callback() {
@Override
@@ -184,7 +199,8 @@ public class NotificationMediaManager implements Dumpable {
SysuiColorExtractor colorExtractor,
KeyguardStateController keyguardStateController,
DumpManager dumpManager,
- WallpaperManager wallpaperManager) {
+ WallpaperManager wallpaperManager,
+ DisplayManager displayManager) {
mContext = context;
mMediaArtworkProcessor = mediaArtworkProcessor;
mKeyguardBypassController = keyguardBypassController;
@@ -200,6 +216,7 @@ public class NotificationMediaManager implements Dumpable {
mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor;
mKeyguardStateController = keyguardStateController;
+ mDisplayManager = displayManager;
mIsLockscreenLiveWallpaperEnabled = wallpaperManager.isLockscreenLiveWallpaperEnabled();
setupNotifPipeline();
@@ -477,6 +494,48 @@ public class NotificationMediaManager implements Dumpable {
}
/**
+ * Notify lockscreen wallpaper drawable the current internal display.
+ */
+ public void onDisplayUpdated(Display display) {
+ Trace.beginSection("NotificationMediaManager#onDisplayUpdated");
+ mCurrentDisplay = display;
+ if (mWallapperDrawable != null) {
+ mWallapperDrawable.onDisplayUpdated(isOnSmallerInternalDisplays());
+ }
+ Trace.endSection();
+ }
+
+ private boolean isOnSmallerInternalDisplays() {
+ if (mSmallerInternalDisplayUids == null) {
+ mSmallerInternalDisplayUids = findSmallerInternalDisplayUids();
+ }
+ return mSmallerInternalDisplayUids.contains(mCurrentDisplay.getUniqueId());
+ }
+
+ private List<String> findSmallerInternalDisplayUids() {
+ if (mSmallerInternalDisplayUids != null) {
+ return mSmallerInternalDisplayUids;
+ }
+ List<Display> internalDisplays = Arrays.stream(mDisplayManager.getDisplays(
+ DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED))
+ .filter(display -> display.getType() == Display.TYPE_INTERNAL)
+ .collect(Collectors.toList());
+ if (internalDisplays.isEmpty()) {
+ return List.of();
+ }
+ Display largestDisplay = internalDisplays.stream()
+ .max(Comparator.comparingInt(this::getRealDisplayArea))
+ .orElse(internalDisplays.get(0));
+ internalDisplays.remove(largestDisplay);
+ return internalDisplays.stream().map(Display::getUniqueId).collect(Collectors.toList());
+ }
+
+ private int getRealDisplayArea(Display display) {
+ display.getRealSize(mTmpDisplaySize);
+ return mTmpDisplaySize.x * mTmpDisplaySize.y;
+ }
+
+ /**
* Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
*/
public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
@@ -551,7 +610,7 @@ public class NotificationMediaManager implements Dumpable {
mLockscreenWallpaper != null ? mLockscreenWallpaper.getBitmap() : null;
if (lockWallpaper != null) {
artworkDrawable = new LockscreenWallpaper.WallpaperDrawable(
- mBackdropBack.getResources(), lockWallpaper);
+ mBackdropBack.getResources(), lockWallpaper, isOnSmallerInternalDisplays());
// We're in the SHADE mode on the SIM screen - yet we still need to show
// the lockscreen wallpaper in that mode.
allowWhenShade = mStatusBarStateController.getState() == KEYGUARD;
@@ -611,6 +670,10 @@ public class NotificationMediaManager implements Dumpable {
mBackdropBack.setBackgroundColor(0xFFFFFFFF);
mBackdropBack.setImageDrawable(new ColorDrawable(c));
} else {
+ if (artworkDrawable instanceof LockscreenWallpaper.WallpaperDrawable) {
+ mWallapperDrawable =
+ (LockscreenWallpaper.WallpaperDrawable) artworkDrawable;
+ }
mBackdropBack.setImageDrawable(artworkDrawable);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index f6c9a5cae34a..c67e81f1c5c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.dagger;
import android.app.IActivityManager;
import android.app.WallpaperManager;
import android.content.Context;
+import android.hardware.display.DisplayManager;
import android.os.RemoteException;
import android.service.dreams.IDreamManager;
import android.util.Log;
@@ -144,7 +145,8 @@ public interface CentralSurfacesDependenciesModule {
SysuiColorExtractor colorExtractor,
KeyguardStateController keyguardStateController,
DumpManager dumpManager,
- WallpaperManager wallpaperManager) {
+ WallpaperManager wallpaperManager,
+ DisplayManager displayManager) {
return new NotificationMediaManager(
context,
centralSurfacesOptionalLazy,
@@ -160,7 +162,8 @@ public interface CentralSurfacesDependenciesModule {
colorExtractor,
keyguardStateController,
dumpManager,
- wallpaperManager);
+ wallpaperManager,
+ displayManager);
}
/** */
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 518825cea5e0..6c1dc8c0a51d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -124,6 +124,7 @@ constructor(
private var showSensitiveContentForCurrentUser = false
private var showSensitiveContentForManagedUser = false
private var managedUserHandle: UserHandle? = null
+ private var mSplitShadeEnabled = false
// TODO(b/202758428): refactor so that we can test color updates via region samping, similar to
// how we test color updates when theme changes (See testThemeChangeUpdatesTextColor).
@@ -131,6 +132,7 @@ constructor(
// TODO: Move logic into SmartspaceView
var stateChangeListener = object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) {
+ (v as SmartspaceView).setSplitShadeEnabled(mSplitShadeEnabled)
smartspaceViews.add(v as SmartspaceView)
connectSession()
@@ -216,6 +218,11 @@ constructor(
execution.assertIsMainThread()
smartspaceViews.forEach { it.setDozeAmount(eased) }
}
+
+ override fun onDozingChanged(isDozing: Boolean) {
+ execution.assertIsMainThread()
+ smartspaceViews.forEach { it.setDozing(isDozing) }
+ }
}
private val deviceProvisionedListener =
@@ -421,6 +428,11 @@ constructor(
reloadSmartspace()
}
+ fun setSplitShadeEnabled(enabled: Boolean) {
+ mSplitShadeEnabled = enabled
+ smartspaceViews.forEach { it.setSplitShadeEnabled(enabled) }
+ }
+
/**
* Requests the smartspace session for an update.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 8aeefeeac211..d2c6d4baf817 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -840,6 +840,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable {
&& !hasFlag(entry, Notification.FLAG_ONGOING_EVENT)
&& !hasFlag(entry, Notification.FLAG_BUBBLE)
&& !hasFlag(entry, Notification.FLAG_NO_CLEAR)
+ && (entry.getChannel() == null || !entry.getChannel().isImportantConversation())
&& entry.getDismissState() != DISMISSED;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
index 62a0d138fd05..5c2f9a8d28ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
@@ -39,7 +39,10 @@ class StackCoordinator @Inject internal constructor(
override fun attach(pipeline: NotifPipeline) {
pipeline.addOnAfterRenderListListener(::onAfterRenderList)
- groupExpansionManagerImpl.attach(pipeline)
+ // TODO(b/282865576): This has an issue where it makes changes to some groups without
+ // notifying listeners. To be fixed in QPR, but for now let's comment it out to avoid the
+ // group expansion bug.
+ // groupExpansionManagerImpl.attach(pipeline)
}
fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
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 9272c376d4fe..11ba753643ac 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
@@ -411,7 +411,8 @@ public class NotificationStackScrollLayoutController {
}
};
- private final NotificationSwipeHelper.NotificationCallback mNotificationCallback =
+ @VisibleForTesting
+ final NotificationSwipeHelper.NotificationCallback mNotificationCallback =
new NotificationSwipeHelper.NotificationCallback() {
@Override
@@ -470,10 +471,11 @@ public class NotificationStackScrollLayoutController {
*/
public void handleChildViewDismissed(View view) {
+ // The View needs to clean up the Swipe states, e.g. roundness.
+ mView.onSwipeEnd();
if (mView.getClearAllInProgress()) {
return;
}
- mView.onSwipeEnd();
if (view instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
if (row.isHeadsUp()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 2d8f371aadac..ed11711f66c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -462,7 +462,10 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
Trace.endSection();
};
- if (mMode != MODE_NONE) {
+ final boolean wakingFromDream = mMode == MODE_WAKE_AND_UNLOCK_FROM_DREAM
+ && mPowerManager.isInteractive();
+
+ if (mMode != MODE_NONE && !wakingFromDream) {
wakeUp.run();
}
switch (mMode) {
@@ -498,7 +501,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
// later to awaken.
}
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
- mKeyguardViewMediator.onWakeAndUnlocking();
+ mKeyguardViewMediator.onWakeAndUnlocking(wakingFromDream);
Trace.endSection();
break;
case MODE_ONLY_WAKE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 648ece527bef..ae38105e9110 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -2267,6 +2267,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
void updateDisplaySize() {
mDisplay.getMetrics(mDisplayMetrics);
mDisplay.getSize(mCurrentDisplaySize);
+ mMediaManager.onDisplayUpdated(mDisplay);
if (DEBUG_GESTURES) {
mGestureRec.tag("display",
String.format("%dx%d", mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt
index f7426451fa50..a61914a70f59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt
@@ -209,7 +209,7 @@ constructor(
if (this.contains(other) || other.contains(this)) {
return false
}
- return this.intersect(other)
+ return this.intersects(other.left, other.top, other.right, other.bottom)
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
index c07b5e062d70..4569099eebb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -281,19 +281,25 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
/**
* Drawable that aligns left horizontally and center vertically (like ImageWallpaper).
+ *
+ * <p>Aligns to the center when showing on the smaller internal display of a multi display
+ * device.
*/
public static class WallpaperDrawable extends DrawableWrapper {
private final ConstantState mState;
private final Rect mTmpRect = new Rect();
+ private boolean mIsOnSmallerInternalDisplays;
- public WallpaperDrawable(Resources r, Bitmap b) {
- this(r, new ConstantState(b));
+ public WallpaperDrawable(Resources r, Bitmap b, boolean isOnSmallerInternalDisplays) {
+ this(r, new ConstantState(b), isOnSmallerInternalDisplays);
}
- private WallpaperDrawable(Resources r, ConstantState state) {
+ private WallpaperDrawable(Resources r, ConstantState state,
+ boolean isOnSmallerInternalDisplays) {
super(new BitmapDrawable(r, state.mBackground));
mState = state;
+ mIsOnSmallerInternalDisplays = isOnSmallerInternalDisplays;
}
@Override
@@ -332,10 +338,17 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
}
dy = (vheight - dheight * scale) * 0.5f;
+ int offsetX = 0;
+ // Offset to show the center area of the wallpaper on a smaller display for multi
+ // display device
+ if (mIsOnSmallerInternalDisplays) {
+ offsetX = bounds.centerX() - (Math.round(dwidth * scale) / 2);
+ }
+
mTmpRect.set(
- bounds.left,
+ bounds.left + offsetX,
bounds.top + Math.round(dy),
- bounds.left + Math.round(dwidth * scale),
+ bounds.left + Math.round(dwidth * scale) + offsetX,
bounds.top + Math.round(dheight * scale + dy));
super.onBoundsChange(mTmpRect);
@@ -346,6 +359,17 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
return mState;
}
+ /**
+ * Update bounds when the hosting display or the display size has changed.
+ *
+ * @param isOnSmallerInternalDisplays true if the drawable is on one of the internal
+ * displays with the smaller area.
+ */
+ public void onDisplayUpdated(boolean isOnSmallerInternalDisplays) {
+ mIsOnSmallerInternalDisplays = isOnSmallerInternalDisplays;
+ onBoundsChange(getBounds());
+ }
+
static class ConstantState extends Drawable.ConstantState {
private final Bitmap mBackground;
@@ -361,7 +385,7 @@ public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implemen
@Override
public Drawable newDrawable(@Nullable Resources res) {
- return new WallpaperDrawable(res, this);
+ return new WallpaperDrawable(res, this, /* isOnSmallerInternalDisplays= */ false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 25ecf1a424e0..c42a6dc5b6f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1509,6 +1509,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mColors.setSupportsDarkText(
ColorUtils.calculateContrast(mColors.getMainColor(), Color.WHITE) > 4.5);
}
+
+ int surface = Utils.getColorAttr(mScrimBehind.getContext(),
+ com.android.internal.R.attr.materialColorSurface).getDefaultColor();
+ for (ScrimState state : ScrimState.values()) {
+ state.setSurfaceColor(surface);
+ }
+
mNeedsDrawableColorUpdate = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 7b2028310a84..e3b65ab27f48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -122,11 +122,19 @@ public enum ScrimState {
@Override
public void prepare(ScrimState previousState) {
mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
- mBehindTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
+ mBehindTint = mClipQsScrim ? Color.BLACK : mSurfaceColor;
mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0;
mNotifTint = Color.TRANSPARENT;
mFrontAlpha = 0f;
}
+
+ @Override
+ public void setSurfaceColor(int surfaceColor) {
+ super.setSurfaceColor(surfaceColor);
+ if (!mClipQsScrim) {
+ mBehindTint = mSurfaceColor;
+ }
+ }
},
/**
@@ -295,6 +303,7 @@ public enum ScrimState {
int mFrontTint = Color.TRANSPARENT;
int mBehindTint = Color.TRANSPARENT;
int mNotifTint = Color.TRANSPARENT;
+ int mSurfaceColor = Color.TRANSPARENT;
boolean mAnimateChange = true;
float mAodFrontScrimAlpha;
@@ -409,6 +418,10 @@ public enum ScrimState {
mDefaultScrimAlpha = defaultScrimAlpha;
}
+ public void setSurfaceColor(int surfaceColor) {
+ mSurfaceColor = surfaceColor;
+ }
+
public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
}
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 1bf63be3c8b0..d97e64ee6672 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -51,6 +51,7 @@ import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardViewController;
+import com.android.keyguard.TrustGrantFlags;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
import com.android.systemui.dagger.SysUISingleton;
@@ -305,6 +306,16 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@Nullable private TaskbarDelegate mTaskbarDelegate;
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onTrustGrantedForCurrentUser(
+ boolean dismissKeyguard,
+ boolean newlyUnlocked,
+ @NonNull TrustGrantFlags flags,
+ @Nullable String message
+ ) {
+ updateAlternateBouncerShowing(mAlternateBouncerInteractor.maybeHide());
+ }
+
@Override
public void onEmergencyCallAction() {
// Since we won't get a setOccluded call we have to reset the view manually such that
@@ -430,7 +441,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mDockManager.addListener(mDockEventListener);
mIsDocked = mDockManager.isDocked();
}
- mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
}
/** Register a callback, to be invoked by the Predictive Back system. */
@@ -1564,14 +1574,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|| mode == KeyguardSecurityModel.SecurityMode.SimPuk;
}
- private KeyguardStateController.Callback mKeyguardStateControllerCallback =
- new KeyguardStateController.Callback() {
- @Override
- public void onUnlockedChanged() {
- updateAlternateBouncerShowing(mAlternateBouncerInteractor.maybeHide());
- }
- };
-
/**
* Delegate used to send show and hide events to an alternate authentication method instead of
* the regular pin/pattern/password bouncer.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 592d1aa8f43f..135307accd13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -182,7 +182,7 @@ class UnlockedScreenOffAnimationController @Inject constructor(
// Cancel any existing CUJs before starting the animation
interactionJankMonitor.cancel(CUJ_SCREEN_OFF_SHOW_AOD)
-
+ PropertyAnimator.cancelAnimation(keyguardView, AnimatableProperty.ALPHA)
PropertyAnimator.setProperty(
keyguardView, AnimatableProperty.ALPHA, 1f,
AnimationProperties()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index a47f95d69c65..74352d29cd9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -57,7 +57,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
@@ -205,9 +204,6 @@ constructor(
}
.stateIn(scope, SharingStarted.WhileSubscribed(), null)
- private val defaultDataSubIdChangeEvent: MutableSharedFlow<Unit> =
- MutableSharedFlow(extraBufferCapacity = 1)
-
override val defaultDataSubId: StateFlow<Int> =
broadcastDispatcher
.broadcastFlow(
@@ -223,7 +219,6 @@ constructor(
initialValue = INVALID_SUBSCRIPTION_ID,
)
.onStart { emit(subscriptionManagerProxy.getDefaultDataSubscriptionId()) }
- .onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
.stateIn(scope, SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
private val carrierConfigChangedEvent =
@@ -232,7 +227,7 @@ constructor(
.onEach { logger.logActionCarrierConfigChanged() }
override val defaultDataSubRatConfig: StateFlow<Config> =
- merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
+ merge(defaultDataSubId, carrierConfigChangedEvent)
.onStart { emit(Unit) }
.mapLatest { Config.readConfig(context) }
.distinctUntilChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
index 22b4c9d81d25..736b14574da0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy
+import android.app.ActivityOptions
import android.app.Notification
import android.app.PendingIntent
import android.app.RemoteInput
@@ -275,7 +276,10 @@ class RemoteInputViewControllerImpl @Inject constructor(
entry.sbn.instanceId)
try {
- pendingIntent.send(view.context, 0, intent)
+ val options = ActivityOptions.makeBasic()
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
+ pendingIntent.send(view.context, 0, intent, null, null, null, options.toBundle())
} catch (e: PendingIntent.CanceledException) {
Log.i(TAG, "Unable to send remote input result", e)
uiEventLogger.logWithInstanceId(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
index 21d03386b9e2..cac5e3290a26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
@@ -22,6 +22,13 @@ import android.app.PendingIntent
import android.app.RemoteInput
import android.content.Context
import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.ImageDecoder
+import android.graphics.drawable.AdaptiveIconDrawable
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.Icon
import android.os.Build
import android.os.Bundle
import android.os.SystemClock
@@ -48,7 +55,13 @@ import com.android.systemui.statusbar.policy.InflatedSmartReplyState.SuppressedA
import com.android.systemui.statusbar.policy.SmartReplyView.SmartActions
import com.android.systemui.statusbar.policy.SmartReplyView.SmartButtonType
import com.android.systemui.statusbar.policy.SmartReplyView.SmartReplies
+import java.util.concurrent.FutureTask
+import java.util.concurrent.SynchronousQueue
+import java.util.concurrent.ThreadPoolExecutor
+import java.util.concurrent.TimeUnit
import javax.inject.Inject
+import kotlin.system.measureTimeMillis
+
/** Returns whether we should show the smart reply view and its smart suggestions. */
fun shouldShowSmartReplyView(
@@ -281,6 +294,51 @@ interface SmartActionInflater {
): Button
}
+private const val ICON_TASK_TIMEOUT_MS = 500L
+private val iconTaskThreadPool = ThreadPoolExecutor(0, 25, 1, TimeUnit.MINUTES, SynchronousQueue())
+
+private fun loadIconDrawableWithTimeout(
+ icon: Icon,
+ packageContext: Context,
+ targetSize: Int,
+): Drawable? {
+ if (icon.type != Icon.TYPE_URI && icon.type != Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ return icon.loadDrawable(packageContext)
+ }
+ val bitmapTask = FutureTask {
+ val bitmap: Bitmap?
+ val durationMillis = measureTimeMillis {
+ val source = ImageDecoder.createSource(packageContext.contentResolver, icon.uri)
+ bitmap = ImageDecoder.decodeBitmap(source) { decoder, _, _ ->
+ decoder.setTargetSize(targetSize, targetSize)
+ decoder.allocator = ImageDecoder.ALLOCATOR_DEFAULT
+ }
+ }
+ if (durationMillis > ICON_TASK_TIMEOUT_MS) {
+ Log.w(TAG, "Loading $icon took ${durationMillis / 1000f} sec")
+ }
+ checkNotNull(bitmap) { "ImageDecoder.decodeBitmap() returned null" }
+ }
+ val bitmap = runCatching {
+ iconTaskThreadPool.execute(bitmapTask)
+ bitmapTask.get(ICON_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS)
+ }.getOrElse { ex ->
+ Log.e(TAG, "Failed to load $icon: $ex")
+ bitmapTask.cancel(true)
+ return null
+ }
+ // TODO(b/288561520): rewrite Icon so that we don't need to duplicate this logic
+ val bitmapDrawable = BitmapDrawable(packageContext.resources, bitmap)
+ val result = if (icon.type == Icon.TYPE_URI_ADAPTIVE_BITMAP)
+ AdaptiveIconDrawable(null, bitmapDrawable) else bitmapDrawable
+ if (icon.hasTint()) {
+ result.mutate()
+ result.setTintList(icon.tintList)
+ result.setTintBlendMode(icon.tintBlendMode)
+ }
+ return result
+}
+
/* internal */ class SmartActionInflaterImpl @Inject constructor(
private val constants: SmartReplyConstants,
private val activityStarter: ActivityStarter,
@@ -304,12 +362,12 @@ interface SmartActionInflater {
// We received the Icon from the application - so use the Context of the application to
// reference icon resources.
- val iconDrawable = action.getIcon().loadDrawable(packageContext)
- .apply {
- val newIconSize: Int = context.resources.getDimensionPixelSize(
- R.dimen.smart_action_button_icon_size)
- setBounds(0, 0, newIconSize, newIconSize)
- }
+ val newIconSize = context.resources
+ .getDimensionPixelSize(R.dimen.smart_action_button_icon_size)
+ val iconDrawable =
+ loadIconDrawableWithTimeout(action.getIcon(), packageContext, newIconSize)
+ ?: GradientDrawable()
+ iconDrawable.setBounds(0, 0, newIconSize, newIconSize)
// Add the action icon to the Smart Action button.
setCompoundDrawablesRelative(iconDrawable, null, null, null)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index b135d0d8c9dc..1c3a8850df8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -28,6 +28,7 @@ import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerExecutor;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings.Global;
@@ -122,7 +123,12 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable {
userTracker.getUserId()) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
- updateZenModeConfig();
+ try {
+ Trace.beginSection("updateZenModeConfig");
+ updateZenModeConfig();
+ } finally {
+ Trace.endSection();
+ }
}
};
mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
index bcf3b0cbfc86..24987abd7a85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
@@ -240,8 +240,10 @@ public class StatusBarWindowController {
Insets.of(0, safeTouchRegionHeight, 0, 0));
}
lp.providedInsets = new InsetsFrameProvider[] {
- new InsetsFrameProvider(mInsetsSourceOwner, 0, statusBars()),
- new InsetsFrameProvider(mInsetsSourceOwner, 0, tappableElement()),
+ new InsetsFrameProvider(mInsetsSourceOwner, 0, statusBars())
+ .setInsetsSize(getInsets(height)),
+ new InsetsFrameProvider(mInsetsSourceOwner, 0, tappableElement())
+ .setInsetsSize(getInsets(height)),
gestureInsetsProvider
};
return lp;
@@ -306,12 +308,37 @@ public class StatusBarWindowController {
mLpChanged.height =
state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT : mBarHeight;
for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+ int height = SystemBarUtils.getStatusBarHeightForRotation(mContext, rot);
mLpChanged.paramsForRotation[rot].height =
- state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT :
- SystemBarUtils.getStatusBarHeightForRotation(mContext, rot);
+ state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT : height;
+ // The status bar height could change at runtime if one display has a cutout while
+ // another doesn't (like some foldables). It could also change when using debug cutouts.
+ // So, we need to re-fetch the height and re-apply it to the insets each time to avoid
+ // bugs like b/290300359.
+ InsetsFrameProvider[] providers = mLpChanged.paramsForRotation[rot].providedInsets;
+ if (providers != null) {
+ for (InsetsFrameProvider provider : providers) {
+ provider.setInsetsSize(getInsets(height));
+ }
+ }
}
}
+ /**
+ * Get the insets that should be applied to the status bar window given the current status bar
+ * height.
+ *
+ * The status bar window height can sometimes be full-screen (see {@link #applyHeight(State)}.
+ * However, the status bar *insets* should *not* be full-screen, because this would prevent apps
+ * from drawing any content and can cause animations to be cancelled (see b/283958440). Instead,
+ * the status bar insets should always be equal to the space occupied by the actual status bar
+ * content -- setting the insets correctly will prevent window manager from unnecessarily
+ * re-drawing this window and other windows. This method provides the correct insets.
+ */
+ private Insets getInsets(int height) {
+ return Insets.of(0, height, 0, 0);
+ }
+
private void apply(State state) {
if (!mIsAttached) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index 21f0ee2715e5..ba6325c78710 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -774,17 +774,16 @@ constructor(
}
// TODO(b/246631653): cache the bitmaps to avoid the background work to fetch them.
- val userIcon = withContext(backgroundDispatcher) {
- manager.getUserIcon(userId)
- ?.let { bitmap ->
+ val userIcon =
+ withContext(backgroundDispatcher) {
+ manager.getUserIcon(userId)?.let { bitmap ->
val iconSize =
- applicationContext
- .resources
- .getDimensionPixelSize(R.dimen.bouncer_user_switcher_icon_size)
+ applicationContext.resources.getDimensionPixelSize(
+ R.dimen.bouncer_user_switcher_icon_size
+ )
Icon.scaleDownIfNecessary(bitmap, iconSize, iconSize)
}
- }
-
+ }
if (userIcon != null) {
return BitmapDrawable(userIcon)
diff --git a/packages/SystemUI/src/com/android/systemui/util/wrapper/LottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/LottieViewWrapper.kt
new file mode 100644
index 000000000000..a804923bafdf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/LottieViewWrapper.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.util.wrapper
+
+import android.content.Context
+import android.util.AttributeSet
+import com.airbnb.lottie.LottieAnimationView
+import com.android.systemui.util.traceSection
+
+/** LottieAnimationView that traces each call to invalidate. */
+open class LottieViewWrapper : LottieAnimationView {
+ constructor(context: Context?) : super(context)
+ constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context?,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
+
+ override fun invalidate() {
+ traceSection<Any?>("${this::class} invalidate") {
+ super.invalidate()
+ null
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 96395b5179f1..ab0d78cdfd6e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -476,7 +476,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,
mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
- mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index fa32835c2695..677d3ff3df69 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -187,9 +187,7 @@ public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase {
@Test
public void testLockedOut_verifyPasswordAndUnlock_doesNotEnableViewInput() {
- mKeyguardAbsKeyInputViewController.handleAttemptLockout(
- SystemClock.elapsedRealtime() + 1000);
- mKeyguardAbsKeyInputViewController.verifyPasswordAndUnlock();
+ mKeyguardAbsKeyInputViewController.handleAttemptLockout(SystemClock.elapsedRealtime());
verify(mAbsKeyInputView).setPasswordEntryInputEnabled(false);
verify(mAbsKeyInputView).setPasswordEntryEnabled(false);
verify(mAbsKeyInputView, never()).setPasswordEntryInputEnabled(true);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index b21cc6dde815..9e561ed290f7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -408,4 +408,18 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
any(ClockRegistry.ClockChangeListener.class));
verify(mClockEventController, times).registerListeners(mView);
}
+
+ @Test
+ public void testSplitShadeEnabledSetToSmartspaceController() {
+ mController.setSplitShadeEnabled(true);
+ verify(mSmartspaceController, times(1)).setSplitShadeEnabled(true);
+ verify(mSmartspaceController, times(0)).setSplitShadeEnabled(false);
+ }
+
+ @Test
+ public void testSplitShadeDisabledSetToSmartspaceController() {
+ mController.setSplitShadeEnabled(false);
+ verify(mSmartspaceController, times(1)).setSplitShadeEnabled(false);
+ verify(mSmartspaceController, times(0)).setSplitShadeEnabled(true);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index 2f20f76ccc50..d9d0b4e661ff 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -72,6 +72,7 @@ import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.settings.GlobalSettings;
@@ -213,7 +214,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
mKeyguardStateController, mKeyguardSecurityViewFlipperController,
mConfigurationController, mFalsingCollector, mFalsingManager,
- mUserSwitcherController, mFeatureFlags, mGlobalSettings,
+ mUserSwitcherController, mock(DeviceProvisionedController.class), mFeatureFlags, mGlobalSettings,
mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate,
mTelephonyManager, mViewMediatorCallback, mAudioManager,
mock(KeyguardFaceAuthInteractor.class));
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index a2c632936047..512e5dc1a0d6 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -17,6 +17,7 @@
package com.android.keyguard;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -155,4 +156,18 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
verify(mControllerMock).setProperty(AnimatableProperty.SCALE_X, 20f, true);
verify(mControllerMock).setProperty(AnimatableProperty.SCALE_Y, 20f, true);
}
+
+ @Test
+ public void splitShadeEnabledPassedToClockSwitchController() {
+ mController.setSplitShadeEnabled(true);
+ verify(mKeyguardClockSwitchController, times(1)).setSplitShadeEnabled(true);
+ verify(mKeyguardClockSwitchController, times(0)).setSplitShadeEnabled(false);
+ }
+
+ @Test
+ public void splitShadeDisabledPassedToClockSwitchController() {
+ mController.setSplitShadeEnabled(false);
+ verify(mKeyguardClockSwitchController, times(1)).setSplitShadeEnabled(false);
+ verify(mKeyguardClockSwitchController, times(0)).setSplitShadeEnabled(true);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 1e675f8e4540..3cb4c0c51252 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -2935,6 +2935,16 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
TelephonyManager.SIM_STATE_UNKNOWN);
}
+ @Test
+ public void testOnSimStateChanged_HandleSimStateNotReady() {
+ KeyguardUpdateMonitorCallback keyguardUpdateMonitorCallback = spy(
+ KeyguardUpdateMonitorCallback.class);
+ mKeyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback);
+ mKeyguardUpdateMonitor.handleSimStateChange(-1, 0, TelephonyManager.SIM_STATE_NOT_READY);
+ verify(keyguardUpdateMonitorCallback).onSimStateChanged(-1, 0,
+ TelephonyManager.SIM_STATE_NOT_READY);
+ }
+
private void verifyFingerprintAuthenticateNeverCalled() {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any());
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index 84e58be2150f..403bd8c0a622 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -48,6 +48,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
@@ -95,6 +96,8 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
protected @Mock KeyguardTransitionRepository mTransitionRepository;
protected @Mock CommandQueue mCommandQueue;
protected FakeExecutor mDelayableExecutor = new FakeExecutor(new FakeSystemClock());
+ protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+
protected LockIconViewController mUnderTest;
@@ -167,7 +170,8 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
mFeatureFlags,
new FakeKeyguardBouncerRepository()
),
- mFeatureFlags
+ mFeatureFlags,
+ mPrimaryBouncerInteractor
);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
index b62875988b2e..ed6a891a6094 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
@@ -33,6 +33,7 @@ import android.hardware.biometrics.BiometricSourceType;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Pair;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -267,4 +268,75 @@ public class LockIconViewControllerTest extends LockIconViewControllerBaseTest {
// THEN the lock icon is shown
verify(mLockIconView).setContentDescription(LOCKED_LABEL);
}
+
+ @Test
+ public void lockIconAccessibility_notVisibleToUser() {
+ // GIVEN lock icon controller is initialized and view is attached
+ init(/* useMigrationFlag= */false);
+ captureKeyguardStateCallback();
+ captureKeyguardUpdateMonitorCallback();
+
+ // GIVEN user has unlocked with a biometric auth (ie: face auth)
+ // and biometric running state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
+ mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
+ BiometricSourceType.FACE);
+ reset(mLockIconView);
+ when(mLockIconView.isVisibleToUser()).thenReturn(false);
+
+ // WHEN the unlocked state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
+ mKeyguardStateCallback.onUnlockedChanged();
+
+ // THEN the lock icon is shown
+ verify(mLockIconView).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ }
+
+ @Test
+ public void lockIconAccessibility_bouncerAnimatingAway() {
+ // GIVEN lock icon controller is initialized and view is attached
+ init(/* useMigrationFlag= */false);
+ captureKeyguardStateCallback();
+ captureKeyguardUpdateMonitorCallback();
+
+ // GIVEN user has unlocked with a biometric auth (ie: face auth)
+ // and biometric running state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
+ mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
+ BiometricSourceType.FACE);
+ reset(mLockIconView);
+ when(mLockIconView.isVisibleToUser()).thenReturn(true);
+ when(mPrimaryBouncerInteractor.isAnimatingAway()).thenReturn(true);
+
+ // WHEN the unlocked state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
+ mKeyguardStateCallback.onUnlockedChanged();
+
+ // THEN the lock icon is shown
+ verify(mLockIconView).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ }
+
+ @Test
+ public void lockIconAccessibility_bouncerNotAnimatingAway_viewVisible() {
+ // GIVEN lock icon controller is initialized and view is attached
+ init(/* useMigrationFlag= */false);
+ captureKeyguardStateCallback();
+ captureKeyguardUpdateMonitorCallback();
+
+ // GIVEN user has unlocked with a biometric auth (ie: face auth)
+ // and biometric running state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(true);
+ mKeyguardUpdateMonitorCallback.onBiometricRunningStateChanged(false,
+ BiometricSourceType.FACE);
+ reset(mLockIconView);
+ when(mLockIconView.isVisibleToUser()).thenReturn(true);
+ when(mPrimaryBouncerInteractor.isAnimatingAway()).thenReturn(false);
+
+ // WHEN the unlocked state changes
+ when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(anyInt())).thenReturn(false);
+ mKeyguardStateCallback.onUnlockedChanged();
+
+ // THEN the lock icon is shown
+ verify(mLockIconView).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index 1990c8f644b4..18ace162696a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -86,6 +86,22 @@ class AuthenticationInteractorTest : SysuiTestCase() {
underTest.biometricUnlock()
runCurrent()
+ // Toggle isUnlocked, twice.
+ //
+ // This is done because the underTest.isUnlocked flow doesn't receive values from
+ // just changing the state above; the actual isUnlocked state needs to change to
+ // cause the logic under test to "pick up" the current state again.
+ //
+ // It is done twice to make sure that we don't actually change the isUnlocked
+ // state from what it originally was.
+ utils.authenticationRepository().setUnlocked(
+ !utils.authenticationRepository().isUnlocked.value
+ )
+ runCurrent()
+ utils.authenticationRepository().setUnlocked(
+ !utils.authenticationRepository().isUnlocked.value
+ )
+ runCurrent()
assertThat(isUnlocked).isTrue()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index b2ccd60216d7..78341915edb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -22,6 +22,7 @@ import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
import static com.android.internal.util.FunctionalUtils.ThrowingConsumer;
+import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -59,6 +60,7 @@ import android.os.PowerManager;
import android.os.RemoteException;
import android.os.VibrationAttributes;
import android.testing.TestableLooper.RunWithLooper;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
@@ -1184,8 +1186,53 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
+ public void fingerDown_falsingManagerInformed() throws RemoteException {
+ final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
+ givenAcceptFingerDownEvent();
+
+ // WHEN ACTION_DOWN is received
+ when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+ touchProcessorResult.first);
+ MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ mBiometricExecutor.runAllReady();
+ downEvent.recycle();
+
+ // THEN falsing manager is informed of the touch
+ verify(mFalsingManager).isFalseTouch(UDFPS_AUTHENTICATION);
+ }
+
+ @Test
public void onTouch_withNewTouchDetection_shouldCallNewFingerprintManagerPath()
throws RemoteException {
+ final Pair<TouchProcessorResult, TouchProcessorResult> processorResultDownAndUp =
+ givenAcceptFingerDownEvent();
+
+ // WHEN ACTION_DOWN is received
+ when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+ processorResultDownAndUp.first);
+ MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+ mBiometricExecutor.runAllReady();
+ downEvent.recycle();
+
+ // AND ACTION_UP is received
+ when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+ processorResultDownAndUp.second);
+ MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
+ mBiometricExecutor.runAllReady();
+ upEvent.recycle();
+
+ // THEN the new FingerprintManager path is invoked.
+ verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
+ anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
+ verify(mFingerprintManager).onPointerUp(anyLong(), anyInt(), anyInt(), anyFloat(),
+ anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
+ }
+
+ private Pair<TouchProcessorResult, TouchProcessorResult> givenAcceptFingerDownEvent()
+ throws RemoteException {
final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
0L);
final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
@@ -1211,27 +1258,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
- // WHEN ACTION_DOWN is received
- when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
- processorResultDown);
- MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
- mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
- mBiometricExecutor.runAllReady();
- downEvent.recycle();
-
- // AND ACTION_UP is received
- when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
- processorResultUp);
- MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
- mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
- mBiometricExecutor.runAllReady();
- upEvent.recycle();
-
- // THEN the new FingerprintManager path is invoked.
- verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
- anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
- verify(mFingerprintManager).onPointerUp(anyLong(), anyInt(), anyInt(), anyFloat(),
- anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
+ return new Pair<>(processorResultDown, processorResultUp);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt
new file mode 100644
index 000000000000..bfdb9231a9f8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.ui
+
+import android.content.ContentProvider
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class CanUseIconPredicateTest : SysuiTestCase() {
+
+ private companion object {
+ const val USER_ID_1 = 1
+ const val USER_ID_2 = 2
+ }
+
+ val underTest: CanUseIconPredicate = CanUseIconPredicate(USER_ID_1)
+
+ @Test
+ fun testReturnsFalseForDifferentUser() {
+ val user2Icon =
+ Icon.createWithContentUri(
+ ContentProvider.createContentUriForUser(
+ Uri.parse("content://test"),
+ UserHandle.of(USER_ID_2)
+ )
+ )
+
+ assertThat(underTest.invoke(user2Icon)).isFalse()
+ }
+
+ @Test
+ fun testReturnsTrueForCorrectUser() {
+ val user1Icon =
+ Icon.createWithContentUri(
+ ContentProvider.createContentUriForUser(
+ Uri.parse("content://test"),
+ UserHandle.of(USER_ID_1)
+ )
+ )
+
+ assertThat(underTest.invoke(user1Icon)).isTrue()
+ }
+
+ @Test
+ fun testReturnsTrueForUriWithoutUser() {
+ val uriIcon = Icon.createWithContentUri(Uri.parse("content://test"))
+
+ assertThat(underTest.invoke(uriIcon)).isTrue()
+ }
+
+ @Test
+ fun testReturnsTrueForNonUriIcon() {
+ val bitmapIcon = Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
+
+ assertThat(underTest.invoke(bitmapIcon)).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
index d3c465dab438..42f28c8c6043 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
@@ -66,7 +66,8 @@ class ControlViewHolderTest : SysuiTestCase() {
FakeExecutor(clock),
mock(ControlActionCoordinator::class.java),
mock(ControlsMetricsLogger::class.java),
- uid = 100
+ uid = 100,
+ 0,
)
val cws = ControlWithState(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
index 7840525b14aa..021facc51dba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
@@ -146,17 +146,8 @@ class PanelTaskViewControllerTest : SysuiTestCase() {
}
@Test
- fun testTaskViewReleasedOnDismiss() {
- underTest.dismiss()
- verify(taskView).release()
- }
-
- @Test
- fun testTaskViewReleasedOnBackOnRoot() {
- underTest.launchTaskView()
- verify(taskView).setListener(any(), capture(listenerCaptor))
-
- listenerCaptor.value.onBackPressedOnTaskRoot(0)
+ fun testTaskViewReleasedOnRelease() {
+ underTest.release()
verify(taskView).release()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index c280538f2d30..34ea91b94414 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -31,7 +31,10 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -186,6 +189,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
when(mStatusBarKeyguardViewManager.getViewRootImpl()).thenReturn(testViewRoot);
when(mDreamingToLockscreenTransitionViewModel.getDreamOverlayAlpha())
.thenReturn(mock(Flow.class));
+ when(mDreamingToLockscreenTransitionViewModel.getTransitionEnded())
+ .thenReturn(mock(Flow.class));
mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext,
mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
mConfigurationController, mViewMediator, mKeyguardBypassController,
@@ -238,7 +243,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
TestableLooper.get(this).processAllMessages();
mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
- mViewMediator.onWakeAndUnlocking();
+ mViewMediator.onWakeAndUnlocking(false);
mViewMediator.onStartedWakingUp(OFF_BECAUSE_OF_USER, false);
TestableLooper.get(this).processAllMessages();
@@ -591,8 +596,98 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
@Test
public void testWakeAndUnlocking() {
- mViewMediator.onWakeAndUnlocking();
+ mViewMediator.onWakeAndUnlocking(false);
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ }
+
+ @Test
+ public void testWakeAndUnlockingOverDream() {
+ // Send signal to wake
+ mViewMediator.onWakeAndUnlocking(true);
+
+ // Ensure not woken up yet
+ verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+
+ // Verify keyguard told of authentication
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ mViewMediator.mViewMediatorCallback.keyguardDonePending(true,
+ mUpdateMonitor.getCurrentUser());
+ mViewMediator.mViewMediatorCallback.readyForKeyguardDone();
+ final ArgumentCaptor<Runnable> animationRunnableCaptor =
+ ArgumentCaptor.forClass(Runnable.class);
+ verify(mStatusBarKeyguardViewManager).startPreHideAnimation(
+ animationRunnableCaptor.capture());
+
+ when(mStatusBarStateController.isDreaming()).thenReturn(true);
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
+ animationRunnableCaptor.getValue().run();
+
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+ mViewMediator.mViewMediatorCallback.keyguardGone();
+
+ // Verify woken up now.
+ verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
+ }
+
+ @Test
+ public void testWakeAndUnlockingOverDream_signalAuthenticateIfStillShowing() {
+ // Send signal to wake
+ mViewMediator.onWakeAndUnlocking(true);
+
+ // Ensure not woken up yet
+ verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+
+ // Verify keyguard told of authentication
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ clearInvocations(mStatusBarKeyguardViewManager);
+ mViewMediator.mViewMediatorCallback.keyguardDonePending(true,
+ mUpdateMonitor.getCurrentUser());
+ mViewMediator.mViewMediatorCallback.readyForKeyguardDone();
+ final ArgumentCaptor<Runnable> animationRunnableCaptor =
+ ArgumentCaptor.forClass(Runnable.class);
+ verify(mStatusBarKeyguardViewManager).startPreHideAnimation(
+ animationRunnableCaptor.capture());
+
+ when(mStatusBarStateController.isDreaming()).thenReturn(true);
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
+ animationRunnableCaptor.getValue().run();
+
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+ mViewMediator.mViewMediatorCallback.keyguardGone();
+
+
+ // Verify keyguard view controller informed of authentication again
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ }
+
+ @Test
+ public void testWakeAndUnlockingOverNonInteractiveDream_noWakeByKeyguardViewMediator() {
+ // Send signal to wake
+ mViewMediator.onWakeAndUnlocking(false);
+
+ // Ensure not woken up yet
+ verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+
+ // Verify keyguard told of authentication
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(anyBoolean());
+ mViewMediator.mViewMediatorCallback.keyguardDonePending(true,
+ mUpdateMonitor.getCurrentUser());
+ mViewMediator.mViewMediatorCallback.readyForKeyguardDone();
+ final ArgumentCaptor<Runnable> animationRunnableCaptor =
+ ArgumentCaptor.forClass(Runnable.class);
+ verify(mStatusBarKeyguardViewManager).startPreHideAnimation(
+ animationRunnableCaptor.capture());
+
+ when(mStatusBarStateController.isDreaming()).thenReturn(true);
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
+ animationRunnableCaptor.getValue().run();
+
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+ mViewMediator.mViewMediatorCallback.keyguardGone();
+
+ // Verify not woken up.
+ verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
index a3413466d62e..ab994b72a45b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt
@@ -22,8 +22,16 @@ import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING
+import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
+import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.util.mockito.mock
import com.google.common.collect.Range
@@ -60,7 +68,7 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
val job =
underTest.dreamOverlayTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0f, STARTED))
repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.3f))
repository.sendTransitionStep(step(0.5f))
@@ -82,7 +90,7 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
val job = underTest.dreamOverlayAlpha.onEach { values.add(it) }.launchIn(this)
// Should start running here...
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0f, STARTED))
repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.1f))
repository.sendTransitionStep(step(0.5f))
@@ -104,7 +112,7 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
val job = underTest.lockscreenAlpha.onEach { values.add(it) }.launchIn(this)
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0f, STARTED))
repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.1f))
repository.sendTransitionStep(step(0.2f))
@@ -126,7 +134,7 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
val job =
underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
- repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+ repository.sendTransitionStep(step(0f, STARTED))
repository.sendTransitionStep(step(0f))
repository.sendTransitionStep(step(0.3f))
repository.sendTransitionStep(step(0.5f))
@@ -138,13 +146,44 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() {
job.cancel()
}
- private fun step(
- value: Float,
- state: TransitionState = TransitionState.RUNNING
- ): TransitionStep {
+ @Test
+ fun transitionEnded() =
+ runTest(UnconfinedTestDispatcher()) {
+ val values = mutableListOf<TransitionStep>()
+
+ val job = underTest.transitionEnded.onEach { values.add(it) }.launchIn(this)
+
+ repository.sendTransitionStep(TransitionStep(DOZING, DREAMING, 0.0f, STARTED))
+ repository.sendTransitionStep(TransitionStep(DOZING, DREAMING, 1.0f, FINISHED))
+
+ repository.sendTransitionStep(TransitionStep(DREAMING, LOCKSCREEN, 0.0f, STARTED))
+ repository.sendTransitionStep(TransitionStep(DREAMING, LOCKSCREEN, 0.1f, RUNNING))
+ repository.sendTransitionStep(TransitionStep(DREAMING, LOCKSCREEN, 1.0f, FINISHED))
+
+ repository.sendTransitionStep(TransitionStep(LOCKSCREEN, DREAMING, 0.0f, STARTED))
+ repository.sendTransitionStep(TransitionStep(LOCKSCREEN, DREAMING, 0.5f, RUNNING))
+ repository.sendTransitionStep(TransitionStep(LOCKSCREEN, DREAMING, 1.0f, FINISHED))
+
+ repository.sendTransitionStep(TransitionStep(DREAMING, GONE, 0.0f, STARTED))
+ repository.sendTransitionStep(TransitionStep(DREAMING, GONE, 0.5f, RUNNING))
+ repository.sendTransitionStep(TransitionStep(DREAMING, GONE, 1.0f, CANCELED))
+
+ repository.sendTransitionStep(TransitionStep(DREAMING, AOD, 0.0f, STARTED))
+ repository.sendTransitionStep(TransitionStep(DREAMING, AOD, 1.0f, FINISHED))
+
+ assertThat(values.size).isEqualTo(3)
+ values.forEach {
+ assertThat(it.transitionState == FINISHED || it.transitionState == CANCELED)
+ .isTrue()
+ }
+
+ job.cancel()
+ }
+
+ private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
return TransitionStep(
- from = KeyguardState.DREAMING,
- to = KeyguardState.LOCKSCREEN,
+ from = DREAMING,
+ to = LOCKSCREEN,
value = value,
transitionState = state,
ownerName = "DreamingToLockscreenTransitionViewModelTest"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
index 9ab728949e40..530b86eb4978 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
@@ -98,6 +98,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
@Captor lateinit var callbackCaptor: ArgumentCaptor<ResumeMediaBrowser.Callback>
@Captor lateinit var actionCaptor: ArgumentCaptor<Runnable>
@Captor lateinit var componentCaptor: ArgumentCaptor<String>
+ @Captor lateinit var userIdCaptor: ArgumentCaptor<Int>
+ @Captor lateinit var userCallbackCaptor: ArgumentCaptor<UserTracker.Callback>
private lateinit var executor: FakeExecutor
private lateinit var data: MediaData
@@ -124,7 +126,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
)
Settings.Secure.putInt(context.contentResolver, Settings.Secure.MEDIA_CONTROLS_RESUME, 1)
- whenever(resumeBrowserFactory.create(capture(callbackCaptor), any()))
+ whenever(resumeBrowserFactory.create(capture(callbackCaptor), any(), capture(userIdCaptor)))
.thenReturn(resumeBrowser)
// resume components are stored in sharedpreferences
@@ -334,6 +336,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
@Test
fun testOnUserUnlock_loadsTracks() {
// Set up mock service to successfully find valid media
+ setUpMbsWithValidResolveInfo()
val description = MediaDescription.Builder().setTitle(TITLE).build()
val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
whenever(resumeBrowser.token).thenReturn(token)
@@ -417,6 +420,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
@Test
fun testLoadComponents_recentlyPlayed_adds() {
// Set up browser to return successfully
+ setUpMbsWithValidResolveInfo()
val description = MediaDescription.Builder().setTitle(TITLE).build()
val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
whenever(resumeBrowser.token).thenReturn(token)
@@ -600,7 +604,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
// Set up our factory to return a new browser so we can verify we disconnected the old one
val newResumeBrowser = mock(ResumeMediaBrowser::class.java)
- whenever(resumeBrowserFactory.create(capture(callbackCaptor), any()))
+ whenever(resumeBrowserFactory.create(capture(callbackCaptor), any(), anyInt()))
.thenReturn(newResumeBrowser)
// When the resume action is run
@@ -610,6 +614,66 @@ class MediaResumeListenerTest : SysuiTestCase() {
verify(resumeBrowser).disconnect()
}
+ @Test
+ fun testUserUnlocked_userChangeWhileQuerying() {
+ val firstUserId = 1
+ val secondUserId = 2
+ val description = MediaDescription.Builder().setTitle(TITLE).build()
+ val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
+
+ setUpMbsWithValidResolveInfo()
+ whenever(resumeBrowser.token).thenReturn(token)
+ whenever(resumeBrowser.appIntent).thenReturn(pendingIntent)
+
+ val unlockIntent =
+ Intent(Intent.ACTION_USER_UNLOCKED).apply {
+ putExtra(Intent.EXTRA_USER_HANDLE, firstUserId)
+ }
+ verify(userTracker).addCallback(capture(userCallbackCaptor), any())
+
+ // When the first user unlocks and we query their recent media
+ userCallbackCaptor.value.onUserChanged(firstUserId, context)
+ resumeListener.userUnlockReceiver.onReceive(context, unlockIntent)
+ whenever(resumeBrowser.userId).thenReturn(userIdCaptor.value)
+ verify(resumeBrowser, times(3)).findRecentMedia()
+
+ // And the user changes before the MBS response is received
+ userCallbackCaptor.value.onUserChanged(secondUserId, context)
+ callbackCaptor.value.addTrack(description, component, resumeBrowser)
+
+ // Then the loaded media is correctly associated with the first user
+ verify(mediaDataManager)
+ .addResumptionControls(
+ eq(firstUserId),
+ eq(description),
+ any(),
+ eq(token),
+ eq(PACKAGE_NAME),
+ eq(pendingIntent),
+ eq(PACKAGE_NAME)
+ )
+ }
+
+ @Test
+ fun testUserUnlocked_noComponent_doesNotQuery() {
+ // Set up a valid MBS, but user does not have the service available
+ setUpMbsWithValidResolveInfo()
+ val pm = mock(PackageManager::class.java)
+ whenever(mockContext.packageManager).thenReturn(pm)
+ whenever(pm.resolveServiceAsUser(any(), anyInt(), anyInt())).thenReturn(null)
+
+ val unlockIntent =
+ Intent(Intent.ACTION_USER_UNLOCKED).apply {
+ putExtra(Intent.EXTRA_USER_HANDLE, context.userId)
+ }
+
+ // When the user is unlocked, but does not have the component installed
+ resumeListener.userUnlockReceiver.onReceive(context, unlockIntent)
+
+ // Then we never attempt to connect to it
+ verify(resumeBrowser, never()).findRecentMedia()
+ }
+
/** Sets up mocks to successfully find a MBS that returns valid media. */
private fun setUpMbsWithValidResolveInfo() {
val pm = mock(PackageManager::class.java)
@@ -620,6 +684,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
resolveInfo.serviceInfo = serviceInfo
resolveInfo.serviceInfo.name = CLASS_NAME
val resumeInfo = listOf(resolveInfo)
- whenever(pm.queryIntentServices(any(), anyInt())).thenReturn(resumeInfo)
+ whenever(pm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn(resumeInfo)
+ whenever(pm.resolveServiceAsUser(any(), anyInt(), anyInt())).thenReturn(resolveInfo)
+ whenever(pm.getApplicationLabel(any())).thenReturn(PACKAGE_NAME)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserTest.kt
index a04cfd46588b..b45e66bfc31b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserTest.kt
@@ -93,7 +93,8 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
component,
browserFactory,
logger,
- mediaController
+ mediaController,
+ context.userId,
)
}
@@ -381,8 +382,9 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
componentName: ComponentName,
browserFactory: MediaBrowserFactory,
logger: ResumeMediaBrowserLogger,
- private val fakeController: MediaController
- ) : ResumeMediaBrowser(context, callback, componentName, browserFactory, logger) {
+ private val fakeController: MediaController,
+ userId: Int,
+ ) : ResumeMediaBrowser(context, callback, componentName, browserFactory, logger, userId) {
override fun createMediaController(token: MediaSession.Token): MediaController {
return fakeController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
index b40ebc9bb156..91b0245be8d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
@@ -193,6 +193,17 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
}
@Test
+ fun dozeWakeUpAnimationWaiting_inSplitShade_mediaIsHidden() {
+ val splitShadeContainer = FrameLayout(context)
+ keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
+ keyguardMediaController.useSplitShade = true
+
+ keyguardMediaController.isDozeWakeUpAnimationWaiting = true
+
+ assertThat(splitShadeContainer.visibility).isEqualTo(GONE)
+ }
+
+ @Test
fun dozing_inSingleShade_mediaIsVisible() {
val splitShadeContainer = FrameLayout(context)
keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
@@ -203,6 +214,17 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE)
}
+ @Test
+ fun dozeWakeUpAnimationWaiting_inSingleShade_mediaIsVisible() {
+ val splitShadeContainer = FrameLayout(context)
+ keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
+ keyguardMediaController.useSplitShade = false
+
+ keyguardMediaController.isDozeWakeUpAnimationWaiting = true
+
+ assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE)
+ }
+
private fun setDozing() {
whenever(statusBarStateController.isDozing).thenReturn(true)
statusBarStateListener.onDozingChanged(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 7df54d44e69e..e4f89a226a34 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -291,13 +291,13 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTitleText.getText().toString()).isEqualTo(TEST_DEVICE_NAME_1);
- assertThat(mViewHolder.mStatusIcon.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mStatusIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewHolder.mEndTouchArea.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mEndTouchArea.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
@@ -525,16 +525,16 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewHolder.mStatusIcon.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mStatusIcon.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mSubTitleText.getText().toString()).isEqualTo(TEST_CUSTOM_SUBTEXT);
assertThat(mViewHolder.mTwoLineTitleText.getText().toString()).isEqualTo(
TEST_DEVICE_NAME_1);
- assertThat(mViewHolder.mContainerLayout.hasOnClickListeners()).isTrue();
+ assertThat(mViewHolder.mContainerLayout.hasOnClickListeners()).isFalse();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 810ab344e7d8..587c49d77481 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -297,11 +297,20 @@ public class QSTileHostTest extends SysuiTestCase {
StringWriter w = new StringWriter();
PrintWriter pw = new PrintWriter(w);
mQSTileHost.dump(pw, new String[]{});
- String output = "QSTileHost:\n"
- + TestTile1.class.getSimpleName() + ":\n"
- + " " + MOCK_STATE_STRING + "\n"
- + TestTile2.class.getSimpleName() + ":\n"
- + " " + MOCK_STATE_STRING + "\n";
+
+ String output = "QSTileHost:" + "\n"
+ + "tile specs: [spec1, spec2]" + "\n"
+ + "current user: 0" + "\n"
+ + "is dirty: false" + "\n"
+ + "tiles:" + "\n"
+ + "TestTile1:" + "\n"
+ + " MockState" + "\n"
+ + "TestTile2:" + "\n"
+ + " MockState" + "\n";
+
+ System.out.println(output);
+ System.out.println(w.getBuffer().toString());
+
assertEquals(output, w.getBuffer().toString());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
index d7682b20a98d..421c35595026 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
@@ -26,6 +26,7 @@ import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,6 +52,7 @@ class RetailModeSettingsRepositoryTest : SysuiTestCase() {
fun retailMode_defaultFalse() =
testScope.runTest {
val value by collectLastValue(underTest.retailMode)
+ runCurrent()
assertThat(value).isFalse()
assertThat(underTest.inRetailMode).isFalse()
@@ -60,6 +62,7 @@ class RetailModeSettingsRepositoryTest : SysuiTestCase() {
fun retailMode_false() =
testScope.runTest {
val value by collectLastValue(underTest.retailMode)
+ runCurrent()
globalSettings.putInt(SETTING, 0)
@@ -71,6 +74,7 @@ class RetailModeSettingsRepositoryTest : SysuiTestCase() {
fun retailMode_true() =
testScope.runTest {
val value by collectLastValue(underTest.retailMode)
+ runCurrent()
globalSettings.putInt(SETTING, 1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 8f2ee91d6a6a..987e09c8776c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -510,6 +510,17 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo
}
@Test
+ public void keyguardStatusView_willPlayDelayedDoze_notifiesKeyguardMediaController() {
+ when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2);
+ mStatusBarStateController.setState(KEYGUARD);
+ enableSplitShade(/* enabled= */ true);
+
+ mNotificationPanelViewController.setWillPlayDelayedDozeAmountAnimation(true);
+
+ verify(mKeyguardMediaController).setDozeWakeUpAnimationWaiting(true);
+ }
+
+ @Test
public void keyguardStatusView_willPlayDelayedDoze_isCentered_thenStillCenteredIfNoNotifs() {
when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(0);
mStatusBarStateController.setState(KEYGUARD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 04c93cb71e42..0c6926849c4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -224,6 +224,25 @@ class ClockRegistryTest : SysuiTestCase() {
}
@Test
+ fun activeClockId_changeAfterPluginConnected() {
+ val plugin1 = FakeClockPlugin()
+ .addClock("clock_1", "clock 1")
+ .addClock("clock_2", "clock 2")
+
+ val plugin2 = FakeClockPlugin()
+ .addClock("clock_3", "clock 3", { mockClock })
+ .addClock("clock_4", "clock 4")
+
+ registry.applySettings(ClockSettings("clock_3", null))
+
+ pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle)
+ assertEquals(DEFAULT_CLOCK_ID, registry.activeClockId)
+
+ pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle)
+ assertEquals("clock_3", registry.activeClockId)
+ }
+
+ @Test
fun createDefaultClock_pluginDisconnected() {
val plugin1 = FakeClockPlugin()
.addClock("clock_1", "clock 1")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 540bda6ea9dc..9037df821ca8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -1675,11 +1675,21 @@ public class NotifCollectionTest extends SysuiTestCase {
}
@Test
+ public void testCanDismissOtherNotificationChildren() {
+ // GIVEN an ongoing notification
+ final NotificationEntry container = new NotificationEntryBuilder()
+ .setGroup(mContext, "group")
+ .build();
+
+ // THEN its children are dismissible
+ assertTrue(mCollection.shouldAutoDismissChildren(
+ container, container.getSbn().getGroupKey()));
+ }
+
+ @Test
public void testCannotDismissOngoingNotificationChildren() {
// GIVEN an ongoing notification
final NotificationEntry container = new NotificationEntryBuilder()
- .setPkg(TEST_PACKAGE)
- .setId(47)
.setGroup(mContext, "group")
.setFlag(mContext, FLAG_ONGOING_EVENT, true)
.build();
@@ -1693,6 +1703,7 @@ public class NotifCollectionTest extends SysuiTestCase {
public void testCannotDismissNoClearNotifications() {
// GIVEN an no-clear notification
final NotificationEntry container = new NotificationEntryBuilder()
+ .setGroup(mContext, "group")
.setFlag(mContext, FLAG_NO_CLEAR, true)
.build();
@@ -1702,11 +1713,25 @@ public class NotifCollectionTest extends SysuiTestCase {
}
@Test
+ public void testCannotDismissPriorityConversations() {
+ // GIVEN an no-clear notification
+ NotificationChannel channel =
+ new NotificationChannel("foo", "Foo", NotificationManager.IMPORTANCE_HIGH);
+ channel.setImportantConversation(true);
+ final NotificationEntry container = new NotificationEntryBuilder()
+ .setGroup(mContext, "group")
+ .setChannel(channel)
+ .build();
+
+ // THEN its children are not dismissible
+ assertFalse(mCollection.shouldAutoDismissChildren(
+ container, container.getSbn().getGroupKey()));
+ }
+
+ @Test
public void testCanDismissFgsNotificationChildren() {
// GIVEN an FGS but not ongoing notification
final NotificationEntry container = new NotificationEntryBuilder()
- .setPkg(TEST_PACKAGE)
- .setId(47)
.setGroup(mContext, "group")
.setFlag(mContext, FLAG_FOREGROUND_SERVICE, true)
.build();
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 02666e40b98d..cd0550e13540 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.notification.collection.render.SectionHead
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController.NotificationPanelEvent;
+import com.android.systemui.statusbar.notification.stack.NotificationSwipeHelper.NotificationCallback;
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
@@ -339,6 +340,36 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
}
@Test
+ public void callSwipeCallbacksDuringClearAll() {
+ initController(/* viewIsAttached= */ true);
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ NotificationCallback notificationCallback = mController.mNotificationCallback;
+
+ when(mNotificationStackScrollLayout.getClearAllInProgress()).thenReturn(true);
+
+ notificationCallback.onBeginDrag(row);
+ verify(mNotificationStackScrollLayout).onSwipeBegin(row);
+
+ notificationCallback.handleChildViewDismissed(row);
+ verify(mNotificationStackScrollLayout).onSwipeEnd();
+ }
+
+ @Test
+ public void callSwipeCallbacksDuringClearNotification() {
+ initController(/* viewIsAttached= */ true);
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ NotificationCallback notificationCallback = mController.mNotificationCallback;
+
+ when(mNotificationStackScrollLayout.getClearAllInProgress()).thenReturn(false);
+
+ notificationCallback.onBeginDrag(row);
+ verify(mNotificationStackScrollLayout).onSwipeBegin(row);
+
+ notificationCallback.handleChildViewDismissed(row);
+ verify(mNotificationStackScrollLayout).onSwipeEnd();
+ }
+
+ @Test
public void testOnMenuClickedLogging() {
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
when(row.getEntry().getSbn().getLogMaker()).thenReturn(new LogMaker(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 89f8bdbfe05b..7acf398955fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -186,7 +186,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
- verify(mKeyguardViewMediator).onWakeAndUnlocking();
+ verify(mKeyguardViewMediator).onWakeAndUnlocking(false);
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING);
}
@@ -204,7 +204,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */);
- verify(mKeyguardViewMediator).onWakeAndUnlocking();
+ verify(mKeyguardViewMediator).onWakeAndUnlocking(false);
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(MODE_WAKE_AND_UNLOCK);
}
@@ -542,4 +542,21 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
when(mKeyguardStateController.isShowing()).thenReturn(true);
}
+
+ private void givenDreamingLocked() {
+ when(mUpdateMonitor.isDreaming()).thenReturn(true);
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+ }
+ @Test
+ public void onSideFingerprintSuccess_dreaming_unlockNoWake() {
+ when(mAuthController.isSfpsEnrolled(anyInt())).thenReturn(true);
+ when(mWakefulnessLifecycle.getLastWakeReason())
+ .thenReturn(PowerManager.WAKE_REASON_POWER_BUTTON);
+ givenDreamingLocked();
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ mBiometricUnlockController.startWakeAndUnlock(BiometricSourceType.FINGERPRINT, true);
+ verify(mKeyguardViewMediator).onWakeAndUnlocking(true);
+ // Ensure that the power hasn't been told to wake up yet.
+ verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
index c0243dc537b5..b2dc0dc984c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
@@ -105,6 +105,30 @@ class LetterboxAppearanceCalculatorTest : SysuiTestCase() {
expect.that(letterboxAppearance.appearanceRegions).isEqualTo(TEST_APPEARANCE_REGIONS)
}
+ /** Regression test for b/287508741 */
+ @Test
+ fun getLetterboxAppearance_withOverlap_doesNotMutateOriginalBounds() {
+ val statusBarStartSideBounds = Rect(left = 0, top = 0, right = 100, bottom = 100)
+ val statusBarEndSideBounds = Rect(left = 200, top = 0, right = 300, bottom = 100)
+ val letterBoxInnerBounds = Rect(left = 150, top = 50, right = 250, bottom = 150)
+ val statusBarStartSideBoundsCopy = Rect(statusBarStartSideBounds)
+ val statusBarEndSideBoundsCopy = Rect(statusBarEndSideBounds)
+ val letterBoxInnerBoundsCopy = Rect(letterBoxInnerBounds)
+ whenever(statusBarBoundsProvider.visibleStartSideBounds)
+ .thenReturn(statusBarStartSideBounds)
+ whenever(statusBarBoundsProvider.visibleEndSideBounds).thenReturn(statusBarEndSideBounds)
+
+ calculator.getLetterboxAppearance(
+ TEST_APPEARANCE,
+ TEST_APPEARANCE_REGIONS,
+ arrayOf(letterboxWithInnerBounds(letterBoxInnerBounds))
+ )
+
+ expect.that(statusBarStartSideBounds).isEqualTo(statusBarStartSideBoundsCopy)
+ expect.that(statusBarEndSideBounds).isEqualTo(statusBarEndSideBoundsCopy)
+ expect.that(letterBoxInnerBounds).isEqualTo(letterBoxInnerBoundsCopy)
+ }
+
@Test
fun getLetterboxAppearance_noOverlap_BackgroundMultiColor_returnsAppearanceWithScrim() {
whenever(letterboxBackgroundProvider.isLetterboxBackgroundMultiColored).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index a9ed17531926..7fc02280354f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -44,6 +44,9 @@ import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
import android.animation.Animator;
import android.app.AlarmManager;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
@@ -121,6 +124,7 @@ public class ScrimControllerTest extends SysuiTestCase {
private int mScrimVisibility;
private boolean mAlwaysOnEnabled;
private TestableLooper mLooper;
+ private Context mContext;
@Mock private AlarmManager mAlarmManager;
@Mock private DozeParameters mDozeParameters;
@Mock private LightBarController mLightBarController;
@@ -134,6 +138,7 @@ public class ScrimControllerTest extends SysuiTestCase {
@Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Mock private CoroutineDispatcher mMainDispatcher;
+ @Mock private TypedArray mMockTypedArray;
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
// event-dispatch-on-registration pattern caused some of these unit tests to fail.)
@@ -182,10 +187,11 @@ public class ScrimControllerTest extends SysuiTestCase {
mNumEnds = 0;
mNumCancels = 0;
}
- };
+ }
private AnimatorListener mAnimatorListener = new AnimatorListener();
+ private int mSurfaceColor = 0x112233;
private void finishAnimationsImmediately() {
// Execute code that will trigger animations.
@@ -214,10 +220,17 @@ public class ScrimControllerTest extends SysuiTestCase {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ mContext = spy(getContext());
+ when(mContext.obtainStyledAttributes(
+ new int[]{com.android.internal.R.attr.materialColorSurface}))
+ .thenReturn(mMockTypedArray);
+
+ when(mMockTypedArray.getColorStateList(anyInt()))
+ .thenAnswer((invocation) -> ColorStateList.valueOf(mSurfaceColor));
- mScrimBehind = spy(new ScrimView(getContext()));
- mScrimInFront = new ScrimView(getContext());
- mNotificationsScrim = new ScrimView(getContext());
+ mScrimBehind = spy(new ScrimView(mContext));
+ mScrimInFront = new ScrimView(mContext);
+ mNotificationsScrim = new ScrimView(mContext);
mAlwaysOnEnabled = true;
mLooper = TestableLooper.get(this);
DejankUtils.setImmediate(true);
@@ -577,7 +590,7 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimController.transitionTo(BOUNCER);
finishAnimationsImmediately();
// Front scrim should be transparent
- // Back scrim should be visible without tint
+ // Back scrim should be visible and tinted to the surface color
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, TRANSPARENT,
@@ -585,9 +598,31 @@ public class ScrimControllerTest extends SysuiTestCase {
assertScrimTinted(Map.of(
mScrimInFront, false,
- mScrimBehind, false,
+ mScrimBehind, true,
mNotificationsScrim, false
));
+
+ assertScrimTint(mScrimBehind, mSurfaceColor);
+ }
+
+ @Test
+ public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() {
+ assertEquals(BOUNCER.getBehindTint(), 0x112233);
+ mSurfaceColor = 0x223344;
+ mConfigurationController.notifyThemeChanged();
+ assertEquals(BOUNCER.getBehindTint(), 0x223344);
+ }
+
+ @Test
+ public void onThemeChangeWhileClipQsScrim_bouncerBehindTint_remainsBlack() {
+ mScrimController.setClipsQsScrim(true);
+ mScrimController.transitionTo(BOUNCER);
+ finishAnimationsImmediately();
+
+ assertEquals(BOUNCER.getBehindTint(), Color.BLACK);
+ mSurfaceColor = 0x223344;
+ mConfigurationController.notifyThemeChanged();
+ assertEquals(BOUNCER.getBehindTint(), Color.BLACK);
}
@Test
@@ -619,16 +654,17 @@ public class ScrimControllerTest extends SysuiTestCase {
finishAnimationsImmediately();
// Front scrim should be transparent
- // Back scrim should be visible without tint
+ // Back scrim should be visible and has a tint of surfaceColor
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, TRANSPARENT,
mScrimBehind, OPAQUE));
assertScrimTinted(Map.of(
mScrimInFront, false,
- mScrimBehind, false,
+ mScrimBehind, true,
mNotificationsScrim, false
));
+ assertScrimTint(mScrimBehind, mSurfaceColor);
}
@Test
@@ -1809,6 +1845,13 @@ public class ScrimControllerTest extends SysuiTestCase {
assertEquals(message, hasTint, scrim.getTint() != Color.TRANSPARENT);
}
+ private void assertScrimTint(ScrimView scrim, int expectedTint) {
+ String message = "Tint test failed with expected scrim tint: "
+ + Integer.toHexString(expectedTint) + " and actual tint: "
+ + Integer.toHexString(scrim.getTint()) + " for scrim: " + getScrimName(scrim);
+ assertEquals(message, expectedTint, scrim.getTint(), 0.1);
+ }
+
private String getScrimName(ScrimView scrim) {
if (scrim == mScrimInFront) {
return "front";
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 3eea93c6ec2c..131cc07178f4 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
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.service.trust.TrustAgentService;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
@@ -57,6 +58,8 @@ import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardMessageAreaController;
import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.TrustGrantFlags;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
@@ -84,7 +87,6 @@ import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.google.common.truth.Truth;
@@ -153,7 +155,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Captor
private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor;
@Captor
- private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallback;
+ private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
@Before
@@ -925,18 +927,24 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
}
@Test
- public void onDeviceUnlocked_hideAlternateBouncerAndClearMessageArea() {
+ public void onTrustChanged_hideAlternateBouncerAndClearMessageArea() {
+ // GIVEN keyguard update monitor callback is registered
+ verify(mKeyguardUpdateMonitor).registerCallback(mKeyguardUpdateMonitorCallback.capture());
+
reset(mKeyguardUpdateMonitor);
reset(mKeyguardMessageAreaController);
- // GIVEN keyguard state controller callback is registered
- verify(mKeyguardStateController).addCallback(mKeyguardStateControllerCallback.capture());
-
// GIVEN alternate bouncer state = not visible
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
- // WHEN the device is unlocked
- mKeyguardStateControllerCallback.getValue().onUnlockedChanged();
+ // WHEN the device is trusted by active unlock
+ mKeyguardUpdateMonitorCallback.getValue().onTrustGrantedForCurrentUser(
+ true,
+ true,
+ new TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD
+ | TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE),
+ null
+ );
// THEN the false visibility state is propagated to the keyguardUpdateMonitor
verify(mKeyguardUpdateMonitor).setAlternateBouncerShowing(eq(false));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index fd156d86c19e..9aea70f9cdb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -1074,13 +1074,10 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {
assertThat(configFromContext.showAtLeast3G).isTrue()
// WHEN the change event is fired
- fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
- receiver.onReceive(
- context,
- Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
- .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
- )
- }
+ val intent =
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
// THEN the config is updated
assertTrue(latest!!.areEqual(configFromContext))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 47a86b1fca5c..17ada0d7fa1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -167,6 +167,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Optional;
+@Ignore("b/292153259")
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
index af940e4fa687..f19e19113b30 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
@@ -18,6 +18,7 @@ package com.android.systemui.broadcast
import android.content.BroadcastReceiver
import android.content.Context
+import android.content.Intent
import android.content.IntentFilter
import android.os.Handler
import android.os.Looper
@@ -31,6 +32,14 @@ import java.lang.IllegalStateException
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executor
+/**
+ * A fake instance of [BroadcastDispatcher] for tests.
+ *
+ * Important: The *real* broadcast dispatcher will only send intents to receivers if the intent
+ * matches the [IntentFilter] that the [BroadcastReceiver] was registered with. This fake class does
+ * *not* do that matching by default. Use [sendIntentToMatchingReceiversOnly] to get the same
+ * matching behavior as the real broadcast dispatcher.
+ */
class FakeBroadcastDispatcher(
context: SysuiTestableContext,
mainExecutor: Executor,
@@ -52,7 +61,10 @@ class FakeBroadcastDispatcher(
PendingRemovalStore(logger)
) {
- val registeredReceivers: MutableSet<BroadcastReceiver> = ConcurrentHashMap.newKeySet()
+ private val receivers: MutableSet<InternalReceiver> = ConcurrentHashMap.newKeySet()
+
+ val registeredReceivers: Set<BroadcastReceiver>
+ get() = receivers.map { it.receiver }.toSet()
override fun registerReceiverWithHandler(
receiver: BroadcastReceiver,
@@ -62,7 +74,7 @@ class FakeBroadcastDispatcher(
@Context.RegisterReceiverFlags flags: Int,
permission: String?
) {
- registeredReceivers.add(receiver)
+ receivers.add(InternalReceiver(receiver, filter))
}
override fun registerReceiver(
@@ -73,15 +85,34 @@ class FakeBroadcastDispatcher(
@Context.RegisterReceiverFlags flags: Int,
permission: String?
) {
- registeredReceivers.add(receiver)
+ receivers.add(InternalReceiver(receiver, filter))
}
override fun unregisterReceiver(receiver: BroadcastReceiver) {
- registeredReceivers.remove(receiver)
+ receivers.removeIf { it.receiver == receiver }
}
override fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
- registeredReceivers.remove(receiver)
+ receivers.removeIf { it.receiver == receiver }
+ }
+
+ /**
+ * Sends the given [intent] to *only* the receivers that were registered with an [IntentFilter]
+ * that matches the intent.
+ */
+ fun sendIntentToMatchingReceiversOnly(context: Context, intent: Intent) {
+ receivers.forEach {
+ if (
+ it.filter.match(
+ context.contentResolver,
+ intent,
+ /* resolve= */ false,
+ /* logTag= */ "FakeBroadcastDispatcher",
+ ) > 0
+ ) {
+ it.receiver.onReceive(context, intent)
+ }
+ }
}
fun cleanUpReceivers(testName: String) {
@@ -91,6 +122,11 @@ class FakeBroadcastDispatcher(
throw IllegalStateException("Receiver not unregistered from dispatcher: $it")
}
}
- registeredReceivers.clear()
+ receivers.clear()
}
+
+ private data class InternalReceiver(
+ val receiver: BroadcastReceiver,
+ val filter: IntentFilter,
+ )
}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 8060d5a96aa6..9b9593b2b99a 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -637,7 +637,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
MotionEvent event, MotionEvent rawEvent, int policyFlags) {
switch (event.getActionMasked()) {
case ACTION_DOWN:
- handleActionDownStateTouchExploring(event, rawEvent, policyFlags);
+ // We should have already received ACTION_DOWN. Ignore.
break;
case ACTION_POINTER_DOWN:
handleActionPointerDown(event, rawEvent, policyFlags);
@@ -843,15 +843,6 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
}
- private void handleActionDownStateTouchExploring(
- MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- // This is an interrupted and continued touch exploration. Maintain the consistency of the
- // event stream.
- mSendTouchExplorationEndDelayed.cancel();
- mSendTouchInteractionEndDelayed.cancel();
- sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
- }
-
/**
* Handles move events while touch exploring. this is also where we drag or delegate based on
* the number of fingers moving on the screen.
@@ -1109,15 +1100,12 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
/**
- * Sends the enter events if needed. Such events are hover enter and touch explore gesture
- * start.
+ * Sends the enter events if needed. Such events are hover enter and touch explore
+ * gesture start.
*
* @param policyFlags The policy flags associated with the event.
*/
private void sendTouchExplorationGestureStartAndHoverEnterIfNeeded(int policyFlags) {
- if (!mState.isTouchExploring()) {
- mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
- }
MotionEvent event = mState.getLastInjectedHoverEvent();
if (event != null && event.getActionMasked() == ACTION_HOVER_EXIT) {
final int pointerIdBits = event.getPointerIdBits();
@@ -1130,6 +1118,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
}
+
/**
* Determines whether a two pointer gesture is a dragging one.
*
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 82af38200166..7557071d0d4b 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -20,6 +20,8 @@ import static com.android.server.autofill.Helper.sDebug;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.app.assist.AssistStructure.WindowNode;
@@ -40,6 +42,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
+import android.widget.RemoteViews;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
@@ -50,6 +53,8 @@ import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+
public final class Helper {
@@ -83,6 +88,44 @@ public final class Helper {
throw new UnsupportedOperationException("contains static members only");
}
+ private static boolean checkRemoteViewUriPermissions(
+ @UserIdInt int userId, @NonNull RemoteViews rView) {
+ final AtomicBoolean permissionsOk = new AtomicBoolean(true);
+
+ rView.visitUris(uri -> {
+ int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri);
+ boolean allowed = uriOwnerId == userId;
+ permissionsOk.set(allowed && permissionsOk.get());
+ });
+
+ return permissionsOk.get();
+ }
+
+ /**
+ * Checks the URI permissions of the remote view,
+ * to see if the current userId is able to access it.
+ *
+ * Returns the RemoteView that is passed if user is able, null otherwise.
+ *
+ * TODO: instead of returning a null remoteview when
+ * the current userId cannot access an URI,
+ * return a new RemoteView with the URI removed.
+ */
+ public static @Nullable RemoteViews sanitizeRemoteView(RemoteViews rView) {
+ if (rView == null) return null;
+
+ int userId = ActivityManager.getCurrentUser();
+
+ boolean ok = checkRemoteViewUriPermissions(userId, rView);
+ if (!ok) {
+ Slog.w(TAG,
+ "sanitizeRemoteView() user: " + userId
+ + " tried accessing resource that does not belong to them");
+ }
+ return (ok ? rView : null);
+ }
+
+
@Nullable
static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) {
if (set == null) return null;
diff --git a/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java b/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
index dbeb624bd202..fa414e3b172b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
@@ -53,6 +53,7 @@ import android.widget.TextView;
import com.android.internal.R;
import com.android.server.autofill.AutofillManagerService;
+import com.android.server.autofill.Helper;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -208,7 +209,8 @@ final class DialogFillUi {
}
private void setHeader(View decor, FillResponse response) {
- final RemoteViews presentation = response.getDialogHeader();
+ final RemoteViews presentation =
+ Helper.sanitizeRemoteView(response.getDialogHeader());
if (presentation == null) {
return;
}
@@ -243,9 +245,10 @@ final class DialogFillUi {
}
private void initialAuthenticationLayout(View decor, FillResponse response) {
- RemoteViews presentation = response.getDialogPresentation();
+ RemoteViews presentation = Helper.sanitizeRemoteView(
+ response.getDialogPresentation());
if (presentation == null) {
- presentation = response.getPresentation();
+ presentation = Helper.sanitizeRemoteView(response.getPresentation());
}
if (presentation == null) {
throw new RuntimeException("No presentation for fill dialog authentication");
@@ -289,7 +292,8 @@ final class DialogFillUi {
final Dataset dataset = response.getDatasets().get(i);
final int index = dataset.getFieldIds().indexOf(focusedViewId);
if (index >= 0) {
- RemoteViews presentation = dataset.getFieldDialogPresentation(index);
+ RemoteViews presentation = Helper.sanitizeRemoteView(
+ dataset.getFieldDialogPresentation(index));
if (presentation == null) {
if (sDebug) {
Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because "
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 129ce72e037d..cdfe7bb4f4a7 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -148,8 +148,9 @@ final class FillUi {
final LayoutInflater inflater = LayoutInflater.from(mContext);
- final RemoteViews headerPresentation = response.getHeader();
- final RemoteViews footerPresentation = response.getFooter();
+ final RemoteViews headerPresentation = Helper.sanitizeRemoteView(response.getHeader());
+ final RemoteViews footerPresentation = Helper.sanitizeRemoteView(response.getFooter());
+
final ViewGroup decor;
if (mFullScreen) {
decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null);
@@ -227,6 +228,9 @@ final class FillUi {
ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker);
final View content;
try {
+ if (Helper.sanitizeRemoteView(response.getPresentation()) == null) {
+ throw new RuntimeException("Permission error accessing RemoteView");
+ }
content = response.getPresentation().applyWithTheme(
mContext, decor, interceptionHandler, mThemeId);
container.addView(content);
@@ -306,7 +310,8 @@ final class FillUi {
final Dataset dataset = response.getDatasets().get(i);
final int index = dataset.getFieldIds().indexOf(focusedViewId);
if (index >= 0) {
- final RemoteViews presentation = dataset.getFieldPresentation(index);
+ final RemoteViews presentation = Helper.sanitizeRemoteView(
+ dataset.getFieldPresentation(index));
if (presentation == null) {
Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because "
+ "service didn't provide a presentation for it on " + dataset);
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index f035d0764279..70382f1d5274 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -384,8 +384,7 @@ final class SaveUi {
return false;
}
writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION);
-
- final RemoteViews template = customDescription.getPresentation();
+ final RemoteViews template = Helper.sanitizeRemoteView(customDescription.getPresentation());
if (template == null) {
Slog.w(TAG, "No remote view on custom description");
return false;
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index 77275e056db6..d803c8c8e8c2 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -318,14 +318,14 @@ class AssociationRequestsProcessor {
public void enableSystemDataSync(int associationId, int flags) {
AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- AssociationInfo updated = AssociationInfo.builder(association)
+ AssociationInfo updated = (new AssociationInfo.Builder(association))
.setSystemDataSyncFlags(association.getSystemDataSyncFlags() | flags).build();
mAssociationStore.updateAssociation(updated);
}
public void disableSystemDataSync(int associationId, int flags) {
AssociationInfo association = mAssociationStore.getAssociationById(associationId);
- AssociationInfo updated = AssociationInfo.builder(association)
+ AssociationInfo updated = (new AssociationInfo.Builder(association))
.setSystemDataSyncFlags(association.getSystemDataSyncFlags() & (~flags)).build();
mAssociationStore.updateAssociation(updated);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 611541f671cf..9ac2b6dd69c7 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -18,6 +18,8 @@
package com.android.server.companion;
import static android.Manifest.permission.MANAGE_COMPANION_DEVICES;
+import static android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE;
+import static android.Manifest.permission.USE_COMPANION_TRANSPORTS;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
@@ -44,6 +46,7 @@ import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MINUTES;
+import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -632,29 +635,44 @@ public class CompanionDeviceManagerService extends SystemService {
}
@Override
+ @EnforcePermission(USE_COMPANION_TRANSPORTS)
public void addOnTransportsChangedListener(IOnTransportsChangedListener listener) {
+ addOnTransportsChangedListener_enforcePermission();
+
mTransportManager.addListener(listener);
}
@Override
+ @EnforcePermission(USE_COMPANION_TRANSPORTS)
public void removeOnTransportsChangedListener(IOnTransportsChangedListener listener) {
+ removeOnTransportsChangedListener_enforcePermission();
+
mTransportManager.removeListener(listener);
}
@Override
+ @EnforcePermission(USE_COMPANION_TRANSPORTS)
public void sendMessage(int messageType, byte[] data, int[] associationIds) {
+ sendMessage_enforcePermission();
+
mTransportManager.sendMessage(messageType, data, associationIds);
}
@Override
+ @EnforcePermission(USE_COMPANION_TRANSPORTS)
public void addOnMessageReceivedListener(int messageType,
IOnMessageReceivedListener listener) {
+ addOnMessageReceivedListener_enforcePermission();
+
mTransportManager.addListener(messageType, listener);
}
@Override
+ @EnforcePermission(USE_COMPANION_TRANSPORTS)
public void removeOnMessageReceivedListener(int messageType,
IOnMessageReceivedListener listener) {
+ removeOnMessageReceivedListener_enforcePermission();
+
mTransportManager.removeListener(messageType, listener);
}
@@ -809,7 +827,7 @@ public class CompanionDeviceManagerService extends SystemService {
}
// AssociationInfo class is immutable: create a new AssociationInfo object with updated
// timestamp.
- association = AssociationInfo.builder(association)
+ association = (new AssociationInfo.Builder(association))
.setLastTimeConnected(System.currentTimeMillis())
.build();
mAssociationStore.updateAssociation(association);
@@ -867,7 +885,7 @@ public class CompanionDeviceManagerService extends SystemService {
// AssociationInfo class is immutable: create a new AssociationInfo object with updated
// flag.
- association = AssociationInfo.builder(association)
+ association = (new AssociationInfo.Builder(association))
.setNotifyOnDeviceNearby(active)
.build();
// Do not need to call {@link BleCompanionDeviceScanner#restartScan()} since it will
@@ -1147,7 +1165,7 @@ public class CompanionDeviceManagerService extends SystemService {
*/
private void addToPendingRoleHolderRemoval(@NonNull AssociationInfo association) {
// First: set revoked flag.
- association = AssociationInfo.builder(association)
+ association = (new AssociationInfo.Builder(association))
.setRevoked(true)
.build();
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 04fbab434d1f..a86839293feb 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -16,6 +16,8 @@
package com.android.server.companion;
+import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_CONTEXT_SYNC;
+
import android.companion.AssociationInfo;
import android.companion.ContextSyncMessage;
import android.companion.Telecom;
@@ -30,7 +32,6 @@ import com.android.server.companion.datatransfer.contextsync.BitmapUtils;
import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;
import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
import com.android.server.companion.transport.CompanionTransportManager;
-import com.android.server.companion.transport.Transport;
import java.io.PrintWriter;
import java.util.List;
@@ -135,7 +136,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
case "send-context-sync-empty-message": {
associationId = getNextIntArgRequired();
mTransportManager.createEmulatedTransport(associationId)
- .processMessage(Transport.MESSAGE_REQUEST_CONTEXT_SYNC,
+ .processMessage(MESSAGE_REQUEST_CONTEXT_SYNC,
/* sequence= */ 0,
CrossDeviceSyncController.createEmptyMessage());
break;
@@ -147,7 +148,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
String address = getNextArgRequired();
String facilitator = getNextArgRequired();
mTransportManager.createEmulatedTransport(associationId)
- .processMessage(Transport.MESSAGE_REQUEST_CONTEXT_SYNC,
+ .processMessage(MESSAGE_REQUEST_CONTEXT_SYNC,
/* sequence= */ 0,
CrossDeviceSyncController.createCallCreateMessage(callId,
address, facilitator));
@@ -159,7 +160,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
String callId = getNextArgRequired();
int control = getNextIntArgRequired();
mTransportManager.createEmulatedTransport(associationId)
- .processMessage(Transport.MESSAGE_REQUEST_CONTEXT_SYNC,
+ .processMessage(MESSAGE_REQUEST_CONTEXT_SYNC,
/* sequence= */ 0,
CrossDeviceSyncController.createCallControlMessage(callId,
control));
@@ -184,7 +185,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
}
pos.end(telecomToken);
mTransportManager.createEmulatedTransport(associationId)
- .processMessage(Transport.MESSAGE_REQUEST_CONTEXT_SYNC,
+ .processMessage(MESSAGE_REQUEST_CONTEXT_SYNC,
/* sequence= */ 0, pos.getBytes());
break;
}
@@ -246,7 +247,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
pos.end(callsToken);
pos.end(telecomToken);
mTransportManager.createEmulatedTransport(associationId)
- .processMessage(Transport.MESSAGE_REQUEST_CONTEXT_SYNC,
+ .processMessage(MESSAGE_REQUEST_CONTEXT_SYNC,
/* sequence= */ 0, pos.getBytes());
break;
}
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
index dd7d38f34f28..fcc7a830e9be 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -20,10 +20,10 @@ import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
import static android.companion.CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME;
+import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_PERMISSION_RESTORE;
import static android.content.ComponentName.createRelative;
import static com.android.server.companion.Utils.prepareForIpc;
-import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PERMISSION_RESTORE;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
index 9bd5af956a6e..ad1eff8cebad 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
@@ -16,7 +16,7 @@
package com.android.server.companion.datatransfer.contextsync;
-import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_CONTEXT_SYNC;
+import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_CONTEXT_SYNC;
import android.app.admin.DevicePolicyManager;
import android.companion.AssociationInfo;
diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
index a49021a8eec4..ee285be970c9 100644
--- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
+++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
@@ -17,8 +17,7 @@
package com.android.server.companion.transport;
import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES;
-
-import static com.android.server.companion.transport.Transport.MESSAGE_REQUEST_PERMISSION_RESTORE;
+import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_PERMISSION_RESTORE;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
diff --git a/services/companion/java/com/android/server/companion/transport/Transport.java b/services/companion/java/com/android/server/companion/transport/Transport.java
index 5af3b98d71cc..32d4061db1f7 100644
--- a/services/companion/java/com/android/server/companion/transport/Transport.java
+++ b/services/companion/java/com/android/server/companion/transport/Transport.java
@@ -16,6 +16,11 @@
package com.android.server.companion.transport;
+import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_CONTEXT_SYNC;
+import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_PERMISSION_RESTORE;
+import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_PING;
+import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_REMOTE_AUTHENTICATION;
+
import android.annotation.NonNull;
import android.companion.IOnMessageReceivedListener;
import android.content.Context;
@@ -45,10 +50,6 @@ public abstract class Transport {
protected static final String TAG = "CDM_CompanionTransport";
protected static final boolean DEBUG = Build.IS_DEBUGGABLE;
- static final int MESSAGE_REQUEST_PING = 0x63807378; // ?PIN
- public static final int MESSAGE_REQUEST_CONTEXT_SYNC = 0x63678883; // ?CXS
- public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
-
static final int MESSAGE_RESPONSE_SUCCESS = 0x33838567; // !SUC
static final int MESSAGE_RESPONSE_FAILURE = 0x33706573; // !FAI
@@ -181,7 +182,8 @@ public abstract class Transport {
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, data);
break;
}
- case MESSAGE_REQUEST_CONTEXT_SYNC: {
+ case MESSAGE_REQUEST_CONTEXT_SYNC:
+ case MESSAGE_REQUEST_REMOTE_AUTHENTICATION: {
callback(message, data);
sendMessage(MESSAGE_RESPONSE_SUCCESS, sequence, EmptyArray.BYTE);
break;
diff --git a/services/core/java/com/android/server/PendingIntentUtils.java b/services/core/java/com/android/server/PendingIntentUtils.java
index 1600101b20f4..a72a4d254a2a 100644
--- a/services/core/java/com/android/server/PendingIntentUtils.java
+++ b/services/core/java/com/android/server/PendingIntentUtils.java
@@ -34,6 +34,7 @@ public class PendingIntentUtils {
public static Bundle createDontSendToRestrictedAppsBundle(@Nullable Bundle bundle) {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setDontSendToRestrictedApps(true);
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
if (bundle == null) {
return options.toBundle();
}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index f348af12ff24..bca2d60761d1 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -88,7 +88,7 @@ public class SystemConfig {
private static final int ALLOW_APP_CONFIGS = 0x008;
private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x010;
private static final int ALLOW_OEM_PERMISSIONS = 0x020;
- private static final int ALLOW_HIDDENAPI_ALLOWLISTING = 0x040;
+ private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x040;
private static final int ALLOW_ASSOCIATIONS = 0x080;
// ALLOW_OVERRIDE_APP_RESTRICTIONS allows to use "allow-in-power-save-except-idle",
// "allow-in-power-save", "allow-in-data-usage-save","allow-unthrottled-location",
@@ -237,7 +237,7 @@ public class SystemConfig {
final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();
// These are the packages that are white-listed to be able to run in the
- // background while in power save mode (but not allowlisted from device idle modes),
+ // background while in power save mode (but not whitelisted from device idle modes),
// as read from the configuration files.
final ArraySet<String> mAllowInPowerSaveExceptIdle = new ArraySet<>();
@@ -261,7 +261,7 @@ public class SystemConfig {
// location settings are off, for emergency purposes, as read from the configuration files.
final ArrayMap<String, ArraySet<String>> mAllowIgnoreLocationSettings = new ArrayMap<>();
- // These are the action strings of broadcasts which are allowlisted to
+ // These are the action strings of broadcasts which are whitelisted to
// be delivered anonymously even to apps which target O+.
final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>();
@@ -284,7 +284,7 @@ public class SystemConfig {
final ArrayMap<String, ArrayMap<String, Boolean>> mPackageComponentEnabledState =
new ArrayMap<>();
- // Package names that are exempted from private API denylisting
+ // Package names that are exempted from private API blacklisting
final ArraySet<String> mHiddenApiPackageWhitelist = new ArraySet<>();
// The list of carrier applications which should be disabled until used.
@@ -514,7 +514,7 @@ public class SystemConfig {
/**
* Gets map of packagesNames to userTypes, dictating on which user types each package should NOT
- * be initially installed, even if they are allowlisted, and then removes this map from
+ * be initially installed, even if they are whitelisted, and then removes this map from
* SystemConfig.
* Called by UserManagerService when it is constructed.
*/
@@ -630,10 +630,10 @@ public class SystemConfig {
Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
// Allow Product to customize these configs
- // TODO(b/157203468): ALLOW_HIDDENAPI_ALLOWLISTING must be removed because we prohibited
+ // TODO(b/157203468): ALLOW_HIDDENAPI_WHITELISTING must be removed because we prohibited
// the use of hidden APIs from the product partition.
int productPermissionFlag = ALLOW_FEATURES | ALLOW_LIBS | ALLOW_PERMISSIONS
- | ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_HIDDENAPI_ALLOWLISTING
+ | ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_HIDDENAPI_WHITELISTING
| ALLOW_ASSOCIATIONS | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS
| ALLOW_VENDOR_APEX;
if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.R) {
@@ -757,7 +757,7 @@ public class SystemConfig {
final boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS)
!= 0;
final boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0;
- final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_ALLOWLISTING)
+ final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING)
!= 0;
final boolean allowAssociations = (permissionFlag & ALLOW_ASSOCIATIONS) != 0;
final boolean allowOverrideAppRestrictions =
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 5da0575200f6..5fec8494fb92 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4996,7 +4996,10 @@ public class AccountManagerService
p.setDataPosition(0);
Bundle simulateBundle = p.readBundle();
p.recycle();
- Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
+ Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
+ if (intent != null && intent.getClass() != Intent.class) {
+ return false;
+ }
Intent simulateIntent = simulateBundle.getParcelable(AccountManager.KEY_INTENT,
Intent.class);
if (intent == null) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c1239d53058c..97659a40748c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2414,7 +2414,7 @@ public final class ActiveServices {
// Even if the service is already a FGS, we need to update the notification,
// so we need to call it again.
signalForegroundServiceObserversLocked(r);
- r.postNotification();
+ r.postNotification(true);
if (r.app != null) {
updateServiceForegroundLocked(psr, true);
}
@@ -2472,7 +2472,7 @@ public final class ActiveServices {
} else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
// if it's been deferred, force to visibility
if (!r.mFgsNotificationShown) {
- r.postNotification();
+ r.postNotification(false);
}
dropFgsNotificationStateLocked(r);
if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
@@ -2916,7 +2916,7 @@ public final class ActiveServices {
// in the interval, so we lazy check whether we still need to show
// the notification.
if (r.isForeground && r.app != null) {
- r.postNotification();
+ r.postNotification(true);
r.mFgsNotificationShown = true;
} else {
if (DEBUG_FOREGROUND_SERVICE) {
@@ -5341,7 +5341,7 @@ public final class ActiveServices {
thread.scheduleCreateService(r, r.serviceInfo,
null /* compatInfo (unused but need to keep method signature) */,
app.mState.getReportedProcState());
- r.postNotification();
+ r.postNotification(false);
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3856d2735908..d85e630796a5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3074,6 +3074,22 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ /**
+ * Enforces that the uid of the caller matches the uid of the package.
+ *
+ * @param packageName the name of the package to match uid against.
+ * @param callingUid the uid of the caller.
+ * @throws SecurityException if the calling uid doesn't match uid of the package.
+ */
+ private void enforceCallingPackage(String packageName, int callingUid) {
+ final int userId = UserHandle.getUserId(callingUid);
+ final int packageUid = getPackageManagerInternal().getPackageUid(packageName,
+ /*flags=*/ 0, userId);
+ if (packageUid != callingUid) {
+ throw new SecurityException(packageName + " does not belong to uid " + callingUid);
+ }
+ }
+
@Override
public void setPackageScreenCompatMode(String packageName, int mode) {
mActivityTaskManager.setPackageScreenCompatMode(packageName, mode);
@@ -13629,13 +13645,16 @@ public class ActivityManagerService extends IActivityManager.Stub
// A backup agent has just come up
@Override
public void backupAgentCreated(String agentPackageName, IBinder agent, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ enforceCallingPackage(agentPackageName, callingUid);
+
// Resolve the target user id and enforce permissions.
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid,
userId, /* allowAll */ false, ALLOW_FULL_ONLY, "backupAgentCreated", null);
if (DEBUG_BACKUP) {
Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName + " = " + agent
+ " callingUserId = " + UserHandle.getCallingUserId() + " userId = " + userId
- + " callingUid = " + Binder.getCallingUid() + " uid = " + Process.myUid());
+ + " callingUid = " + callingUid + " uid = " + Process.myUid());
}
synchronized(this) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 50fe6d71d26e..b9914faa469a 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -1212,7 +1212,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
});
}
- public void postNotification() {
+ public void postNotification(boolean byForegroundService) {
if (isForeground && foregroundNoti != null && app != null) {
final int appUid = appInfo.uid;
final int appPid = app.getPid();
@@ -1320,7 +1320,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
nm.enqueueNotification(localPackageName, localPackageName,
appUid, appPid, null, localForegroundId, localForegroundNoti,
- userId);
+ userId, byForegroundService /* byForegroundService */);
foregroundNoti = localForegroundNoti; // save it for amending next time
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
index fc3d7c8114b0..745222873698 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
@@ -216,6 +216,10 @@ public final class BiometricContextProvider implements BiometricContext {
public void subscribe(@NonNull OperationContextExt context,
@NonNull Consumer<OperationContext> consumer) {
mSubscribers.put(context, consumer);
+ // TODO(b/294161627) Combine the getContext/subscribe APIs to avoid race
+ if (context.getDisplayState() != getDisplayState()) {
+ consumer.accept(context.update(this, context.isCrypto()).toAidlContext());
+ }
}
@Override
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index eb7fa1069b7b..add94b1bf937 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -172,6 +172,7 @@ public final class DeviceStateManagerService extends SystemService {
private DeviceState mRearDisplayState;
// TODO(259328837) Generalize for all pending feature requests in the future
+ @GuardedBy("mLock")
@Nullable
private OverrideRequest mRearDisplayPendingOverrideRequest;
@@ -779,7 +780,7 @@ public final class DeviceStateManagerService extends SystemService {
* {@link StatusBarManagerInternal} to notify SystemUI to display the educational dialog.
*/
@GuardedBy("mLock")
- private void showRearDisplayEducationalOverlayLocked(OverrideRequest request) {
+ private void showRearDisplayEducationalOverlayLocked(@NonNull OverrideRequest request) {
mRearDisplayPendingOverrideRequest = request;
StatusBarManagerInternal statusBar =
@@ -844,8 +845,8 @@ public final class DeviceStateManagerService extends SystemService {
* request if it was dismissed in a way that should cancel the feature.
*/
private void onStateRequestOverlayDismissedInternal(boolean shouldCancelRequest) {
- if (mRearDisplayPendingOverrideRequest != null) {
- synchronized (mLock) {
+ synchronized (mLock) {
+ if (mRearDisplayPendingOverrideRequest != null) {
if (shouldCancelRequest) {
ProcessRecord processRecord = mProcessRecords.get(
mRearDisplayPendingOverrideRequest.getPid());
diff --git a/services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java b/services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java
new file mode 100644
index 000000000000..03103834f325
--- /dev/null
+++ b/services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.feature;
+
+import android.hardware.display.DisplayManager;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Helper class to access all DeviceConfig features for display_manager namespace
+ *
+ **/
+public class DeviceConfigParameterProvider {
+
+ private static final String TAG = "DisplayFeatureProvider";
+
+ private final DeviceConfigInterface mDeviceConfig;
+
+ public DeviceConfigParameterProvider(DeviceConfigInterface deviceConfig) {
+ mDeviceConfig = deviceConfig;
+ }
+
+ public boolean isDisableScreenWakeLocksWhileCachedFeatureEnabled() {
+ return mDeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_DISABLE_SCREEN_WAKE_LOCKS_WHILE_CACHED, true);
+ }
+
+ /** add property change listener to DeviceConfig */
+ public void addOnPropertiesChangedListener(Executor executor,
+ DeviceConfig.OnPropertiesChangedListener listener) {
+ mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ executor, listener);
+ }
+}
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 6d70d21e3b84..da93d0b0fc35 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -18,6 +18,8 @@ package com.android.server.dreams;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
+import static android.os.PowerManager.USER_ACTIVITY_EVENT_OTHER;
+import static android.os.PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS;
import android.app.ActivityTaskManager;
import android.app.BroadcastOptions;
@@ -72,6 +74,7 @@ final class DreamController {
private final Handler mHandler;
private final Listener mListener;
private final ActivityTaskManager mActivityTaskManager;
+ private final PowerManager mPowerManager;
private final Intent mDreamingStartedIntent = new Intent(Intent.ACTION_DREAMING_STARTED)
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | FLAG_RECEIVER_FOREGROUND);
@@ -84,6 +87,15 @@ final class DreamController {
private final Intent mCloseNotificationShadeIntent;
private final Bundle mCloseNotificationShadeOptions;
+ /**
+ * If this flag is on, we report user activity to {@link PowerManager} so that the screen
+ * doesn't shut off immediately when a dream quits unexpectedly. The device will instead go to
+ * keyguard and time out back to dreaming shortly.
+ *
+ * This allows the dream a second chance to relaunch in case of an app update or other crash.
+ */
+ private final boolean mResetScreenTimeoutOnUnexpectedDreamExit;
+
private DreamRecord mCurrentDream;
// Whether a dreaming started intent has been broadcast.
@@ -101,6 +113,7 @@ final class DreamController {
mHandler = handler;
mListener = listener;
mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
mCloseNotificationShadeIntent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mCloseNotificationShadeIntent.putExtra(EXTRA_REASON_KEY, EXTRA_REASON_VALUE);
mCloseNotificationShadeIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -110,6 +123,8 @@ final class DreamController {
EXTRA_REASON_VALUE)
.setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
.toBundle();
+ mResetScreenTimeoutOnUnexpectedDreamExit = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_resetScreenTimeoutOnUnexpectedDreamExit);
}
/**
@@ -214,6 +229,17 @@ final class DreamController {
}
/**
+ * Sends a user activity signal to PowerManager to stop the screen from turning off immediately
+ * if there hasn't been any user interaction in a while.
+ */
+ private void resetScreenTimeout() {
+ Slog.i(TAG, "Resetting screen timeout");
+ long time = SystemClock.uptimeMillis();
+ mPowerManager.userActivity(time, USER_ACTIVITY_EVENT_OTHER,
+ USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS);
+ }
+
+ /**
* Stops dreaming.
*
* The current dream, if any, and any unstopped previous dreams are stopped. The device stops
@@ -420,6 +446,9 @@ final class DreamController {
mHandler.post(() -> {
mService = null;
if (mCurrentDream == DreamRecord.this) {
+ if (mResetScreenTimeoutOnUnexpectedDreamExit) {
+ resetScreenTimeout();
+ }
stopDream(true /*immediate*/, "binder died");
}
});
@@ -445,6 +474,9 @@ final class DreamController {
mHandler.post(() -> {
mService = null;
if (mCurrentDream == DreamRecord.this) {
+ if (mResetScreenTimeoutOnUnexpectedDreamExit) {
+ resetScreenTimeout();
+ }
stopDream(true /*immediate*/, "service disconnected");
}
});
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index e9f4bd058297..0a02c49192b9 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -873,6 +873,10 @@ public class LockSettingsService extends ILockSettings.Stub {
getAuthSecretHal();
mDeviceProvisionedObserver.onSystemReady();
+ // Work around an issue in PropertyInvalidatedCache where the cache doesn't work until the
+ // first invalidation. This can be removed if PropertyInvalidatedCache is fixed.
+ LockPatternUtils.invalidateCredentialTypeCache();
+
// TODO: maybe skip this for split system user mode.
mStorage.prefetchUser(UserHandle.USER_SYSTEM);
mBiometricDeferredQueue.systemReady(mInjector.getFingerprintManager(),
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index e8fd6f88359c..11c0f5183e21 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -31,6 +31,7 @@ import android.hardware.weaver.IWeaver;
import android.hardware.weaver.WeaverConfig;
import android.hardware.weaver.WeaverReadResponse;
import android.hardware.weaver.WeaverReadStatus;
+import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -71,7 +72,6 @@ import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
-
/**
* A class that manages a user's synthetic password (SP) ({@link #SyntheticPassword}), along with a
* set of SP protectors that are independent ways that the SP is protected.
@@ -500,7 +500,7 @@ class SyntheticPasswordManager {
private final Context mContext;
private LockSettingsStorage mStorage;
- private IWeaver mWeaver;
+ private volatile IWeaver mWeaver;
private WeaverConfig mWeaverConfig;
private PasswordSlotManager mPasswordSlotManager;
@@ -531,17 +531,63 @@ class SyntheticPasswordManager {
}
}
- private IWeaver getWeaverService() {
- // Try to get the AIDL service first
+ private class WeaverDiedRecipient implements IBinder.DeathRecipient {
+ // Not synchronized on the outer class, since setting the pointer to null is atomic, and we
+ // don't want to have to worry about any sort of deadlock here.
+ @Override
+ public void binderDied() {
+ // Weaver died. Try to recover by setting mWeaver to null, which makes
+ // getWeaverService() look up the service again. This is done only as a simple
+ // robustness measure; it should not be relied on. If this triggers, the root cause is
+ // almost certainly a bug in the device's Weaver implementation, which must be fixed.
+ Slog.wtf(TAG, "Weaver service has died");
+ mWeaver.asBinder().unlinkToDeath(this, 0);
+ mWeaver = null;
+ }
+ }
+
+ private @Nullable IWeaver getWeaverAidlService() {
+ final IWeaver aidlWeaver;
try {
- IWeaver aidlWeaver = IWeaver.Stub.asInterface(
- ServiceManager.waitForDeclaredService(IWeaver.DESCRIPTOR + "/default"));
- if (aidlWeaver != null) {
- Slog.i(TAG, "Using AIDL weaver service");
- return aidlWeaver;
- }
+ aidlWeaver =
+ IWeaver.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(IWeaver.DESCRIPTOR + "/default"));
} catch (SecurityException e) {
Slog.w(TAG, "Does not have permissions to get AIDL weaver service");
+ return null;
+ }
+ if (aidlWeaver == null) {
+ return null;
+ }
+ final int aidlVersion;
+ try {
+ aidlVersion = aidlWeaver.getInterfaceVersion();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Cannot get AIDL weaver service version", e);
+ return null;
+ }
+ if (aidlVersion < 2) {
+ Slog.w(TAG,
+ "Ignoring AIDL weaver service v"
+ + aidlVersion
+ + " because only v2 and later are supported");
+ return null;
+ }
+ Slog.i(TAG, "Found AIDL weaver service v" + aidlVersion);
+ return aidlWeaver;
+ }
+
+ private @Nullable IWeaver getWeaverServiceInternal() {
+ // Try to get the AIDL service first
+ IWeaver aidlWeaver = getWeaverAidlService();
+ if (aidlWeaver != null) {
+ Slog.i(TAG, "Using AIDL weaver service");
+ try {
+ aidlWeaver.asBinder().linkToDeath(new WeaverDiedRecipient(), 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to register Weaver death recipient", e);
+ }
+ return aidlWeaver;
}
// If the AIDL service can't be found, look for the HIDL service
@@ -563,15 +609,20 @@ class SyntheticPasswordManager {
return LockPatternUtils.isAutoPinConfirmFeatureAvailable();
}
- private synchronized boolean isWeaverAvailable() {
- if (mWeaver != null) {
- return true;
+ /**
+ * Returns a handle to the Weaver service, or null if Weaver is unavailable. Note that not all
+ * devices support Weaver.
+ */
+ private synchronized @Nullable IWeaver getWeaverService() {
+ IWeaver weaver = mWeaver;
+ if (weaver != null) {
+ return weaver;
}
// Re-initialize weaver in case there was a transient error preventing access to it.
- IWeaver weaver = getWeaverService();
+ weaver = getWeaverServiceInternal();
if (weaver == null) {
- return false;
+ return null;
}
final WeaverConfig weaverConfig;
@@ -579,19 +630,18 @@ class SyntheticPasswordManager {
weaverConfig = weaver.getConfig();
} catch (RemoteException | ServiceSpecificException e) {
Slog.e(TAG, "Failed to get weaver config", e);
- return false;
+ return null;
}
if (weaverConfig == null || weaverConfig.slots <= 0) {
Slog.e(TAG, "Invalid weaver config");
- return false;
+ return null;
}
mWeaver = weaver;
mWeaverConfig = weaverConfig;
mPasswordSlotManager.refreshActiveSlots(getUsedWeaverSlots());
Slog.i(TAG, "Weaver service initialized");
-
- return true;
+ return weaver;
}
/**
@@ -601,7 +651,7 @@ class SyntheticPasswordManager {
*
* @return the value stored in the weaver slot, or null if the operation fails
*/
- private byte[] weaverEnroll(int slot, byte[] key, @Nullable byte[] value) {
+ private byte[] weaverEnroll(IWeaver weaver, int slot, byte[] key, @Nullable byte[] value) {
if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) {
throw new IllegalArgumentException("Invalid slot for weaver");
}
@@ -614,7 +664,7 @@ class SyntheticPasswordManager {
value = SecureRandomUtils.randomBytes(mWeaverConfig.valueSize);
}
try {
- mWeaver.write(slot, key, value);
+ weaver.write(slot, key, value);
} catch (RemoteException e) {
Slog.e(TAG, "weaver write binder call failed, slot: " + slot, e);
return null;
@@ -643,7 +693,7 @@ class SyntheticPasswordManager {
* the verification is successful, throttled or failed. If successful, the bound secret
* is also returned.
*/
- private VerifyCredentialResponse weaverVerify(int slot, byte[] key) {
+ private VerifyCredentialResponse weaverVerify(IWeaver weaver, int slot, byte[] key) {
if (slot == INVALID_WEAVER_SLOT || slot >= mWeaverConfig.slots) {
throw new IllegalArgumentException("Invalid slot for weaver");
}
@@ -654,7 +704,7 @@ class SyntheticPasswordManager {
}
final WeaverReadResponse readResponse;
try {
- readResponse = mWeaver.read(slot, key);
+ readResponse = weaver.read(slot, key);
} catch (RemoteException e) {
Slog.e(TAG, "weaver read failed, slot: " + slot, e);
return VerifyCredentialResponse.ERROR;
@@ -846,14 +896,15 @@ class SyntheticPasswordManager {
int slot = loadWeaverSlot(protectorId, userId);
destroyState(WEAVER_SLOT_NAME, protectorId, userId);
if (slot != INVALID_WEAVER_SLOT) {
- if (!isWeaverAvailable()) {
+ final IWeaver weaver = getWeaverService();
+ if (weaver == null) {
Slog.e(TAG, "Cannot erase Weaver slot because Weaver is unavailable");
return;
}
Set<Integer> usedSlots = getUsedWeaverSlots();
if (!usedSlots.contains(slot)) {
Slogf.i(TAG, "Erasing Weaver slot %d", slot);
- weaverEnroll(slot, null, null);
+ weaverEnroll(weaver, slot, null, null);
mPasswordSlotManager.markSlotDeleted(slot);
} else {
Slogf.i(TAG, "Weaver slot %d was already reused; not erasing it", slot);
@@ -931,13 +982,14 @@ class SyntheticPasswordManager {
Slogf.i(TAG, "Creating LSKF-based protector %016x for user %d", protectorId, userId);
- if (isWeaverAvailable()) {
+ final IWeaver weaver = getWeaverService();
+ if (weaver != null) {
// Weaver is available, so make the protector use it to verify the LSKF. Do this even
// if the LSKF is empty, as that gives us support for securely deleting the protector.
int weaverSlot = getNextAvailableWeaverSlot();
Slogf.i(TAG, "Enrolling LSKF for user %d into Weaver slot %d", userId, weaverSlot);
- byte[] weaverSecret = weaverEnroll(weaverSlot, stretchedLskfToWeaverKey(stretchedLskf),
- null);
+ byte[] weaverSecret = weaverEnroll(weaver, weaverSlot,
+ stretchedLskfToWeaverKey(stretchedLskf), null);
if (weaverSecret == null) {
throw new IllegalStateException(
"Fail to enroll user password under weaver " + userId);
@@ -1024,7 +1076,8 @@ class SyntheticPasswordManager {
}
return VerifyCredentialResponse.fromGateKeeperResponse(response);
} else if (persistentData.type == PersistentData.TYPE_SP_WEAVER) {
- if (!isWeaverAvailable()) {
+ final IWeaver weaver = getWeaverService();
+ if (weaver == null) {
Slog.e(TAG, "No weaver service to verify SP-based FRP credential");
return VerifyCredentialResponse.ERROR;
}
@@ -1032,7 +1085,8 @@ class SyntheticPasswordManager {
byte[] stretchedLskf = stretchLskf(userCredential, pwd);
int weaverSlot = persistentData.userId;
- return weaverVerify(weaverSlot, stretchedLskfToWeaverKey(stretchedLskf)).stripPayload();
+ return weaverVerify(weaver, weaverSlot,
+ stretchedLskfToWeaverKey(stretchedLskf)).stripPayload();
} else {
Slog.e(TAG, "persistentData.type must be TYPE_SP_GATEKEEPER or TYPE_SP_WEAVER, but is "
+ persistentData.type);
@@ -1134,7 +1188,7 @@ class SyntheticPasswordManager {
TokenData tokenData = new TokenData();
tokenData.mType = type;
final byte[] secdiscardable = SecureRandomUtils.randomBytes(SECDISCARDABLE_LENGTH);
- if (isWeaverAvailable()) {
+ if (getWeaverService() != null) {
tokenData.weaverSecret = SecureRandomUtils.randomBytes(mWeaverConfig.valueSize);
tokenData.secdiscardableOnDisk = SyntheticPasswordCrypto.encrypt(tokenData.weaverSecret,
PERSONALIZATION_WEAVER_TOKEN, secdiscardable);
@@ -1177,10 +1231,11 @@ class SyntheticPasswordManager {
return false;
}
Slogf.i(TAG, "Creating token-based protector %016x for user %d", tokenHandle, userId);
- if (isWeaverAvailable()) {
+ final IWeaver weaver = getWeaverService();
+ if (weaver != null) {
int slot = getNextAvailableWeaverSlot();
Slogf.i(TAG, "Using Weaver slot %d for new token-based protector", slot);
- if (weaverEnroll(slot, null, tokenData.weaverSecret) == null) {
+ if (weaverEnroll(weaver, slot, null, tokenData.weaverSecret) == null) {
Slog.e(TAG, "Failed to enroll weaver secret when activating token");
return false;
}
@@ -1269,12 +1324,14 @@ class SyntheticPasswordManager {
int weaverSlot = loadWeaverSlot(protectorId, userId);
if (weaverSlot != INVALID_WEAVER_SLOT) {
// Protector uses Weaver to verify the LSKF
- if (!isWeaverAvailable()) {
+ final IWeaver weaver = getWeaverService();
+ if (weaver == null) {
Slog.e(TAG, "Protector uses Weaver, but Weaver is unavailable");
result.gkResponse = VerifyCredentialResponse.ERROR;
return result;
}
- result.gkResponse = weaverVerify(weaverSlot, stretchedLskfToWeaverKey(stretchedLskf));
+ result.gkResponse = weaverVerify(weaver, weaverSlot,
+ stretchedLskfToWeaverKey(stretchedLskf));
if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
return result;
}
@@ -1442,12 +1499,13 @@ class SyntheticPasswordManager {
}
int slotId = loadWeaverSlot(protectorId, userId);
if (slotId != INVALID_WEAVER_SLOT) {
- if (!isWeaverAvailable()) {
+ final IWeaver weaver = getWeaverService();
+ if (weaver == null) {
Slog.e(TAG, "Protector uses Weaver, but Weaver is unavailable");
result.gkResponse = VerifyCredentialResponse.ERROR;
return result;
}
- VerifyCredentialResponse response = weaverVerify(slotId, null);
+ VerifyCredentialResponse response = weaverVerify(weaver, slotId, null);
if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK ||
response.getGatekeeperHAT() == null) {
Slog.e(TAG,
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 9185a00da570..4084462d3f28 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -1062,6 +1062,14 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
!= 0) {
return;
}
+
+ if (pi != null && pi.isActivity()) {
+ Log.w(
+ TAG,
+ "Ignoring invalid media button receiver targeting an activity: " + pi);
+ return;
+ }
+
mMediaButtonReceiverHolder =
MediaButtonReceiverHolder.create(mUserId, pi, mPackageName);
mService.onMediaButtonReceiverChanged(MediaSessionRecord.this);
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 65e34e682724..38aac4648e34 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -117,6 +117,10 @@ public final class MediaProjectionManagerService extends SystemService
// WindowManagerService -> MediaProjectionManagerService -> DisplayManagerService
// See mediaprojection.md
private final Object mLock = new Object();
+ // A handler for posting tasks that must interact with a service holding another lock,
+ // especially for services that will eventually acquire the WindowManager lock.
+ @NonNull private final Handler mHandler;
+
private final Map<IBinder, IBinder.DeathRecipient> mDeathEaters;
private final CallbackDelegate mCallbackDelegate;
@@ -145,6 +149,8 @@ public final class MediaProjectionManagerService extends SystemService
super(context);
mContext = context;
mInjector = injector;
+ // Post messages on the main thread; no need for a separate thread.
+ mHandler = new Handler(Looper.getMainLooper());
mClock = injector.createClock();
mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
mCallbackDelegate = new CallbackDelegate();
@@ -238,15 +244,20 @@ public final class MediaProjectionManagerService extends SystemService
if (!mProjectionGrant.requiresForegroundService()) {
return;
}
+ }
- if (mActivityManagerInternal.hasRunningForegroundService(
- uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
- // If there is any process within this UID running a FGS
- // with the mediaProjection type, that's Okay.
- return;
- }
+ // Run outside the lock when calling into ActivityManagerService.
+ if (mActivityManagerInternal.hasRunningForegroundService(
+ uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
+ // If there is any process within this UID running a FGS
+ // with the mediaProjection type, that's Okay.
+ return;
+ }
- mProjectionGrant.stop();
+ synchronized (mLock) {
+ if (mProjectionGrant != null) {
+ mProjectionGrant.stop();
+ }
}
}
@@ -854,7 +865,6 @@ public final class MediaProjectionManagerService extends SystemService
mTargetSdkVersion = targetSdkVersion;
mIsPrivileged = isPrivileged;
mCreateTimeMs = mClock.uptimeMillis();
- // TODO(b/267740338): Add unit test.
mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
MEDIA_PROJECTION_TOKEN_EVENT_CREATED);
}
@@ -911,6 +921,10 @@ public final class MediaProjectionManagerService extends SystemService
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
+ // Cache result of calling into ActivityManagerService outside of the lock, to prevent
+ // deadlock with WindowManagerService.
+ final boolean hasFGS = mActivityManagerInternal.hasRunningForegroundService(
+ uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
synchronized (mLock) {
if (isCurrentProjection(asBinder())) {
Slog.w(TAG, "UID " + Binder.getCallingUid()
@@ -922,9 +936,7 @@ public final class MediaProjectionManagerService extends SystemService
}
if (REQUIRE_FG_SERVICE_FOR_PROJECTION
- && requiresForegroundService()
- && !mActivityManagerInternal.hasRunningForegroundService(
- uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
+ && requiresForegroundService() && !hasFGS) {
throw new SecurityException("Media projections require a foreground service"
+ " of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION");
}
@@ -1013,10 +1025,11 @@ public final class MediaProjectionManagerService extends SystemService
mToken = null;
unregisterCallback(mCallback);
mCallback = null;
- // TODO(b/267740338): Add unit test.
- mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
- MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED);
}
+ // Run on a separate thread, to ensure no lock is held when calling into
+ // ActivityManagerService.
+ mHandler.post(() -> mActivityManagerInternal.notifyMediaProjectionEvent(uid, asBinder(),
+ MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED));
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/media/projection/mediaprojection.md b/services/core/java/com/android/server/media/projection/mediaprojection.md
index bccdf3411903..34e7ecc6c6c5 100644
--- a/services/core/java/com/android/server/media/projection/mediaprojection.md
+++ b/services/core/java/com/android/server/media/projection/mediaprojection.md
@@ -11,6 +11,11 @@ Calls must follow the below invocation order while holding locks:
`WindowManagerService -> MediaProjectionManagerService -> DisplayManagerService`
+`MediaProjectionManagerService` should never lock when calling into a service that may acquire
+the `WindowManagerService` global lock (for example,
+`MediaProjectionManagerService -> ActivityManagerService` may result in deadlock, since
+`ActivityManagerService -> WindowManagerService`).
+
### Justification
`MediaProjectionManagerService` calls into `WindowManagerService` in the below cases. While handling
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 919fc712c409..c240bcbce911 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -27,6 +27,9 @@ public interface NotificationManagerInternal {
NotificationChannelGroup getNotificationChannelGroup(String pkg, int uid, String channelId);
void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int userId);
+ void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
+ String tag, int id, Notification notification, int userId,
+ boolean byForegroundService);
void cancelNotification(String pkg, String basePkg, int callingUid, int callingPid,
String tag, int id, int userId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 488745c6ea97..647087de1c04 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2528,7 +2528,8 @@ public class NotificationManagerService extends SystemService {
}
enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(),
r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(),
- r.getSbn().getId(), r.getSbn().getNotification(), userId, muteOnReturn);
+ r.getSbn().getId(), r.getSbn().getNotification(), userId, muteOnReturn,
+ false /* byForegroundService */);
} catch (Exception e) {
Slog.e(TAG, "Cannot un-snooze notification", e);
}
@@ -3518,7 +3519,8 @@ public class NotificationManagerService extends SystemService {
public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Notification notification, int userId) throws RemoteException {
enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
- Binder.getCallingPid(), tag, id, notification, userId);
+ Binder.getCallingPid(), tag, id, notification, userId,
+ false /* byForegroundService */);
}
@Override
@@ -4442,7 +4444,7 @@ public class NotificationManagerService extends SystemService {
// Remove background token before returning notification to untrusted app, this
// ensures the app isn't able to perform background operations that are
// associated with notification interactions.
- notification.setAllowlistToken(null);
+ notification.clearAllowlistToken();
return new StatusBarNotification(
sbn.getPackageName(),
sbn.getOpPkg(),
@@ -5594,6 +5596,11 @@ public class NotificationManagerService extends SystemService {
boolean granted, boolean userSet) {
Objects.requireNonNull(listener);
checkNotificationListenerAccess();
+ if (granted && listener.flattenToString().length()
+ > NotificationManager.MAX_SERVICE_COMPONENT_NAME_LENGTH) {
+ throw new IllegalArgumentException(
+ "Component name too long: " + listener.flattenToString());
+ }
if (!userSet && isNotificationListenerAccessUserSet(listener)) {
// Don't override user's choice
return;
@@ -6069,7 +6076,7 @@ public class NotificationManagerService extends SystemService {
}
if (summaryRecord != null && checkDisqualifyingFeatures(userId, uid,
summaryRecord.getSbn().getId(), summaryRecord.getSbn().getTag(), summaryRecord,
- true)) {
+ true, false)) {
return summaryRecord;
}
}
@@ -6398,7 +6405,15 @@ public class NotificationManagerService extends SystemService {
public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int userId) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
- userId);
+ userId, false /* byForegroundService */);
+ }
+
+ @Override
+ public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
+ String tag, int id, Notification notification, int userId,
+ boolean byForegroundService) {
+ enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
+ userId, byForegroundService);
}
@Override
@@ -6576,19 +6591,19 @@ public class NotificationManagerService extends SystemService {
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
- int incomingUserId) {
+ int incomingUserId, boolean byForegroundService) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
- incomingUserId, false);
+ incomingUserId, false /* postSilently */, byForegroundService);
}
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
- int incomingUserId, boolean postSilently) {
+ int incomingUserId, boolean postSilently, boolean byForegroundService) {
PostNotificationTracker tracker = acquireWakeLockForPost(pkg, callingUid);
boolean enqueued = false;
try {
enqueued = enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id,
- notification, incomingUserId, postSilently, tracker);
+ notification, incomingUserId, postSilently, tracker, byForegroundService);
} finally {
if (!enqueued) {
tracker.cancel();
@@ -6619,10 +6634,10 @@ public class NotificationManagerService extends SystemService {
* @return True if we successfully processed the notification and handed off the task of
* enqueueing it to a background thread; false otherwise.
*/
- private boolean enqueueNotificationInternal(final String pkg, final String opPkg,
+ private boolean enqueueNotificationInternal(final String pkg, final String opPkg, //HUI
final int callingUid, final int callingPid, final String tag, final int id,
final Notification notification, int incomingUserId, boolean postSilently,
- PostNotificationTracker tracker) {
+ PostNotificationTracker tracker, boolean byForegroundService) {
if (DBG) {
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+ " notification=" + notification);
@@ -6768,7 +6783,7 @@ public class NotificationManagerService extends SystemService {
mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid));
if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
- r.getSbn().getOverrideGroupKey() != null)) {
+ r.getSbn().getOverrideGroupKey() != null, byForegroundService)) {
return false;
}
@@ -7000,7 +7015,7 @@ public class NotificationManagerService extends SystemService {
*/
private boolean canBeNonDismissible(ApplicationInfo ai, Notification notification) {
return notification.isMediaNotification() || isEnterpriseExempted(ai)
- || isCallNotification(ai.packageName, ai.uid, notification)
+ || notification.isStyle(Notification.CallStyle.class)
|| isDefaultSearchSelectorPackage(ai.packageName);
}
@@ -7188,7 +7203,7 @@ public class NotificationManagerService extends SystemService {
* Has side effects.
*/
boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
- NotificationRecord r, boolean isAutogroup) {
+ NotificationRecord r, boolean isAutogroup, boolean byForegroundService) {
Notification n = r.getNotification();
final String pkg = r.getSbn().getPackageName();
final boolean isSystemNotification =
@@ -7278,7 +7293,8 @@ public class NotificationManagerService extends SystemService {
if (n.isStyle(Notification.CallStyle.class)) {
boolean hasFullScreenIntent = n.fullScreenIntent != null;
boolean requestedFullScreenIntent = (n.flags & FLAG_FSI_REQUESTED_BUT_DENIED) != 0;
- if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent) {
+ if (!n.isFgsOrUij() && !hasFullScreenIntent && !requestedFullScreenIntent
+ && !byForegroundService) {
throw new IllegalArgumentException(r.getKey() + " Not posted."
+ " CallStyle notifications must be for a foreground service or"
+ " user initated job or use a fullScreenIntent.");
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index 0cc4fc4e0516..f26d56ec28a0 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -30,6 +30,7 @@ import android.app.Person;
import android.os.Bundle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
+import android.util.Log;
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEvent;
@@ -45,6 +46,8 @@ import java.util.Objects;
*/
interface NotificationRecordLogger {
+ static final String TAG = "NotificationRecordLogger";
+
// The high-level interface used by clients.
/**
@@ -225,51 +228,40 @@ interface NotificationRecordLogger {
@NotificationStats.DismissalSurface int surface) {
// Shouldn't be possible to get a non-dismissed notification here.
if (surface == NotificationStats.DISMISSAL_NOT_DISMISSED) {
- if (NotificationManagerService.DBG) {
- throw new IllegalArgumentException("Unexpected surface " + surface);
- }
+ Log.wtf(TAG, "Unexpected surface: " + surface + " with reason " + reason);
return INVALID;
}
- // Most cancel reasons do not have a meaningful surface. Reason codes map directly
- // to NotificationCancelledEvent codes.
- if (surface == NotificationStats.DISMISSAL_OTHER) {
+
+ // User cancels have a meaningful surface, which we differentiate by. See b/149038335
+ // for caveats.
+ if (reason == REASON_CANCEL) {
+ switch (surface) {
+ case NotificationStats.DISMISSAL_PEEK:
+ return NOTIFICATION_CANCEL_USER_PEEK;
+ case NotificationStats.DISMISSAL_AOD:
+ return NOTIFICATION_CANCEL_USER_AOD;
+ case NotificationStats.DISMISSAL_SHADE:
+ return NOTIFICATION_CANCEL_USER_SHADE;
+ case NotificationStats.DISMISSAL_BUBBLE:
+ return NOTIFICATION_CANCEL_USER_BUBBLE;
+ case NotificationStats.DISMISSAL_LOCKSCREEN:
+ return NOTIFICATION_CANCEL_USER_LOCKSCREEN;
+ case NotificationStats.DISMISSAL_OTHER:
+ return NOTIFICATION_CANCEL_USER_OTHER;
+ default:
+ Log.wtf(TAG, "Unexpected surface: " + surface + " with reason " + reason);
+ return INVALID;
+ }
+ } else {
if ((REASON_CLICK <= reason) && (reason <= REASON_CLEAR_DATA)) {
return NotificationCancelledEvent.values()[reason];
}
if (reason == REASON_ASSISTANT_CANCEL) {
return NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT;
}
- if (NotificationManagerService.DBG) {
- throw new IllegalArgumentException("Unexpected cancel reason " + reason);
- }
+ Log.wtf(TAG, "Unexpected reason: " + reason + " with surface " + surface);
return INVALID;
}
- // User cancels have a meaningful surface, which we differentiate by. See b/149038335
- // for caveats.
- if (reason != REASON_CANCEL) {
- if (NotificationManagerService.DBG) {
- throw new IllegalArgumentException("Unexpected cancel with surface " + reason);
- }
- return INVALID;
- }
- switch (surface) {
- case NotificationStats.DISMISSAL_PEEK:
- return NOTIFICATION_CANCEL_USER_PEEK;
- case NotificationStats.DISMISSAL_AOD:
- return NOTIFICATION_CANCEL_USER_AOD;
- case NotificationStats.DISMISSAL_SHADE:
- return NOTIFICATION_CANCEL_USER_SHADE;
- case NotificationStats.DISMISSAL_BUBBLE:
- return NOTIFICATION_CANCEL_USER_BUBBLE;
- case NotificationStats.DISMISSAL_LOCKSCREEN:
- return NOTIFICATION_CANCEL_USER_LOCKSCREEN;
- default:
- if (NotificationManagerService.DBG) {
- throw new IllegalArgumentException("Unexpected surface for user-dismiss "
- + reason);
- }
- return INVALID;
- }
}
}
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 39cd88810961..8bd2982d1ead 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -1050,7 +1050,7 @@ public final class DexOptHelper {
context.unregisterReceiver(this);
artManager.scheduleBackgroundDexoptJob();
}
- }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ }, new IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED));
}
/**
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 50f1673cae44..622cb6609630 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -110,6 +110,7 @@ import android.app.backup.IBackupManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.DataLoaderType;
@@ -119,7 +120,6 @@ import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.content.pm.ResolveInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
@@ -166,6 +166,7 @@ import com.android.internal.util.CollectionUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.EventLogTags;
import com.android.server.LocalManagerRegistry;
+import com.android.server.SystemConfig;
import com.android.server.art.model.DexoptParams;
import com.android.server.art.model.DexoptResult;
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
@@ -184,7 +185,9 @@ import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedLibraryWrapper;
import com.android.server.pm.pkg.component.ComponentMutateUtils;
+import com.android.server.pm.pkg.component.ParsedActivity;
import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
import com.android.server.pm.pkg.component.ParsedPermission;
import com.android.server.pm.pkg.component.ParsedPermissionGroup;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
@@ -207,6 +210,7 @@ import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -227,6 +231,7 @@ final class InstallPackageHelper {
private final ViewCompiler mViewCompiler;
private final SharedLibrariesImpl mSharedLibraries;
private final PackageManagerServiceInjector mInjector;
+ private final UpdateOwnershipHelper mUpdateOwnershipHelper;
// TODO(b/198166813): remove PMS dependency
InstallPackageHelper(PackageManagerService pm, AppDataHelper appDataHelper) {
@@ -244,6 +249,7 @@ final class InstallPackageHelper {
mPackageAbiHelper = pm.mInjector.getAbiHelper();
mViewCompiler = pm.mInjector.getViewCompiler();
mSharedLibraries = pm.mInjector.getSharedLibrariesImpl();
+ mUpdateOwnershipHelper = pm.mInjector.getUpdateOwnershipHelper();
}
InstallPackageHelper(PackageManagerService pm) {
@@ -329,6 +335,8 @@ final class InstallPackageHelper {
final String updateOwnerFromSysconfig = isApex || !pkgSetting.isSystem() ? null
: mPm.mInjector.getSystemConfig().getSystemAppUpdateOwnerPackageName(
parsedPackage.getPackageName());
+ final boolean isUpdateOwnershipDenylisted =
+ mUpdateOwnershipHelper.isUpdateOwnershipDenylisted(parsedPackage.getPackageName());
final boolean isUpdateOwnershipEnabled = oldUpdateOwner != null;
// For standard install (install via session), the installSource isn't null.
@@ -364,6 +372,9 @@ final class InstallPackageHelper {
& PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0;
final boolean isSameUpdateOwner =
TextUtils.equals(oldUpdateOwner, installSource.mInstallerPackageName);
+ final boolean isInstallerUpdateOwnerDenylistProvider =
+ mUpdateOwnershipHelper.isUpdateOwnershipDenyListProvider(
+ installSource.mUpdateOwnerPackageName);
// Here we handle the update owner for the package, and the rules are:
// -. Only enabling update ownership enforcement on initial installation if the
@@ -371,13 +382,16 @@ final class InstallPackageHelper {
// -. Once the installer changes and users agree to proceed, clear the update
// owner (package state in other users are taken into account as well).
if (!isUpdate) {
- if (!isRequestUpdateOwnership) {
+ if (!isRequestUpdateOwnership
+ || isUpdateOwnershipDenylisted
+ || isInstallerUpdateOwnerDenylistProvider) {
installSource = installSource.setUpdateOwnerPackageName(null);
} else if ((!isUpdateOwnershipEnabled && pkgAlreadyExists)
|| (isUpdateOwnershipEnabled && !isSameUpdateOwner)) {
installSource = installSource.setUpdateOwnerPackageName(null);
}
- } else if (!isSameUpdateOwner || !isUpdateOwnershipEnabled) {
+ } else if (!isSameUpdateOwner
+ || !isUpdateOwnershipEnabled) {
installSource = installSource.setUpdateOwnerPackageName(null);
}
}
@@ -470,6 +484,19 @@ final class InstallPackageHelper {
pkgSetting.setLoadingProgress(1f);
}
+ ArraySet<String> listItems = mUpdateOwnershipHelper.readUpdateOwnerDenyList(pkgSetting);
+ if (listItems != null && !listItems.isEmpty()) {
+ mUpdateOwnershipHelper.addToUpdateOwnerDenyList(pkgSetting.getPackageName(), listItems);
+ for (String unownedPackage : listItems) {
+ PackageSetting unownedSetting = mPm.mSettings.getPackageLPr(unownedPackage);
+ SystemConfig config = SystemConfig.getInstance();
+ if (unownedSetting != null
+ && config.getSystemAppUpdateOwnerPackageName(unownedPackage) == null) {
+ unownedSetting.setUpdateOwnerPackage(null);
+ }
+ }
+ }
+
return pkg;
}
@@ -3925,23 +3952,6 @@ final class InstallPackageHelper {
}
}
- // If this is a system app we hadn't seen before, and this is a first boot or OTA,
- // we need to unstop it if it doesn't have a launcher entry.
- if (mPm.mShouldStopSystemPackagesByDefault && scanResult.mRequest.mPkgSetting == null
- && ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0)
- && ((scanFlags & SCAN_AS_SYSTEM) != 0)) {
- final Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
- launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- launcherIntent.setPackage(parsedPackage.getPackageName());
- final List<ResolveInfo> launcherActivities =
- mPm.snapshotComputer().queryIntentActivitiesInternal(launcherIntent, null,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 0);
- if (launcherActivities.isEmpty()) {
- scanResult.mPkgSetting.setStopped(false, 0);
- }
- }
-
if (mIncrementalManager != null && isIncrementalPath(parsedPackage.getPath())) {
if (scanResult.mPkgSetting != null && scanResult.mPkgSetting.isLoading()) {
// Continue monitoring loading progress of active incremental packages
@@ -4314,6 +4324,8 @@ final class InstallPackageHelper {
// - It's an APEX or overlay package since stopped state does not affect them.
// - It is enumerated with a <initial-package-state> tag having the stopped attribute
// set to false
+ // - It doesn't have an enabled and exported launcher activity, which means the user
+ // wouldn't have a way to un-stop it
final boolean isApexPkg = (scanFlags & SCAN_AS_APEX) != 0;
if (mPm.mShouldStopSystemPackagesByDefault
&& scanSystemPartition
@@ -4322,8 +4334,9 @@ final class InstallPackageHelper {
&& !parsedPackage.isOverlayIsStatic()
) {
String packageName = parsedPackage.getPackageName();
- if (!mPm.mInitialNonStoppedSystemPackages.contains(packageName)
- && !"android".contentEquals(packageName)) {
+ if (!"android".contentEquals(packageName)
+ && !mPm.mInitialNonStoppedSystemPackages.contains(packageName)
+ && hasLauncherEntry(parsedPackage)) {
scanFlags |= SCAN_AS_STOPPED_SYSTEM_APP;
}
}
@@ -4333,6 +4346,26 @@ final class InstallPackageHelper {
return new Pair<>(scanResult, shouldHideSystemApp);
}
+ private static boolean hasLauncherEntry(ParsedPackage parsedPackage) {
+ final HashSet<String> categories = new HashSet<>();
+ categories.add(Intent.CATEGORY_LAUNCHER);
+ final List<ParsedActivity> activities = parsedPackage.getActivities();
+ for (int indexActivity = 0; indexActivity < activities.size(); indexActivity++) {
+ final ParsedActivity activity = activities.get(indexActivity);
+ if (!activity.isEnabled() || !activity.isExported()) {
+ continue;
+ }
+ final List<ParsedIntentInfo> intents = activity.getIntents();
+ for (int indexIntent = 0; indexIntent < intents.size(); indexIntent++) {
+ final IntentFilter intentFilter = intents.get(indexIntent).getIntentFilter();
+ if (intentFilter != null && intentFilter.matchCategories(categories) == null) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
/**
* Returns if forced apk verification can be skipped for the whole package, including splits.
*/
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index f0e38955f050..d662aaedb774 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -67,6 +67,7 @@ import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.Context;
@@ -311,6 +312,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final long SILENT_INSTALL_ALLOWED = 265131695L;
/**
+ * The system supports pre-approval and update ownership features from
+ * {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE API 34}. The change id is used to make sure
+ * the system includes the fix of pre-approval with update ownership case. When checking the
+ * change id, if it is disabled, it means the build includes the fix. The more detail is on
+ * b/293644536.
+ * See {@link PackageInstaller.SessionParams#setRequestUpdateOwnership(boolean)} and
+ * {@link #requestUserPreapproval(PreapprovalDetails, IntentSender)} for more details.
+ */
+ @Disabled
+ @ChangeId
+ private static final long PRE_APPROVAL_WITH_UPDATE_OWNERSHIP_FIX = 293644536L;
+
+ /**
* The default value of {@link #mValidatedTargetSdk} is {@link Integer#MAX_VALUE}. If {@link
* #mValidatedTargetSdk} is compared with {@link Build.VERSION_CODES#S} before getting the
* target sdk version from a validated apk in {@link #validateApkInstallLocked()}, the compared
@@ -893,16 +907,27 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (mPermissionsManuallyAccepted) {
return USER_ACTION_NOT_NEEDED;
}
- packageName = mPackageName;
+ // For pre-pappvoal case, the mPackageName would be null.
+ if (mPackageName != null) {
+ packageName = mPackageName;
+ } else if (mPreapprovalRequested.get() && mPreapprovalDetails != null) {
+ packageName = mPreapprovalDetails.getPackageName();
+ } else {
+ packageName = null;
+ }
hasDeviceAdminReceiver = mHasDeviceAdminReceiver;
}
- final boolean forcePermissionPrompt =
+ // For the below cases, force user action prompt
+ // 1. installFlags includes INSTALL_FORCE_PERMISSION_PROMPT
+ // 2. params.requireUserAction is USER_ACTION_REQUIRED
+ final boolean forceUserActionPrompt =
(params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0
|| params.requireUserAction == SessionParams.USER_ACTION_REQUIRED;
- if (forcePermissionPrompt) {
- return USER_ACTION_REQUIRED;
- }
+ final int userActionNotTypicallyNeededResponse = forceUserActionPrompt
+ ? USER_ACTION_REQUIRED
+ : USER_ACTION_NOT_NEEDED;
+
// It is safe to access mInstallerUid and mInstallSource without lock
// because they are immutable after sealing.
final Computer snapshot = mPm.snapshotComputer();
@@ -956,7 +981,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|| isInstallerDeviceOwnerOrAffiliatedProfileOwner();
if (noUserActionNecessary) {
- return USER_ACTION_NOT_NEEDED;
+ return userActionNotTypicallyNeededResponse;
}
if (isUpdateOwnershipEnforcementEnabled
@@ -969,7 +994,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
if (isPermissionGranted) {
- return USER_ACTION_NOT_NEEDED;
+ return userActionNotTypicallyNeededResponse;
}
if (snapshot.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index db47306ad58e..f2b62eaf25f8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1607,7 +1607,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
(i, pm) -> new SharedLibrariesImpl(pm, i),
(i, pm) -> new CrossProfileIntentFilterHelper(i.getSettings(),
i.getUserManagerService(), i.getLock(), i.getUserManagerInternal(),
- context));
+ context),
+ (i, pm) -> new UpdateOwnershipHelper());
if (Build.VERSION.SDK_INT <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
index 13549f536c9f..51840e70ed26 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
@@ -144,6 +144,7 @@ public class PackageManagerServiceInjector {
private final Singleton<IBackupManager> mIBackupManager;
private final Singleton<SharedLibrariesImpl> mSharedLibrariesProducer;
private final Singleton<CrossProfileIntentFilterHelper> mCrossProfileIntentFilterHelperProducer;
+ private final Singleton<UpdateOwnershipHelper> mUpdateOwnershipHelperProducer;
PackageManagerServiceInjector(Context context, PackageManagerTracedLock lock,
Installer installer, Object installLock, PackageAbiHelper abiHelper,
@@ -183,7 +184,8 @@ public class PackageManagerServiceInjector {
Producer<BackgroundDexOptService> backgroundDexOptService,
Producer<IBackupManager> iBackupManager,
Producer<SharedLibrariesImpl> sharedLibrariesProducer,
- Producer<CrossProfileIntentFilterHelper> crossProfileIntentFilterHelperProducer) {
+ Producer<CrossProfileIntentFilterHelper> crossProfileIntentFilterHelperProducer,
+ Producer<UpdateOwnershipHelper> updateOwnershipHelperProducer) {
mContext = context;
mLock = lock;
mInstaller = installer;
@@ -238,6 +240,7 @@ public class PackageManagerServiceInjector {
mSharedLibrariesProducer = new Singleton<>(sharedLibrariesProducer);
mCrossProfileIntentFilterHelperProducer = new Singleton<>(
crossProfileIntentFilterHelperProducer);
+ mUpdateOwnershipHelperProducer = new Singleton<>(updateOwnershipHelperProducer);
}
/**
@@ -423,6 +426,11 @@ public class PackageManagerServiceInjector {
return mSharedLibrariesProducer.get(this, mPackageManager);
}
+ public UpdateOwnershipHelper getUpdateOwnershipHelper() {
+ return mUpdateOwnershipHelperProducer.get(this, mPackageManager);
+ }
+
+
/** Provides an abstraction to static access to system state. */
public interface SystemWrapper {
void disablePackageCaches();
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 10673c6f2dd2..59314a26ab97 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -312,6 +312,7 @@ final class RemovePackageHelper {
synchronized (mPm.mLock) {
mPm.mDomainVerificationManager.clearPackage(deletedPs.getPackageName());
mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
+ mPm.mInjector.getUpdateOwnershipHelper().removeUpdateOwnerDenyList(packageName);
final Computer snapshot = mPm.snapshotComputer();
mPm.mAppsFilter.removePackage(snapshot,
snapshot.getPackageStateInternal(packageName));
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index a622d0743bbb..bb6e11dcf8d4 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -90,7 +90,7 @@
]
}
],
- "presubmit-large": [
+ "postsubmit": [
{
"name": "CtsContentTestCases",
"options": [
@@ -104,9 +104,7 @@
"include-filter": "android.content.pm.cts"
}
]
- }
- ],
- "postsubmit": [
+ },
{
"name": "CtsPermissionTestCases",
"options": [
diff --git a/services/core/java/com/android/server/pm/UpdateOwnershipHelper.java b/services/core/java/com/android/server/pm/UpdateOwnershipHelper.java
new file mode 100644
index 000000000000..43752f31a1a2
--- /dev/null
+++ b/services/core/java/com/android/server/pm/UpdateOwnershipHelper.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST;
+
+import static com.android.server.pm.PackageManagerService.TAG;
+
+import android.Manifest;
+import android.app.ResourcesManager;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedUsesPermission;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.List;
+
+/** Helper class for managing update ownership and optouts for the feature. */
+public class UpdateOwnershipHelper {
+
+ // Called out in PackageManager.PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST docs
+ private static final int MAX_DENYLIST_SIZE = 500;
+ private static final String TAG_OWNERSHIP_OPT_OUT = "deny-ownership";
+ private final ArrayMap<String, ArraySet<String>> mUpdateOwnerOptOutsToOwners =
+ new ArrayMap<>(200);
+
+ private final Object mLock = new Object();
+
+ private static boolean hasValidOwnershipDenyList(PackageSetting pkgSetting) {
+ AndroidPackage pkg = pkgSetting.getPkg();
+ // we're checking for uses-permission for these priv permissions instead of grant as we're
+ // only considering system apps to begin with, so presumed to be granted.
+ return pkg != null
+ && (pkgSetting.isSystem() || pkgSetting.isUpdatedSystemApp())
+ && pkg.getProperties().containsKey(PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST)
+ && usesAnyPermission(pkg,
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.INSTALL_PACKAGE_UPDATES);
+ }
+
+
+ /** Returns true if a package setting declares that it uses a permission */
+ private static boolean usesAnyPermission(AndroidPackage pkgSetting, String... permissions) {
+ List<ParsedUsesPermission> usesPermissions = pkgSetting.getUsesPermissions();
+ for (int i = 0; i < usesPermissions.size(); i++) {
+ for (int j = 0; j < permissions.length; j++) {
+ if (permissions[j].equals(usesPermissions.get(i).getName())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Reads the update owner deny list from a {@link PackageSetting} and returns the set of
+ * packages it contains or {@code null} if it cannot be read.
+ */
+ public ArraySet<String> readUpdateOwnerDenyList(PackageSetting pkgSetting) {
+ if (!hasValidOwnershipDenyList(pkgSetting)) {
+ return null;
+ }
+ AndroidPackage pkg = pkgSetting.getPkg();
+ if (pkg == null) {
+ return null;
+ }
+ ArraySet<String> ownershipDenyList = new ArraySet<>(MAX_DENYLIST_SIZE);
+ try {
+ int resId = pkg.getProperties().get(PROPERTY_LEGACY_UPDATE_OWNERSHIP_DENYLIST)
+ .getResourceId();
+ ApplicationInfo appInfo = AndroidPackageUtils.generateAppInfoWithoutState(pkg);
+ Resources resources = ResourcesManager.getInstance().getResources(
+ null, appInfo.sourceDir, appInfo.splitSourceDirs, appInfo.resourceDirs,
+ appInfo.overlayPaths, appInfo.sharedLibraryFiles, null, Configuration.EMPTY,
+ null, null, null);
+ try (XmlResourceParser parser = resources.getXml(resId)) {
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ if (parser.next() == XmlResourceParser.START_TAG) {
+ if (TAG_OWNERSHIP_OPT_OUT.equals(parser.getName())) {
+ parser.next();
+ String packageName = parser.getText();
+ if (packageName != null && !packageName.isBlank()) {
+ ownershipDenyList.add(packageName);
+ if (ownershipDenyList.size() > MAX_DENYLIST_SIZE) {
+ Slog.w(TAG, "Deny list defined by " + pkg.getPackageName()
+ + " was trucated to maximum size of "
+ + MAX_DENYLIST_SIZE);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to parse update owner list for " + pkgSetting.getPackageName(), e);
+ return null;
+ }
+ return ownershipDenyList;
+ }
+
+ /**
+ * Begins tracking the contents of a deny list and the owner of that deny list for use in calls
+ * to {@link #isUpdateOwnershipDenylisted(String)} and
+ * {@link #isUpdateOwnershipDenyListProvider(String)}.
+ *
+ * @param listOwner the packageName of the package that owns the deny list.
+ * @param listContents the list of packageNames that are on the deny list.
+ */
+ public void addToUpdateOwnerDenyList(String listOwner, ArraySet<String> listContents) {
+ synchronized (mLock) {
+ for (int i = 0; i < listContents.size(); i++) {
+ String packageName = listContents.valueAt(i);
+ ArraySet<String> priorDenyListOwners = mUpdateOwnerOptOutsToOwners.putIfAbsent(
+ packageName, new ArraySet<>(new String[]{listOwner}));
+ if (priorDenyListOwners != null) {
+ priorDenyListOwners.add(listOwner);
+ }
+ }
+ }
+ }
+
+ /**
+ * Stop tracking the contents of a deny list owned by the provided owner of the deny list.
+ * @param listOwner the packageName of the package that owns the deny list.
+ */
+ public void removeUpdateOwnerDenyList(String listOwner) {
+ synchronized (mLock) {
+ for (int i = mUpdateOwnerOptOutsToOwners.size() - 1; i >= 0; i--) {
+ ArraySet<String> packageDenyListContributors =
+ mUpdateOwnerOptOutsToOwners.get(mUpdateOwnerOptOutsToOwners.keyAt(i));
+ if (packageDenyListContributors.remove(listOwner)
+ && packageDenyListContributors.isEmpty()) {
+ mUpdateOwnerOptOutsToOwners.removeAt(i);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if the provided package name is on a valid update ownership deny list.
+ */
+ public boolean isUpdateOwnershipDenylisted(String packageName) {
+ return mUpdateOwnerOptOutsToOwners.containsKey(packageName);
+ }
+
+ /**
+ * Returns {@code true} if the provided package name defines a valid update ownership deny list.
+ */
+ public boolean isUpdateOwnershipDenyListProvider(String packageName) {
+ if (packageName == null) {
+ return false;
+ }
+ synchronized (mLock) {
+ for (int i = mUpdateOwnerOptOutsToOwners.size() - 1; i >= 0; i--) {
+ if (mUpdateOwnerOptOutsToOwners.valueAt(i).contains(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index f0bf1ea80570..d0c346a63889 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -334,7 +334,10 @@ public class ArtStatsLogUtils {
ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_UNKNOWN),
cancellationReason,
durationMs,
- 0); // deprecated, used to be durationIncludingSleepMs
+ 0, // deprecated, used to be durationIncludingSleepMs
+ 0, // optimizedPackagesCount
+ 0, // packagesDependingOnBootClasspathCount
+ 0); // totalPackagesCount
}
}
}
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 8c9ecb2e5046..189eb205d927 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
@@ -1532,7 +1532,6 @@ public class ParsingPackageUtils {
private static ParseResult<ParsingPackage> parseUsesSdk(ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
throws IOException, XmlPullParserException {
- String pkgName = (pkg != null) ? pkg.getPackageName() : "<unknown>";
if (SDK_VERSION > 0) {
final boolean isApkInApex = (flags & PARSE_APK_IN_APEX) != 0;
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
@@ -1582,7 +1581,7 @@ public class ParsingPackageUtils {
ParseResult<Integer> targetSdkVersionResult = FrameworkParsingPackageUtils
.computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input,
- isApkInApex, pkgName);
+ isApkInApex);
if (targetSdkVersionResult.isError()) {
return input.error(targetSdkVersionResult);
}
@@ -1596,8 +1595,7 @@ public class ParsingPackageUtils {
}
ParseResult<Integer> minSdkVersionResult = FrameworkParsingPackageUtils
- .computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES,
- input, pkgName);
+ .computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, input);
if (minSdkVersionResult.isError()) {
return input.error(minSdkVersionResult);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5fc557a06df9..473573afd2c5 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -702,8 +702,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
finishKeyguardDrawn();
break;
case MSG_WINDOW_MANAGER_DRAWN_COMPLETE:
- if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mWindowManagerDrawComplete");
- finishWindowsDrawn(msg.arg1);
+ final int displayId = msg.arg1;
+ if (DEBUG_WAKEUP) Slog.w(TAG, "All windows drawn on display " + displayId);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER,
+ TRACE_WAIT_FOR_ALL_WINDOWS_DRAWN_METHOD, displayId /* cookie */);
+ finishWindowsDrawn(displayId);
break;
case MSG_HIDE_BOOT_MESSAGE:
handleHideBootMessage();
@@ -3570,19 +3573,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
- public void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition) {
- if (mKeyguardDelegate != null && waitAppTransition) {
+ public void onKeyguardOccludedChangedLw(boolean occluded) {
+ if (mKeyguardDelegate != null) {
mPendingKeyguardOccluded = occluded;
mKeyguardOccludedChanged = true;
- } else {
- setKeyguardOccludedLw(occluded);
}
}
@Override
public int applyKeyguardOcclusionChange() {
if (DEBUG_KEYGUARD) Slog.d(TAG, "transition/occluded commit occluded="
- + mPendingKeyguardOccluded);
+ + mPendingKeyguardOccluded + " changed=" + mKeyguardOccludedChanged);
// TODO(b/276433230): Explicitly save before/after for occlude state in each
// Transition so we don't need to update SysUI every time.
@@ -4998,15 +4999,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// ... eventually calls finishWindowsDrawn which will finalize our screen turn on
// as well as enabling the orientation change logic/sensor.
Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
- TRACE_WAIT_FOR_ALL_WINDOWS_DRAWN_METHOD, /* cookie= */ 0);
- mWindowManagerInternal.waitForAllWindowsDrawn(() -> {
- if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for every display");
- mHandler.sendMessage(mHandler.obtainMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE,
- INVALID_DISPLAY, 0));
-
- Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER,
- TRACE_WAIT_FOR_ALL_WINDOWS_DRAWN_METHOD, /* cookie= */ 0);
- }, WAITING_FOR_DRAWN_TIMEOUT, INVALID_DISPLAY);
+ TRACE_WAIT_FOR_ALL_WINDOWS_DRAWN_METHOD, INVALID_DISPLAY /* cookie */);
+ mWindowManagerInternal.waitForAllWindowsDrawn(mHandler.obtainMessage(
+ MSG_WINDOW_MANAGER_DRAWN_COMPLETE, INVALID_DISPLAY, 0),
+ WAITING_FOR_DRAWN_TIMEOUT, INVALID_DISPLAY);
}
// Called on the DisplayManager's DisplayPowerController thread.
@@ -5086,15 +5082,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mScreenOnListeners.put(displayId, screenOnListener);
Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
- TRACE_WAIT_FOR_ALL_WINDOWS_DRAWN_METHOD, /* cookie= */ 0);
- mWindowManagerInternal.waitForAllWindowsDrawn(() -> {
- if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for display: " + displayId);
- mHandler.sendMessage(mHandler.obtainMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE,
- displayId, 0));
-
- Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER,
- TRACE_WAIT_FOR_ALL_WINDOWS_DRAWN_METHOD, /* cookie= */ 0);
- }, WAITING_FOR_DRAWN_TIMEOUT, displayId);
+ TRACE_WAIT_FOR_ALL_WINDOWS_DRAWN_METHOD, displayId /* cookie */);
+ mWindowManagerInternal.waitForAllWindowsDrawn(mHandler.obtainMessage(
+ MSG_WINDOW_MANAGER_DRAWN_COMPLETE, displayId, 0),
+ WAITING_FOR_DRAWN_TIMEOUT, displayId);
}
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 887f9461bdce..03a7bd3b68b3 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -169,7 +169,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
*
* @param occluded Whether Keyguard is currently occluded or not.
*/
- void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition);
+ void onKeyguardOccludedChangedLw(boolean occluded);
/**
* Commit any queued changes to keyguard occlude status that had been deferred during the
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a53b831d55c1..d82f7a56a830 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -92,6 +92,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
+import android.provider.DeviceConfigInterface;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal;
@@ -128,6 +129,7 @@ import com.android.server.UiThread;
import com.android.server.UserspaceRebootLogger;
import com.android.server.Watchdog;
import com.android.server.am.BatteryStatsService;
+import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
import com.android.server.policy.WindowManagerPolicy;
@@ -323,6 +325,9 @@ public final class PowerManagerService extends SystemService
private final Injector mInjector;
private final PermissionCheckerWrapper mPermissionCheckerWrapper;
private final PowerPropertiesWrapper mPowerPropertiesWrapper;
+ private final DeviceConfigParameterProvider mDeviceConfigProvider;
+
+ private boolean mDisableScreenWakeLocksWhileCached;
private LightsManager mLightsManager;
private BatteryManagerInternal mBatteryManagerInternal;
@@ -1065,6 +1070,10 @@ public final class PowerManagerService extends SystemService
}
};
}
+
+ DeviceConfigParameterProvider createDeviceConfigParameterProvider() {
+ return new DeviceConfigParameterProvider(DeviceConfigInterface.REAL);
+ }
}
/** Interface for checking an app op permission */
@@ -1161,6 +1170,7 @@ public final class PowerManagerService extends SystemService
mInjector.createInattentiveSleepWarningController();
mPermissionCheckerWrapper = mInjector.createPermissionCheckerWrapper();
mPowerPropertiesWrapper = mInjector.createPowerPropertiesWrapper();
+ mDeviceConfigProvider = mInjector.createDeviceConfigParameterProvider();
mPowerGroupWakefulnessChangeListener = new PowerGroupWakefulnessChangeListener();
@@ -1346,6 +1356,14 @@ public final class PowerManagerService extends SystemService
mLightsManager = getLocalService(LightsManager.class);
mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
+ updateDeviceConfigLocked();
+ mDeviceConfigProvider.addOnPropertiesChangedListener(BackgroundThread.getExecutor(),
+ properties -> {
+ synchronized (mLock) {
+ updateDeviceConfigLocked();
+ updateWakeLockDisabledStatesLocked();
+ }
+ });
// Initialize display power management.
mDisplayManagerInternal.initPowerManagement(
@@ -1545,6 +1563,12 @@ public final class PowerManagerService extends SystemService
updatePowerStateLocked();
}
+ @GuardedBy("mLock")
+ private void updateDeviceConfigLocked() {
+ mDisableScreenWakeLocksWhileCached = mDeviceConfigProvider
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ }
+
@RequiresPermission(value = android.Manifest.permission.TURN_SCREEN_ON, conditional = true)
private void acquireWakeLockInternal(IBinder lock, int displayId, int flags, String tag,
String packageName, WorkSource ws, String historyTag, int uid, int pid,
@@ -2760,13 +2784,13 @@ public final class PowerManagerService extends SystemService
/** Get wake lock summary flags that correspond to the given wake lock. */
@SuppressWarnings("deprecation")
private int getWakeLockSummaryFlags(WakeLock wakeLock) {
+ if (wakeLock.mDisabled) {
+ // We only respect this if the wake lock is not disabled.
+ return 0;
+ }
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.PARTIAL_WAKE_LOCK:
- if (!wakeLock.mDisabled) {
- // We only respect this if the wake lock is not disabled.
- return WAKE_LOCK_CPU;
- }
- break;
+ return WAKE_LOCK_CPU;
case PowerManager.FULL_WAKE_LOCK:
return WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
@@ -4151,7 +4175,7 @@ public final class PowerManagerService extends SystemService
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
- == PowerManager.PARTIAL_WAKE_LOCK) {
+ == PowerManager.PARTIAL_WAKE_LOCK || isScreenLock(wakeLock)) {
if (setWakeLockDisabledStateLocked(wakeLock)) {
changed = true;
if (wakeLock.mDisabled) {
@@ -4205,6 +4229,22 @@ public final class PowerManagerService extends SystemService
}
}
return wakeLock.setDisabled(disabled);
+ } else if (mDisableScreenWakeLocksWhileCached && isScreenLock(wakeLock)) {
+ boolean disabled = false;
+ final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
+ final UidState state = wakeLock.mUidState;
+ // Cached inactive processes are never allowed to hold wake locks.
+ if (mConstants.NO_CACHED_WAKE_LOCKS
+ && appid >= Process.FIRST_APPLICATION_UID
+ && !state.mActive
+ && state.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT
+ && state.mProcState >= ActivityManager.PROCESS_STATE_TOP_SLEEPING) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "disabling full wakelock " + wakeLock);
+ }
+ disabled = true;
+ }
+ return wakeLock.setDisabled(disabled);
}
return false;
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 4a57592aa1ae..27329e20bc8d 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -14613,17 +14613,13 @@ public class BatteryStatsImpl extends BatteryStats {
// Inform StatsLog of setBatteryState changes.
private void reportChangesToStatsLog(final int status, final int plugType, final int level) {
- if (!mHaveBatteryLevel) {
- return;
- }
-
- if (mBatteryStatus != status) {
+ if (!mHaveBatteryLevel || mBatteryStatus != status) {
FrameworkStatsLog.write(FrameworkStatsLog.CHARGING_STATE_CHANGED, status);
}
- if (mBatteryPlugType != plugType) {
+ if (!mHaveBatteryLevel || mBatteryPlugType != plugType) {
FrameworkStatsLog.write(FrameworkStatsLog.PLUGGED_STATE_CHANGED, plugType);
}
- if (mBatteryLevel != level) {
+ if (!mHaveBatteryLevel || mBatteryLevel != level) {
FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_LEVEL_CHANGED, level);
}
}
diff --git a/services/core/java/com/android/server/utils/AlarmQueue.java b/services/core/java/com/android/server/utils/AlarmQueue.java
index 09ba19508476..83605ae09e97 100644
--- a/services/core/java/com/android/server/utils/AlarmQueue.java
+++ b/services/core/java/com/android/server/utils/AlarmQueue.java
@@ -151,6 +151,10 @@ public abstract class AlarmQueue<K> implements AlarmManager.OnAlarmListener {
@GuardedBy("mLock")
@ElapsedRealtimeLong
private long mTriggerTimeElapsed = NOT_SCHEDULED;
+ /** The last time an alarm went off (ie. the last time {@link #onAlarm()} was called}). */
+ @GuardedBy("mLock")
+ @ElapsedRealtimeLong
+ private long mLastFireTimeElapsed;
/**
* @param alarmTag The tag to use when scheduling the alarm with AlarmManager.
@@ -284,7 +288,7 @@ public abstract class AlarmQueue<K> implements AlarmManager.OnAlarmListener {
/** Sets an alarm with {@link AlarmManager} for the earliest alarm in the queue after now. */
@GuardedBy("mLock")
private void setNextAlarmLocked() {
- setNextAlarmLocked(mInjector.getElapsedRealtime());
+ setNextAlarmLocked(mLastFireTimeElapsed + mMinTimeBetweenAlarmsMs);
}
/**
@@ -334,6 +338,7 @@ public abstract class AlarmQueue<K> implements AlarmManager.OnAlarmListener {
final ArraySet<K> expired = new ArraySet<>();
synchronized (mLock) {
final long nowElapsed = mInjector.getElapsedRealtime();
+ mLastFireTimeElapsed = nowElapsed;
while (mAlarmPriorityQueue.size() > 0) {
final Pair<K, Long> alarm = mAlarmPriorityQueue.peek();
if (alarm.second <= nowElapsed) {
diff --git a/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java b/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java
index 9bf046cdaf21..3b930f78e667 100644
--- a/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java
+++ b/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java
@@ -28,6 +28,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.ArrayMap;
+import android.util.IndentingPrintWriter;
import android.util.LongArrayQueue;
import android.util.Slog;
import android.util.TimeUtils;
@@ -36,7 +37,6 @@ import android.util.quota.CountQuotaTrackerProto;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
import java.util.function.Consumer;
import java.util.function.Function;
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index b296ef2a1443..1ff01a6c70bf 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -1049,7 +1049,11 @@ public class VrManagerService extends SystemService
for (ComponentName c : possibleServices) {
if (Objects.equals(c.getPackageName(), pkg)) {
- nm.setNotificationListenerAccessGrantedForUser(c, userId, true);
+ try {
+ nm.setNotificationListenerAccessGrantedForUser(c, userId, true);
+ } catch (Exception e) {
+ Slog.w(TAG, "Could not grant NLS access to package " + pkg, e);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 5af73726ddde..7a940ffc2913 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -3095,7 +3095,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
if (which == FLAG_SYSTEM && systemIsStatic && systemIsBoth) {
Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
+ " updating system wallpaper");
- migrateStaticSystemToLockWallpaperLocked(userId);
+ if (!migrateStaticSystemToLockWallpaperLocked(userId)
+ && !isLockscreenLiveWallpaperEnabled()) {
+ which |= FLAG_LOCK;
+ }
}
wallpaper = getWallpaperSafeLocked(userId, which);
@@ -3123,13 +3126,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
- private void migrateStaticSystemToLockWallpaperLocked(int userId) {
+ private boolean migrateStaticSystemToLockWallpaperLocked(int userId) {
WallpaperData sysWP = mWallpaperMap.get(userId);
if (sysWP == null) {
if (DEBUG) {
Slog.i(TAG, "No system wallpaper? Not tracking for lock-only");
}
- return;
+ return true;
}
// We know a-priori that there is no lock-only wallpaper currently
@@ -3150,11 +3153,13 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
SELinux.restorecon(lockWP.wallpaperFile);
mLastLockWallpaper = lockWP;
}
+ return true;
} catch (ErrnoException e) {
- Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage());
+ // can happen when migrating default wallpaper (which is not stored in wallpaperFile)
+ Slog.w(TAG, "Couldn't migrate system wallpaper: " + e.getMessage());
lockWP.wallpaperFile.delete();
lockWP.cropFile.delete();
- return;
+ return false;
}
}
@@ -3355,7 +3360,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
// therefore it's a shared system+lock image that we need to migrate.
Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
+ "updating system wallpaper");
- migrateStaticSystemToLockWallpaperLocked(userId);
+ if (!migrateStaticSystemToLockWallpaperLocked(userId)) {
+ which |= FLAG_LOCK;
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index c5f63ced989c..a6d5c19395b0 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -285,9 +285,9 @@ class ActivityMetricsLogger {
final LaunchingState mLaunchingState;
/** The type can be cold (new process), warm (new activity), or hot (bring to front). */
- final int mTransitionType;
+ int mTransitionType;
/** Whether the process was already running when the transition started. */
- final boolean mProcessRunning;
+ boolean mProcessRunning;
/** whether the process of the launching activity didn't have any active activity. */
final boolean mProcessSwitch;
/** The process state of the launching activity prior to the launch */
@@ -972,6 +972,19 @@ class ActivityMetricsLogger {
// App isn't attached to record yet, so match with info.
if (info.mLastLaunchedActivity.info.applicationInfo == appInfo) {
info.mBindApplicationDelayMs = info.calculateCurrentDelay();
+ if (info.mProcessRunning) {
+ // It was HOT/WARM launch, but the process was died somehow right after the
+ // launch request.
+ info.mProcessRunning = false;
+ info.mTransitionType = TYPE_TRANSITION_COLD_LAUNCH;
+ final String msg = "Process " + info.mLastLaunchedActivity.info.processName
+ + " restarted";
+ Slog.i(TAG, msg);
+ if (info.mLaunchingState.mTraceName != null) {
+ Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, msg + "#"
+ + LaunchingState.sTraceSeqId);
+ }
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 788bfbcd65c9..f6fa51e3018a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4516,7 +4516,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mTransitionChangeFlags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
}
// Post cleanup after the visibility and animation are transferred.
- fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow);
+ fromActivity.postWindowRemoveStartingWindowCleanup();
fromActivity.mVisibleSetFromTransferredStartingWindow = false;
mWmService.updateFocusedWindowLocked(
@@ -7430,27 +7430,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- void postWindowRemoveStartingWindowCleanup(WindowState win) {
- // TODO: Something smells about the code below...Is there a better way?
- if (mStartingWindow == win) {
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Notify removed startingWindow %s", win);
- removeStartingWindow();
- } else if (mChildren.size() == 0) {
- // If this is the last window and we had requested a starting transition window,
- // well there is no point now.
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Nulling last startingData");
- mStartingData = null;
- if (mVisibleSetFromTransferredStartingWindow) {
- // We set the visible state to true for the token from a transferred starting
- // window. We now reset it back to false since the starting window was the last
- // window in the token.
- setVisible(false);
- }
- } else if (mChildren.size() == 1 && mStartingSurface != null && !isRelaunching()) {
- // If this is the last window except for a starting transition window,
- // we need to get rid of the starting transition.
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Last window, removing starting window %s", win);
- removeStartingWindow();
+ void postWindowRemoveStartingWindowCleanup() {
+ if (mChildren.size() == 0 && mVisibleSetFromTransferredStartingWindow) {
+ // We set the visible state to true for the token from a transferred starting
+ // window. We now reset it back to false since the starting window was the last
+ // window in the token.
+ setVisible(false);
}
}
@@ -7981,6 +7966,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mLastReportedConfiguration.getMergedConfiguration())) {
ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */,
false /* ignoreVisibility */, true /* isRequestedOrientationChanged */);
+ if (mTransitionController.inPlayingTransition(this)) {
+ mTransitionController.mValidateActivityCompat.add(this);
+ }
}
mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 0171c200b56c..b34ae1930048 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2186,7 +2186,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
* Processes the activities to be stopped or destroyed. This should be called when the resumed
* activities are idle or drawn.
*/
- private void processStoppingAndFinishingActivities(ActivityRecord launchedActivity,
+ void processStoppingAndFinishingActivities(ActivityRecord launchedActivity,
boolean processPausingActivities, String reason) {
// Stop any activities that are scheduled to do so but have been waiting for the transition
// animation to finish.
@@ -2194,7 +2194,10 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
ArrayList<ActivityRecord> readyToStopActivities = null;
for (int i = 0; i < mStoppingActivities.size(); i++) {
final ActivityRecord s = mStoppingActivities.get(i);
- final boolean animating = s.isInTransition();
+ // Activity in a force hidden task should not be counted as animating, i.e., we want to
+ // send onStop before any configuration change when removing pip transition is ongoing.
+ final boolean animating = s.isInTransition()
+ && s.getTask() != null && !s.getTask().isForceHidden();
displaySwapping |= s.isDisplaySleepingAndSwapping();
ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b "
+ "finishing=%s", s, s.nowVisible, animating, s.finishing);
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index b216578262b4..188f4d0b8ced 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -280,7 +280,7 @@ public class BackgroundActivityStartController {
// visible window.
if (Process.isSdkSandboxUid(realCallingUid)) {
int realCallingSdkSandboxUidToAppUid =
- Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid));
+ Process.getAppUidForSdkSandboxUid(realCallingUid);
if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
return logStartAllowedAndReturnCode(BAL_ALLOW_SDK_SANDBOX,
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 89f044bdd163..d7667d8ce7a8 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -215,8 +215,7 @@ class Dimmer {
return mDimState;
}
- private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer,
- float alpha, int blurRadius) {
+ private void dim(WindowContainer container, int relativeLayer, float alpha, int blurRadius) {
final DimState d = getDimState(container);
if (d == null) {
@@ -226,6 +225,7 @@ class Dimmer {
// The dim method is called from WindowState.prepareSurfaces(), which is always called
// in the correct Z from lowest Z to highest. This ensures that the dim layer is always
// relative to the highest Z layer with a dim.
+ SurfaceControl.Transaction t = mHost.getPendingTransaction();
t.setRelativeLayer(d.mDimLayer, container.getSurfaceControl(), relativeLayer);
t.setAlpha(d.mDimLayer, alpha);
t.setBackgroundBlurRadius(d.mDimLayer, blurRadius);
@@ -238,26 +238,23 @@ class Dimmer {
* for each call to {@link WindowContainer#prepareSurfaces} the Dim state will be reset
* and the child should call dimAbove again to request the Dim to continue.
*
- * @param t A transaction in which to apply the Dim.
* @param container The container which to dim above. Should be a child of our host.
* @param alpha The alpha at which to Dim.
*/
- void dimAbove(SurfaceControl.Transaction t, WindowContainer container, float alpha) {
- dim(t, container, 1, alpha, 0);
+ void dimAbove(WindowContainer container, float alpha) {
+ dim(container, 1, alpha, 0);
}
/**
* Like {@link #dimAbove} but places the dim below the given container.
*
- * @param t A transaction in which to apply the Dim.
* @param container The container which to dim below. Should be a child of our host.
* @param alpha The alpha at which to Dim.
* @param blurRadius The amount of blur added to the Dim.
*/
- void dimBelow(SurfaceControl.Transaction t, WindowContainer container, float alpha,
- int blurRadius) {
- dim(t, container, -1, alpha, blurRadius);
+ void dimBelow(WindowContainer container, float alpha, int blurRadius) {
+ dim(container, -1, alpha, blurRadius);
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 3f1a077740cc..4c0c4b5add44 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -176,7 +176,7 @@ public class DisplayPolicy {
// TODO(b/266197298): Remove this by a more general protocol from the insets providers.
private static final boolean USE_CACHED_INSETS_FOR_DISPLAY_SWITCH =
- SystemProperties.getBoolean("persist.wm.debug.cached_insets_switch", false);
+ SystemProperties.getBoolean("persist.wm.debug.cached_insets_switch", true);
private final WindowManagerService mService;
private final Context mContext;
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 20936dcf5b42..d03388a8455e 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -419,13 +419,17 @@ class KeyguardController {
return;
}
- final boolean waitAppTransition = isKeyguardLocked(displayId);
- mWindowManager.mPolicy.onKeyguardOccludedChangedLw(isDisplayOccluded(DEFAULT_DISPLAY),
- waitAppTransition);
- if (waitAppTransition) {
- mService.deferWindowLayout();
- try {
- if (isDisplayOccluded(DEFAULT_DISPLAY)) {
+ final TransitionController tc = mRootWindowContainer.mTransitionController;
+
+ final boolean occluded = isDisplayOccluded(displayId);
+ final boolean performTransition = isKeyguardLocked(displayId);
+ final boolean executeTransition = performTransition && !tc.isCollecting();
+
+ mWindowManager.mPolicy.onKeyguardOccludedChangedLw(occluded);
+ mService.deferWindowLayout();
+ try {
+ if (isKeyguardLocked(displayId)) {
+ if (occluded) {
mRootWindowContainer.getDefaultDisplay().requestTransitionAndLegacyPrepare(
TRANSIT_KEYGUARD_OCCLUDE,
TRANSIT_FLAG_KEYGUARD_OCCLUDING,
@@ -435,11 +439,19 @@ class KeyguardController {
TRANSIT_KEYGUARD_UNOCCLUDE,
TRANSIT_FLAG_KEYGUARD_UNOCCLUDING);
}
- updateKeyguardSleepToken(DEFAULT_DISPLAY);
+ } else {
+ if (tc.inTransition()) {
+ tc.mStateValidators.add(mWindowManager.mPolicy::applyKeyguardOcclusionChange);
+ } else {
+ mWindowManager.mPolicy.applyKeyguardOcclusionChange();
+ }
+ }
+ updateKeyguardSleepToken(displayId);
+ if (performTransition && executeTransition) {
mWindowManager.executeAppTransition();
- } finally {
- mService.continueWindowLayout();
}
+ } finally {
+ mService.continueWindowLayout();
}
}
@@ -486,6 +498,9 @@ class KeyguardController {
}
}
+ /**
+ * @return true if Keyguard is occluded or the device is dreaming.
+ */
boolean isDisplayOccluded(int displayId) {
return getDisplayState(displayId).mOccluded;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3d4df9d262de..9a0e47de7873 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1058,8 +1058,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
displayHasContent = true;
} else if (displayContent != null &&
(!mObscureApplicationContentOnSecondaryDisplays
+ || displayContent.isKeyguardAlwaysUnlocked()
|| (obscured && w.mAttrs.type == TYPE_KEYGUARD_DIALOG))) {
- // Allow full screen keyguard presentation dialogs to be seen.
+ // Allow full screen keyguard presentation dialogs to be seen, or simply ignore the
+ // keyguard if this display is always unlocked.
displayHasContent = true;
}
if ((w.mAttrs.privateFlags & PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE) != 0) {
@@ -3206,6 +3208,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
+ "not idle", rootTask.getRootTaskId(), resumedActivity);
return false;
}
+ if (mTransitionController.isTransientLaunch(resumedActivity)) {
+ // Not idle if the transient transition animation is running.
+ return false;
+ }
}
// End power mode launch when idle.
mService.endLaunchPowerMode(ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY);
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 586077658a26..c914fa10687f 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -48,6 +48,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
import android.view.RemoteAnimationAdapter;
+import android.window.RemoteTransition;
import android.window.WindowContainerToken;
import com.android.internal.annotations.VisibleForTesting;
@@ -385,6 +386,18 @@ public class SafeActivityOptions {
throw new SecurityException(msg);
}
+ // Check permission for remote transitions
+ final RemoteTransition transition = options.getRemoteTransition();
+ if (transition != null && supervisor.mService.checkPermission(
+ CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid)
+ != PERMISSION_GRANTED) {
+ final String msg = "Permission Denial: starting " + getIntentString(intent)
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ") with remoteTransition";
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
// If launched from bubble is specified, then ensure that the caller is system or sysui.
if (options.getLaunchedFromBubble() && !isSystemOrSystemUI(callingPid, callingUid)) {
final String msg = "Permission Denial: starting " + getIntentString(intent)
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 5f2d3ca8175b..65c5c9b35ab7 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -27,6 +27,7 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
+import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -711,6 +712,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
mFlags |= WindowManager.TRANSIT_FLAG_INVISIBLE;
return;
}
+ // Activity doesn't need to capture snapshot if the starting window has associated to task.
+ if (wc.asActivityRecord() != null) {
+ final ActivityRecord activityRecord = wc.asActivityRecord();
+ if (activityRecord.mStartingData != null
+ && activityRecord.mStartingData.mAssociatedTask != null) {
+ return;
+ }
+ }
if (mContainerFreezer == null) {
mContainerFreezer = new ScreenshotFreezer();
@@ -1093,6 +1102,16 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
final Task task = ar.getTask();
if (task == null) continue;
boolean visibleAtTransitionEnd = mVisibleAtTransitionEndTokens.contains(ar);
+ // visibleAtTransitionEnd is used to guard against pre-maturely committing
+ // invisible on a window which is actually hidden by a later transition and not this
+ // one. However, for a transient launch, we can't use this mechanism because the
+ // visibility is determined at finish. Instead, use a different heuristic: don't
+ // commit invisible if the window is already in a later transition. That later
+ // transition will then handle the commit.
+ if (isTransientLaunch(ar) && !ar.isVisibleRequested()
+ && mController.inCollectingTransition(ar)) {
+ visibleAtTransitionEnd = true;
+ }
// We need both the expected visibility AND current requested-visibility to be
// false. If it is expected-visible but not currently visible, it means that
// another animation is queued-up to animate this to invisibility, so we can't
@@ -2649,7 +2668,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
}
private void validateKeyguardOcclusion() {
- if ((mFlags & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0) {
+ if ((mFlags & KEYGUARD_VISIBILITY_TRANSIT_FLAGS) != 0) {
mController.mStateValidators.add(
mController.mAtm.mWindowManager.mPolicy::applyKeyguardOcclusionChange);
}
@@ -2666,7 +2685,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
mController.mStateValidators.add(() -> {
for (int i = mTargets.size() - 1; i >= 0; --i) {
final ChangeInfo change = mTargets.get(i);
- if (!change.mContainer.isVisibleRequested()) continue;
+ if (!change.mContainer.isVisibleRequested()
+ || change.mContainer.mSurfaceControl == null) {
+ continue;
+ }
Slog.e(TAG, "Force show for visible " + change.mContainer
+ " which may be hidden by transition unexpectedly");
change.mContainer.getSyncTransaction().show(change.mContainer.mSurfaceControl);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index a539a4893d4f..b05c6b4839e5 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -30,6 +30,7 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IApplicationThread;
import android.app.WindowConfiguration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
@@ -141,6 +142,14 @@ class TransitionController {
final ArrayList<ActivityRecord> mValidateCommitVis = new ArrayList<>();
/**
+ * List of activity-level participants. ActivityRecord is not expected to change independently,
+ * however, recent compatibility logic can now cause this at arbitrary times determined by
+ * client code. If it happens during an animation, the surface can be left at the wrong spot.
+ * TODO(b/290237710) remove when compat logic is moved.
+ */
+ final ArrayList<ActivityRecord> mValidateActivityCompat = new ArrayList<>();
+
+ /**
* Currently playing transitions (in the order they were started). When finished, records are
* removed from this list.
*/
@@ -905,6 +914,14 @@ class TransitionController {
}
}
mValidateCommitVis.clear();
+ for (int i = 0; i < mValidateActivityCompat.size(); ++i) {
+ ActivityRecord ar = mValidateActivityCompat.get(i);
+ if (ar.getSurfaceControl() == null) continue;
+ final Point tmpPos = new Point();
+ ar.getRelativePosition(tmpPos);
+ ar.getSyncTransaction().setPosition(ar.getSurfaceControl(), tmpPos.x, tmpPos.y);
+ }
+ mValidateActivityCompat.clear();
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 9e7df004806b..805e7ffe7d76 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -30,6 +30,7 @@ import android.graphics.Region;
import android.hardware.display.DisplayManagerInternal;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Message;
import android.util.Pair;
import android.view.ContentRecordingSession;
import android.view.Display;
@@ -515,12 +516,13 @@ public abstract class WindowManagerInternal {
* Invalidate all visible windows on a given display, and report back on the callback when all
* windows have redrawn.
*
- * @param callback reporting callback to be called when all windows have redrawn.
+ * @param message The message will be sent when all windows have redrawn. Note that the message
+ * must be obtained from handler, otherwise it will throw NPE.
* @param timeout calls the callback anyway after the timeout.
* @param displayId waits for the windows on the given display, INVALID_DISPLAY to wait for all
* windows on all displays.
*/
- public abstract void waitForAllWindowsDrawn(Runnable callback, long timeout, int displayId);
+ public abstract void waitForAllWindowsDrawn(Message message, long timeout, int displayId);
/**
* Overrides the display size.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 67572bfcad18..10687001f9a8 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -601,7 +601,7 @@ public class WindowManagerService extends IWindowManager.Stub
* The callbacks to make when the windows all have been drawn for a given
* {@link WindowContainer}.
*/
- final HashMap<WindowContainer, Runnable> mWaitingForDrawnCallbacks = new HashMap<>();
+ final ArrayMap<WindowContainer<?>, Message> mWaitingForDrawnCallbacks = new ArrayMap<>();
/** List of window currently causing non-system overlay windows to be hidden. */
private ArrayList<WindowState> mHidingNonSystemOverlayWindows = new ArrayList<>();
@@ -2020,7 +2020,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (win.mActivityRecord != null) {
- win.mActivityRecord.postWindowRemoveStartingWindowCleanup(win);
+ win.mActivityRecord.postWindowRemoveStartingWindowCleanup();
}
if (win.mAttrs.type == TYPE_WALLPAPER) {
@@ -5368,8 +5368,6 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int CLIENT_FREEZE_TIMEOUT = 30;
public static final int NOTIFY_ACTIVITY_DRAWN = 32;
- public static final int ALL_WINDOWS_DRAWN = 33;
-
public static final int NEW_ANIMATOR_SCALE = 34;
public static final int SHOW_EMULATOR_DISPLAY_OVERLAY = 36;
@@ -5491,7 +5489,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
case WAITING_FOR_DRAWN_TIMEOUT: {
- Runnable callback = null;
+ final Message callback;
final WindowContainer<?> container = (WindowContainer<?>) msg.obj;
synchronized (mGlobalLock) {
ProtoLog.w(WM_ERROR, "Timeout waiting for drawn: undrawn=%s",
@@ -5505,7 +5503,7 @@ public class WindowManagerService extends IWindowManager.Stub
callback = mWaitingForDrawnCallbacks.remove(container);
}
if (callback != null) {
- callback.run();
+ callback.sendToTarget();
}
break;
}
@@ -5529,17 +5527,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
break;
}
- case ALL_WINDOWS_DRAWN: {
- Runnable callback;
- final WindowContainer container = (WindowContainer) msg.obj;
- synchronized (mGlobalLock) {
- callback = mWaitingForDrawnCallbacks.remove(container);
- }
- if (callback != null) {
- callback.run();
- }
- break;
- }
case NEW_ANIMATOR_SCALE: {
float scale = getCurrentAnimatorScale();
ValueAnimator.setDurationScale(scale);
@@ -6097,7 +6084,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (mWaitingForDrawnCallbacks.isEmpty()) {
return;
}
- mWaitingForDrawnCallbacks.forEach((container, callback) -> {
+ for (int i = mWaitingForDrawnCallbacks.size() - 1; i >= 0; i--) {
+ final WindowContainer<?> container = mWaitingForDrawnCallbacks.keyAt(i);
for (int j = container.mWaitingForDrawn.size() - 1; j >= 0; j--) {
final WindowState win = (WindowState) container.mWaitingForDrawn.get(j);
ProtoLog.i(WM_DEBUG_SCREEN_ON,
@@ -6123,9 +6111,9 @@ public class WindowManagerService extends IWindowManager.Stub
if (container.mWaitingForDrawn.isEmpty()) {
ProtoLog.d(WM_DEBUG_SCREEN_ON, "All windows drawn!");
mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, container);
- mH.sendMessage(mH.obtainMessage(H.ALL_WINDOWS_DRAWN, container));
+ mWaitingForDrawnCallbacks.removeAt(i).sendToTarget();
}
- });
+ }
}
private void traceStartWaitingForWindowDrawn(WindowState window) {
@@ -7811,13 +7799,14 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void waitForAllWindowsDrawn(Runnable callback, long timeout, int displayId) {
+ public void waitForAllWindowsDrawn(Message message, long timeout, int displayId) {
+ Objects.requireNonNull(message.getTarget());
final WindowContainer<?> container = displayId == INVALID_DISPLAY
? mRoot : mRoot.getDisplayContent(displayId);
if (container == null) {
// The waiting container doesn't exist, no need to wait to run the callback. Run and
// return;
- callback.run();
+ message.sendToTarget();
return;
}
boolean allWindowsDrawn = false;
@@ -7834,13 +7823,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- mWaitingForDrawnCallbacks.put(container, callback);
+ mWaitingForDrawnCallbacks.put(container, message);
mH.sendNewMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, container, timeout);
checkDrawnWindowsLocked();
}
}
if (allWindowsDrawn) {
- callback.run();
+ message.sendToTarget();
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index a2f7ba499fdf..027ab97693fd 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -559,6 +559,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
if (forceHiddenForPip) {
wc.asTask().setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
+ // When removing pip, make sure that onStop is sent to the app ahead of
+ // onPictureInPictureModeChanged.
+ // See also PinnedStackTests#testStopBeforeMultiWindowCallbacksOnDismiss
+ wc.asTask().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ wc.asTask().mTaskSupervisor.processStoppingAndFinishingActivities(
+ null /* launchedActivity */, false /* processPausingActivities */,
+ "force-stop-on-removing-pip");
}
int containerEffect = applyWindowContainerChange(wc, entry.getValue(),
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index cc9ac76a265e..06978a5338ea 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3389,12 +3389,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// apps won't always be considered as foreground state.
// Exclude private presentations as they can only be shown on private virtual displays and
// shouldn't be the cause of an app be considered foreground.
- if (mAttrs.type >= FIRST_SYSTEM_WINDOW && mAttrs.type != TYPE_TOAST
- && mAttrs.type != TYPE_PRIVATE_PRESENTATION) {
+ // Exclude presentations on virtual displays as they are not actually visible.
+ if (mAttrs.type >= FIRST_SYSTEM_WINDOW
+ && mAttrs.type != TYPE_TOAST
+ && mAttrs.type != TYPE_PRIVATE_PRESENTATION
+ && !(mAttrs.type == TYPE_PRESENTATION && isOnVirtualDisplay())
+ ) {
mWmService.mAtmService.mActiveUids.onNonAppSurfaceVisibilityChanged(mOwnerUid, shown);
}
}
+ private boolean isOnVirtualDisplay() {
+ return getDisplayContent().mDisplay.getType() == Display.TYPE_VIRTUAL;
+ }
+
private void logExclusionRestrictions(int side) {
if (!logsGestureExclusionRestrictions(this)
|| SystemClock.uptimeMillis() < mLastExclusionLogUptimeMillis[side]
@@ -5120,7 +5128,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private void applyDims() {
if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind())
- && isVisibleNow() && !mHidden && mTransitionController.canApplyDim(getTask())) {
+ && mToken.isVisibleRequested() && isVisibleNow() && !mHidden
+ && mTransitionController.canApplyDim(getTask())) {
// Only show the Dimmer when the following is satisfied:
// 1. The window has the flag FLAG_DIM_BEHIND or blur behind is requested
// 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
@@ -5130,7 +5139,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mIsDimming = true;
final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
final int blurRadius = shouldDrawBlurBehind() ? mAttrs.getBlurBehindRadius() : 0;
- getDimmer().dimBelow(getSyncTransaction(), this, dimAmount, blurRadius);
+ getDimmer().dimBelow(this, dimAmount, blurRadius);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index a1199d99f1c3..6747cea80115 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -91,8 +91,6 @@ public final class CredentialManagerService
CredentialManagerService, CredentialManagerServiceImpl> {
private static final String TAG = "CredManSysService";
- private static final String DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API =
- "enable_credential_description_api";
private static final String PERMISSION_DENIED_ERROR = "permission_denied";
private static final String PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR =
"Caller is missing WRITE_SECURE_SETTINGS permission";
@@ -311,14 +309,7 @@ public final class CredentialManagerService
}
public static boolean isCredentialDescriptionApiEnabled() {
- final long origId = Binder.clearCallingIdentity();
- try {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API,
- false);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
+ return true;
}
@SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
index 46c90b4bc731..bafa4a56b28a 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
@@ -126,6 +126,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption
mElementKeys = new HashSet<>(requestOption
.getCredentialRetrievalData()
.getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS));
+ mStatus = Status.PENDING;
}
protected ProviderRegistryGetSession(@NonNull Context context,
@@ -143,6 +144,7 @@ public class ProviderRegistryGetSession extends ProviderSession<CredentialOption
mElementKeys = new HashSet<>(requestOption
.getCredentialRetrievalData()
.getStringArrayList(CredentialOption.SUPPORTED_ELEMENT_KEYS));
+ mStatus = Status.PENDING;
}
private List<Entry> prepareUiCredentialEntries(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 29275efc2ccb..34170fa4c8b5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -241,7 +241,6 @@ import static android.provider.Telephony.Carriers.ENFORCE_KEY;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
import static android.provider.Telephony.Carriers.INVALID_APN_ID;
import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTATION;
-
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -540,6 +539,8 @@ import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
@@ -18809,10 +18810,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
});
}
+ ThreadPoolExecutor calculateHasIncompatibleAccountsExecutor = new ThreadPoolExecutor(
+ 1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
+
@Override
public void calculateHasIncompatibleAccounts() {
+ if (calculateHasIncompatibleAccountsExecutor.getQueue().size() > 1) {
+ return;
+ }
new CalculateHasIncompatibleAccountsTask().executeOnExecutor(
- AsyncTask.THREAD_POOL_EXECUTOR, null);
+ calculateHasIncompatibleAccountsExecutor, null);
}
@Nullable
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index de7dc3b53752..44c58e3e78d7 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -931,7 +931,7 @@ class PermissionService(
isGranted: Boolean
) {
val appOpPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as UidAppOpPolicy
- val appOpName = AppOpsManager.permissionToOp(permissionName)
+ val appOpName = checkNotNull(AppOpsManager.permissionToOp(permissionName))
val mode = if (isGranted) AppOpsManager.MODE_ALLOWED else AppOpsManager.MODE_ERRORED
with(appOpPolicy) { setAppOpMode(packageState.appId, userId, appOpName, mode) }
}
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 35b9bc3b1e06..4a8d73d23904 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -254,12 +254,45 @@ public final class PrintManagerService extends SystemService {
}
final long identity = Binder.clearCallingIdentity();
try {
- return userState.getCustomPrinterIcon(printerId);
+ Icon icon = userState.getCustomPrinterIcon(printerId);
+ return validateIconUserBoundary(icon);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ /**
+ * Validates the custom printer icon to see if it's not in the calling user space.
+ * If the condition is not met, return null. Otherwise, return the original icon.
+ *
+ * @param icon
+ * @return icon (validated)
+ */
+ private Icon validateIconUserBoundary(Icon icon) {
+ // Refer to Icon#getUriString for context. The URI string is invalid for icons of
+ // incompatible types.
+ if (icon != null && (icon.getType() == Icon.TYPE_URI
+ || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
+ String encodedUser = icon.getUri().getEncodedUserInfo();
+
+ // If there is no encoded user, the URI is calling into the calling user space
+ if (encodedUser != null) {
+ int userId = Integer.parseInt(encodedUser);
+ // resolve encoded user
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+
+ synchronized (mLock) {
+ // Only the current group members can get the printer icons.
+ if (resolveCallingProfileParentLocked(resolvedUserId)
+ != getCurrentUserId()) {
+ return null;
+ }
+ }
+ }
+ }
+ return icon;
+ }
+
@Override
public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
if (printJobId == null) {
diff --git a/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt b/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt
index d7d2726c1583..7858b301a6f2 100644
--- a/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt
+++ b/services/tests/PackageManager/packageinstaller/src/com/android/packageinstaller/test/ExportedComponentTest.kt
@@ -43,7 +43,7 @@ class ExportedComponentTest {
assertThat(packageInstallers).isNotEmpty()
packageInstallers.forEach {
- val exported = it.receivers.filter { it.exported }
+ val exported = it.receivers?.filter { it.exported }
assertWithMessage("Receivers should not be exported").that(exported).isEmpty()
}
}
diff --git a/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6 b/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6
index 2da2436d9b16..c2418bec1505 100644
--- a/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6
+++ b/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6
Binary files differ
diff --git a/services/tests/PackageManagerServiceTests/server/res/raw/install_app2_cert5_rotated_cert6 b/services/tests/PackageManagerServiceTests/server/res/raw/install_app2_cert5_rotated_cert6
index 30bb6478d18d..6feebb8c833c 100644
--- a/services/tests/PackageManagerServiceTests/server/res/raw/install_app2_cert5_rotated_cert6
+++ b/services/tests/PackageManagerServiceTests/server/res/raw/install_app2_cert5_rotated_cert6
Binary files differ
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
index dc92376263a6..ba13c992edcf 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
@@ -56,7 +56,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.StatFs;
import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.Postsubmit;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -93,7 +93,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
-@Presubmit
+@Postsubmit
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index 460eb3c20e81..9e371649214c 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -106,8 +106,7 @@ public class PackageParserLegacyCoreTest {
minSdkCodename,
PLATFORM_VERSION,
isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
- input,
- null);
+ input);
if (expectedMinSdk == -1) {
assertTrue(result.isError());
@@ -210,7 +209,7 @@ public class PackageParserLegacyCoreTest {
targetSdkCodename,
isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
input,
- allowUnknownCodenames, null);
+ allowUnknownCodenames);
if (expectedTargetSdk == -1) {
assertTrue(result.isError());
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 931a2bf53b84..3c753326fb7d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -216,6 +216,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
val handler = TestHandler(null)
val defaultAppProvider: DefaultAppProvider = mock()
val backgroundHandler = TestHandler(null)
+ val updateOwnershipHelper: UpdateOwnershipHelper = mock()
}
companion object {
@@ -303,6 +304,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
whenever(mocks.injector.handler) { mocks.handler }
whenever(mocks.injector.defaultAppProvider) { mocks.defaultAppProvider }
whenever(mocks.injector.backgroundHandler) { mocks.backgroundHandler }
+ whenever(mocks.injector.updateOwnershipHelper) { mocks.updateOwnershipHelper }
wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig)
whenever(mocks.systemConfig.availableFeatures).thenReturn(DEFAULT_AVAILABLE_FEATURES_MAP)
whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST)
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index cffd027a58a3..6c392751abe6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -131,7 +131,7 @@ class SharedLibrariesImplTest {
wheneverStatic { HexEncoding.decode(STATIC_LIB_NAME, false) }
.thenReturn(PackageUtils.computeSha256DigestBytes(
mSettings.getPackageLPr(STATIC_LIB_PACKAGE_NAME)
- .pkg.signingDetails.signatures!![0].toByteArray()))
+ .pkg!!.signingDetails.signatures!![0].toByteArray()))
}
@Test
@@ -239,7 +239,7 @@ class SharedLibrariesImplTest {
testPackageSetting.setPkgStateLibraryFiles(listOf())
assertThat(testPackageSetting.usesLibraryFiles).isEmpty()
- mSharedLibrariesImpl.updateSharedLibraries(testPackageSetting.pkg, testPackageSetting,
+ mSharedLibrariesImpl.updateSharedLibraries(testPackageSetting.pkg!!, testPackageSetting,
null /* changingLib */, null /* changingLibSetting */, mExistingPackages)
assertThat(testPackageSetting.usesLibraryFiles).hasSize(1)
@@ -252,7 +252,7 @@ class SharedLibrariesImplTest {
testPackageSetting.setPkgStateLibraryFiles(listOf())
assertThat(testPackageSetting.usesLibraryFiles).isEmpty()
- mSharedLibrariesImpl.updateSharedLibraries(testPackageSetting.pkg, testPackageSetting,
+ mSharedLibrariesImpl.updateSharedLibraries(testPackageSetting.pkg!!, testPackageSetting,
null /* changingLib */, null /* changingLibSetting */, mExistingPackages)
assertThat(testPackageSetting.usesLibraryFiles).hasSize(2)
@@ -266,7 +266,7 @@ class SharedLibrariesImplTest {
testPackageSetting.setPkgStateLibraryFiles(listOf())
assertThat(testPackageSetting.usesLibraryFiles).isEmpty()
- mSharedLibrariesImpl.updateSharedLibraries(testPackageSetting.pkg, testPackageSetting,
+ mSharedLibrariesImpl.updateSharedLibraries(testPackageSetting.pkg!!, testPackageSetting,
null /* changingLib */, null /* changingLibSetting */, mExistingPackages)
assertThat(testPackageSetting.usesLibraryFiles).hasSize(3)
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java
index a3a49d7035d9..f3aa4274b3cd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java
@@ -259,6 +259,29 @@ public class AlarmQueueTest {
}
@Test
+ public void testMinTimeBetweenAlarms_freshAlarm() {
+ final AlarmQueue<String> alarmQueue = createAlarmQueue(true, 5 * MINUTE_IN_MILLIS);
+ final long fixedTimeElapsed = mInjector.getElapsedRealtime();
+
+ InOrder inOrder = inOrder(mAlarmManager);
+
+ final String pkg1 = "com.android.test.1";
+ final String pkg2 = "com.android.test.2";
+ alarmQueue.addAlarm(pkg1, fixedTimeElapsed + MINUTE_IN_MILLIS);
+ inOrder.verify(mAlarmManager, timeout(1000).times(1)).setExact(
+ anyInt(), eq(fixedTimeElapsed + MINUTE_IN_MILLIS), eq(ALARM_TAG), any(), any());
+
+ advanceElapsedClock(MINUTE_IN_MILLIS);
+
+ alarmQueue.onAlarm();
+ // Minimum of 5 minutes between alarms, so the next alarm should be 5 minutes after the
+ // first.
+ alarmQueue.addAlarm(pkg2, fixedTimeElapsed + 2 * MINUTE_IN_MILLIS);
+ inOrder.verify(mAlarmManager, timeout(1000).times(1)).setExact(
+ anyInt(), eq(fixedTimeElapsed + 6 * MINUTE_IN_MILLIS), eq(ALARM_TAG), any(), any());
+ }
+
+ @Test
public void testOnAlarm() {
final AlarmQueue<String> alarmQueue = createAlarmQueue(true, 0);
final long nowElapsed = mInjector.getElapsedRealtime();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
index a4423038a072..437510595ecb 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
@@ -252,6 +252,14 @@ public class BiometricContextProviderTest {
}
@Test
+ public void testSubscribesWithDifferentState() throws RemoteException {
+ final Consumer<OperationContext> nonEmptyConsumer = mock(Consumer.class);
+ mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_AOD);
+ mProvider.subscribe(mOpContext, nonEmptyConsumer);
+ verify(nonEmptyConsumer).accept(same(mOpContext.toAidlContext()));
+ }
+
+ @Test
public void testUnsubscribes() throws RemoteException {
final Consumer<OperationContext> emptyConsumer = mock(Consumer.class);
mProvider.subscribe(mOpContext, emptyConsumer);
@@ -259,6 +267,9 @@ public class BiometricContextProviderTest {
mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_AOD);
+ //reset to unknown to avoid trigger accept when subscribe
+ mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_UNKNOWN);
+
final Consumer<OperationContext> nonEmptyConsumer = mock(Consumer.class);
mProvider.subscribe(mOpContext, nonEmptyConsumer);
mListener.onDisplayStateChanged(AuthenticateOptions.DISPLAY_STATE_LOCKSCREEN);
diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java
index d5ad815d3cdb..b5bf1ea34a46 100644
--- a/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/dreams/DreamControllerTest.java
@@ -16,7 +16,11 @@
package com.android.server.dreams;
+import static android.os.PowerManager.USER_ACTIVITY_EVENT_OTHER;
+import static android.os.PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS;
+
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
@@ -32,7 +36,9 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IPowerManager;
import android.os.IRemoteCallback;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.service.dreams.IDreamService;
@@ -58,6 +64,8 @@ public class DreamControllerTest {
@Mock
private ActivityTaskManager mActivityTaskManager;
+ @Mock
+ private IPowerManager mPowerManager;
@Mock
private IBinder mIBinder;
@@ -67,6 +75,8 @@ public class DreamControllerTest {
@Captor
private ArgumentCaptor<ServiceConnection> mServiceConnectionACaptor;
@Captor
+ private ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor;
+ @Captor
private ArgumentCaptor<IRemoteCallback> mRemoteCallbackCaptor;
private final TestLooper mLooper = new TestLooper();
@@ -90,6 +100,12 @@ public class DreamControllerTest {
when(mContext.getSystemServiceName(ActivityTaskManager.class))
.thenReturn(Context.ACTIVITY_TASK_SERVICE);
+ final PowerManager powerManager = new PowerManager(mContext, mPowerManager, null, null);
+ when(mContext.getSystemService(Context.POWER_SERVICE))
+ .thenReturn(powerManager);
+ when(mContext.getSystemServiceName(PowerManager.class))
+ .thenReturn(Context.POWER_SERVICE);
+
mToken = new Binder();
mDreamName = ComponentName.unflattenFromString("dream");
mOverlayName = ComponentName.unflattenFromString("dream_overlay");
@@ -209,9 +225,51 @@ public class DreamControllerTest {
verify(mIDreamService).detach();
}
+ @Test
+ public void serviceDisconnect_resetsScreenTimeout() throws RemoteException {
+ // Start dream.
+ mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
+ 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
+ ServiceConnection serviceConnection = captureServiceConnection();
+ serviceConnection.onServiceConnected(mDreamName, mIBinder);
+ mLooper.dispatchAll();
+
+ // Dream disconnects unexpectedly.
+ serviceConnection.onServiceDisconnected(mDreamName);
+ mLooper.dispatchAll();
+
+ // Power manager receives user activity signal.
+ verify(mPowerManager).userActivity(/*displayId=*/ anyInt(), /*time=*/ anyLong(),
+ eq(USER_ACTIVITY_EVENT_OTHER),
+ eq(USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS));
+ }
+
+ @Test
+ public void binderDied_resetsScreenTimeout() throws RemoteException {
+ // Start dream.
+ mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/,
+ 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/);
+ captureServiceConnection().onServiceConnected(mDreamName, mIBinder);
+ mLooper.dispatchAll();
+
+ // Dream binder dies.
+ captureDeathRecipient().binderDied();
+ mLooper.dispatchAll();
+
+ // Power manager receives user activity signal.
+ verify(mPowerManager).userActivity(/*displayId=*/ anyInt(), /*time=*/ anyLong(),
+ eq(USER_ACTIVITY_EVENT_OTHER),
+ eq(USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS));
+ }
+
private ServiceConnection captureServiceConnection() {
verify(mContext).bindServiceAsUser(any(), mServiceConnectionACaptor.capture(), anyInt(),
any());
return mServiceConnectionACaptor.getValue();
}
+
+ private IBinder.DeathRecipient captureDeathRecipient() throws RemoteException {
+ verify(mIBinder).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
+ return mDeathRecipientCaptor.getValue();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 5c6164efb3b6..431d3a61de51 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -18,6 +18,8 @@ package com.android.server.power;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
+import static android.app.ActivityManager.PROCESS_STATE_TOP_SLEEPING;
import static android.os.PowerManager.USER_ACTIVITY_EVENT_BUTTON;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
@@ -78,6 +80,7 @@ import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.UserHandle;
import android.os.test.TestLooper;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
import android.sysprop.PowerProperties;
@@ -91,6 +94,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.lights.LightsManager;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.PowerManagerService.BatteryReceiver;
@@ -159,6 +163,7 @@ public class PowerManagerServiceTest {
@Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
@Mock private PowerManagerService.PermissionCheckerWrapper mPermissionCheckerWrapperMock;
@Mock private PowerManagerService.PowerPropertiesWrapper mPowerPropertiesWrapper;
+ @Mock private DeviceConfigParameterProvider mDeviceParameterProvider;
@Rule public TestRule compatChangeRule = new PlatformCompatChangeRule();
@@ -340,6 +345,11 @@ public class PowerManagerServiceTest {
PowerManagerService.PowerPropertiesWrapper createPowerPropertiesWrapper() {
return mPowerPropertiesWrapper;
}
+
+ @Override
+ DeviceConfigParameterProvider createDeviceConfigParameterProvider() {
+ return mDeviceParameterProvider;
+ }
});
return mService;
}
@@ -2680,4 +2690,197 @@ public class PowerManagerServiceTest {
verify(mNotifierMock, never()).onUserActivity(anyInt(), anyInt(), anyInt());
}
+ @Test
+ public void testFeatureEnabledProcStateUncachedToCached_fullWakeLockDisabled() {
+ doReturn(true).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+
+ setCachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isTrue();
+ }
+
+ @Test
+ public void testFeatureDisabledProcStateUncachedToCached_fullWakeLockEnabled() {
+ doReturn(false).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+
+ setCachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testFeatureEnabledProcStateUncachedToCached_screenBrightWakeLockDisabled() {
+ doReturn(true).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+
+ setCachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isTrue();
+ }
+
+ @Test
+ public void testFeatureDisabledProcStateUncachedToCached_screenBrightWakeLockEnabled() {
+ doReturn(false).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+
+ setCachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testFeatureEnabledProcStateUncachedToCached_screenDimWakeLockDisabled() {
+ doReturn(true).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
+ PowerManager.SCREEN_DIM_WAKE_LOCK);
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+
+ setCachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isTrue();
+ }
+
+ @Test
+ public void testFeatureDisabledProcStateUncachedToCached_screenDimWakeLockEnabled() {
+ doReturn(false).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
+ PowerManager.SCREEN_DIM_WAKE_LOCK);
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+
+ setCachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testFeatureEnabledProcStateCachedToUncached_fullWakeLockEnabled() {
+ doReturn(true).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
+ setCachedUidProcState(wakeLock.mOwnerUid);
+
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testFeatureDisabledProcStateCachedToUncached_fullWakeLockEnabled() {
+ doReturn(false).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
+ setCachedUidProcState(wakeLock.mOwnerUid);
+
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testFeatureEnabledProcStateCachedToUncached_screenBrightWakeLockEnabled() {
+ doReturn(true).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
+ setCachedUidProcState(wakeLock.mOwnerUid);
+
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testFeatureDisabledProcStateCachedToUncached_screenBrightWakeLockEnabled() {
+ doReturn(false).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
+ setCachedUidProcState(wakeLock.mOwnerUid);
+
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testFeatureEnabledProcStateCachedToUncached_screenDimWakeLockEnabled() {
+ doReturn(true).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
+ PowerManager.SCREEN_DIM_WAKE_LOCK);
+ setCachedUidProcState(wakeLock.mOwnerUid);
+
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testFeatureDisabledProcStateCachedToUncached_screenDimWakeLockEnabled() {
+ doReturn(false).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ createService();
+ startSystem();
+ WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
+ PowerManager.SCREEN_DIM_WAKE_LOCK);
+ setCachedUidProcState(wakeLock.mOwnerUid);
+
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ @Test
+ public void testFeatureDynamicallyDisabledProcStateUncachedToCached_fullWakeLockEnabled() {
+ doReturn(true).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ ArgumentCaptor<DeviceConfig.OnPropertiesChangedListener> listenerCaptor =
+ ArgumentCaptor.forClass(DeviceConfig.OnPropertiesChangedListener.class);
+ createService();
+ startSystem();
+ verify(mDeviceParameterProvider, times(1))
+ .addOnPropertiesChangedListener(any(), listenerCaptor.capture());
+ WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+ // dynamically disable the feature
+ doReturn(false).when(mDeviceParameterProvider)
+ .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
+ listenerCaptor.getValue().onPropertiesChanged(
+ new DeviceConfig.Properties("ignored_namespace", null));
+
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
+ }
+
+ private void setCachedUidProcState(int uid) {
+ mService.updateUidProcStateInternal(uid, PROCESS_STATE_TOP_SLEEPING);
+ }
+
+ private void setUncachedUidProcState(int uid) {
+ mService.updateUidProcStateInternal(uid, PROCESS_STATE_RECEIVER);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index aad373fdaf95..aca96ad20385 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -445,14 +445,14 @@ public class SystemConfigTest {
+ " <library \n"
+ " name=\"foo\"\n"
+ " file=\"" + mFooJar + "\"\n"
- + " on-bootclasspath-before=\"A\"\n"
+ + " on-bootclasspath-before=\"Q\"\n"
+ " on-bootclasspath-since=\"W\"\n"
+ " />\n\n"
+ " </permissions>";
parseSharedLibraries(contents);
assertFooIsOnlySharedLibrary();
SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
- assertThat(entry.onBootclasspathBefore).isEqualTo("A");
+ assertThat(entry.onBootclasspathBefore).isEqualTo("Q");
assertThat(entry.onBootclasspathSince).isEqualTo("W");
}
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 cebc5409c795..86d2b2fc6b56 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4148,6 +4148,30 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testSetListenerAccessForUser_grantWithNameTooLong_throws() {
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
+ ComponentName c = new ComponentName("com.example.package",
+ com.google.common.base.Strings.repeat("Blah", 150));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mBinderService.setNotificationListenerAccessGrantedForUser(
+ c, user.getIdentifier(), /* enabled= */ true, true));
+ }
+
+ @Test
+ public void testSetListenerAccessForUser_revokeWithNameTooLong_okay() throws Exception {
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
+ ComponentName c = new ComponentName("com.example.package",
+ com.google.common.base.Strings.repeat("Blah", 150));
+
+ mBinderService.setNotificationListenerAccessGrantedForUser(
+ c, user.getIdentifier(), /* enabled= */ false, true);
+
+ verify(mListeners).setPackageOrComponentEnabled(
+ c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false, true);
+ }
+
+ @Test
public void testSetAssistantAccessForUser() throws Exception {
UserInfo ui = new UserInfo();
ui.id = mContext.getUserId() + 10;
@@ -5879,6 +5903,69 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testVisitUris_styleExtrasWithoutStyle() {
+ Notification notification = new Notification.Builder(mContext, "a")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .build();
+
+ Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle(
+ personWithIcon("content://user"))
+ .addHistoricMessage(new Notification.MessagingStyle.Message("Heyhey!",
+ System.currentTimeMillis(),
+ personWithIcon("content://historicalMessenger")))
+ .addMessage(new Notification.MessagingStyle.Message("Are you there",
+ System.currentTimeMillis(),
+ personWithIcon("content://messenger")))
+ .setShortcutIcon(
+ Icon.createWithContentUri("content://conversationShortcut"));
+ messagingStyle.addExtras(notification.extras); // Instead of Builder.setStyle(style).
+
+ Notification.CallStyle callStyle = Notification.CallStyle.forOngoingCall(
+ personWithIcon("content://caller"),
+ PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE))
+ .setVerificationIcon(Icon.createWithContentUri("content://callVerification"));
+ callStyle.addExtras(notification.extras); // Same.
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ notification.visitUris(visitor);
+
+ verify(visitor).accept(eq(Uri.parse("content://user")));
+ verify(visitor).accept(eq(Uri.parse("content://historicalMessenger")));
+ verify(visitor).accept(eq(Uri.parse("content://messenger")));
+ verify(visitor).accept(eq(Uri.parse("content://conversationShortcut")));
+ verify(visitor).accept(eq(Uri.parse("content://caller")));
+ verify(visitor).accept(eq(Uri.parse("content://callVerification")));
+ }
+
+ private static Person personWithIcon(String iconUri) {
+ return new Person.Builder()
+ .setName("Mr " + iconUri)
+ .setIcon(Icon.createWithContentUri(iconUri))
+ .build();
+ }
+
+ @Test
+ public void testVisitUris_wearableExtender() {
+ Icon actionIcon = Icon.createWithContentUri("content://media/action");
+ Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
+ PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
+ Notification n = new Notification.Builder(mContext, "a")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build())
+ .extend(new Notification.WearableExtender().addAction(
+ new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build()))
+ .build();
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ n.visitUris(visitor);
+
+ verify(visitor).accept(eq(actionIcon.getUri()));
+ verify(visitor).accept(eq(wearActionIcon.getUri()));
+ }
+
+ @Test
public void testSetNotificationPolicy_preP_setOldFields() {
ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = mZenModeHelper;
@@ -10060,7 +10147,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
try {
mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
- r.getSbn().getTag(), r,false);
+ r.getSbn().getTag(), r, false, false);
fail("Allowed a contextual direct reply with an immutable intent to be posted");
} catch (IllegalArgumentException e) {
// good
@@ -10091,7 +10178,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
r.applyAdjustments();
mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
- r.getSbn().getTag(), r,false);
+ r.getSbn().getTag(), r, false, false);
}
@Test
@@ -10125,7 +10212,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
r.applyAdjustments();
mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
- r.getSbn().getTag(), r,false);
+ r.getSbn().getTag(), r, false, false);
}
@Test
@@ -10338,7 +10425,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// normal blocked notifications - blocked
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
// just using the style - blocked
nb.setStyle(new Notification.MediaStyle());
@@ -10347,7 +10434,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
// using the style, but incorrect type in session - blocked
nb.setStyle(new Notification.MediaStyle());
@@ -10359,7 +10446,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
// style + media session - bypasses block
nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
@@ -10368,7 +10455,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
}
@Test
@@ -10451,7 +10538,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// normal blocked notifications - blocked
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
// just using the style - blocked
Person person = new Person.Builder()
@@ -10465,36 +10552,36 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse();
// style + managed call - bypasses block
when(mTelecomManager.isInManagedCall()).thenReturn(true);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
// style + self managed call - bypasses block
when(mTelecomManager.isInSelfManagedCall(
r.getSbn().getPackageName(), r.getUser())).thenReturn(true);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
// set telecom manager to null - blocked
mService.setTelecomManager(null);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false))
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
.isFalse();
// set telecom feature to false - blocked
when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false))
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
.isFalse();
// telecom manager is not ready - blocked
mService.setTelecomManager(mTelecomManager);
when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready"));
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false))
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false))
.isFalse();
}
@@ -11014,7 +11101,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
try {
mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false);
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false);
assertFalse("CallStyle should not be allowed without a valid use case", true);
} catch (IllegalArgumentException error) {
assertThat(error.getMessage()).contains("CallStyle");
@@ -11034,7 +11121,25 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
+ }
+
+ @Test
+ public void checkCallStyleNotification_allowedForByForegroundService() throws Exception {
+ Person person = new Person.Builder().setName("caller").build();
+ Notification n = new Notification.Builder(mContext, "test")
+ // Without FLAG_FOREGROUND_SERVICE.
+ //.setFlag(FLAG_FOREGROUND_SERVICE, true)
+ .setStyle(Notification.CallStyle.forOngoingCall(
+ person, mock(PendingIntent.class)))
+ .build();
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+ n, UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
+ r.getSbn().getId(), r.getSbn().getTag(), r, false,
+ true /* byForegroundService */)).isTrue();
}
@Test
@@ -11050,7 +11155,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
}
@Test
@@ -11066,7 +11171,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
}
@Test
@@ -11082,7 +11187,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+ r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
}
@Test
@@ -11166,7 +11271,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Given: a call notification has the flag FLAG_ONGOING_EVENT set
// feature flag: ALLOW_DISMISS_ONGOING is on
mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
- when(mTelecomManager.isInManagedCall()).thenReturn(true);
Person person = new Person.Builder()
.setName("caller")
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
index beab107ec556..40f34a679c57 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
@@ -19,6 +19,15 @@ package com.android.server.notification;
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
+import static android.service.notification.NotificationStats.DISMISSAL_OTHER;
+
+import static com.android.server.notification.NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_CLICK;
+import static com.android.server.notification.NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED;
+import static com.android.server.notification.NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_OTHER;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -155,4 +164,18 @@ public class NotificationRecordLoggerTest extends UiServiceTestCase {
// Then: should return false
assertFalse(NotificationRecordLogger.isNonDismissible(p.r));
}
+
+ @Test
+ public void testBubbleGroupSummaryDismissal() {
+ assertEquals(NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED,
+ NotificationRecordLogger.NotificationCancelledEvent.fromCancelReason(
+ REASON_GROUP_SUMMARY_CANCELED, DISMISSAL_BUBBLE));
+ }
+
+ @Test
+ public void testOtherNotificationCancel() {
+ assertEquals(NOTIFICATION_CANCEL_USER_OTHER,
+ NotificationRecordLogger.NotificationCancelledEvent.fromCancelReason(
+ REASON_CANCEL, DISMISSAL_OTHER));
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
index 6668f8520820..024c38e5c1f7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
@@ -66,6 +66,8 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@@ -87,7 +89,6 @@ public class NotificationVisitUrisTest extends UiServiceTestCase {
// This list should be emptied! Items can be removed as bugs are fixed.
private static final Multimap<Class<?>, String> KNOWN_BAD =
ImmutableMultimap.<Class<?>, String>builder()
- .put(Notification.WearableExtender.class, "addAction") // TODO: b/281044385
.put(Person.Builder.class, "setUri") // TODO: b/281044385
.put(RemoteViews.class, "setRemoteAdapter") // TODO: b/281044385
.build();
@@ -149,7 +150,7 @@ public class NotificationVisitUrisTest extends UiServiceTestCase {
Generated<Notification> notification = buildNotification(mContext, /* styleClass= */ null,
/* extenderClass= */ null, /* actionExtenderClass= */ null,
/* includeRemoteViews= */ true);
- assertThat(notification.includedUris.size()).isAtLeast(20);
+ assertThat(notification.includedUris.size()).isAtLeast(900);
}
@Test
@@ -435,19 +436,43 @@ public class NotificationVisitUrisTest extends UiServiceTestCase {
Set<Class<?>> excludingClasses, SpecialParameterGenerator specialGenerator) {
Log.i(TAG, "About to generate parameters for " + ReflectionUtils.methodToString(executable)
+ " in " + where);
- Class<?>[] parameterTypes = executable.getParameterTypes();
+ Type[] parameterTypes = executable.getGenericParameterTypes();
Object[] parameterValues = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
- parameterValues[i] = generateObject(
+ parameterValues[i] = generateParameter(
parameterTypes[i],
where.plus(executable,
- String.format("[%d,%s]", i, parameterTypes[i].getName())),
+ String.format("[%d,%s]", i, parameterTypes[i].getTypeName())),
excludingClasses,
specialGenerator);
}
return parameterValues;
}
+ private static Object generateParameter(Type parameterType, Location where,
+ Set<Class<?>> excludingClasses, SpecialParameterGenerator specialGenerator) {
+ if (parameterType instanceof Class<?> parameterClass) {
+ return generateObject(
+ parameterClass,
+ where,
+ excludingClasses,
+ specialGenerator);
+ } else if (parameterType instanceof ParameterizedType parameterizedType) {
+ if (parameterizedType.getRawType().equals(List.class)
+ && parameterizedType.getActualTypeArguments()[0] instanceof Class<?>) {
+ ArrayList listValue = new ArrayList();
+ for (int i = 0; i < NUM_ELEMENTS_IN_ARRAY; i++) {
+ listValue.add(
+ generateObject((Class<?>) parameterizedType.getActualTypeArguments()[0],
+ where, excludingClasses, specialGenerator));
+ }
+ return listValue;
+ }
+ }
+ throw new IllegalArgumentException(
+ "I have no idea how to produce a(n) " + parameterType + ", sorry");
+ }
+
private static class ReflectionUtils {
static Set<Class<?>> getConcreteSubclasses(Class<?> clazz, Class<?> containerClass) {
return Arrays.stream(containerClass.getDeclaredClasses())
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
index 6a1674b7df8e..63b8e1710b50 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
@@ -38,13 +38,16 @@ import android.os.BatteryStatsInternal;
import android.os.Process;
import android.os.RemoteException;
+import androidx.test.filters.FlakyTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.util.FakeLatencyTracker;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.Timeout;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
@@ -52,8 +55,12 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(JUnit4.class)
+@FlakyTest(bugId = 275746222)
public class SoundTriggerMiddlewareLoggingLatencyTest {
+ @Rule
+ public Timeout mGlobalTimeout = Timeout.seconds(30);
+
private FakeLatencyTracker mLatencyTracker;
@Mock
private BatteryStatsInternal mBatteryStatsInternal;
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 5c3102d870d0..65e77dcd4ca9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -182,12 +182,12 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
@Test
public void testLaunchState() {
- final ToIntFunction<Boolean> launchTemplate = doRelaunch -> {
+ final ToIntFunction<Runnable> launchTemplate = action -> {
clearInvocations(mLaunchObserver);
onActivityLaunched(mTopActivity);
notifyTransitionStarting(mTopActivity);
- if (doRelaunch) {
- mActivityMetricsLogger.notifyActivityRelaunched(mTopActivity);
+ if (action != null) {
+ action.run();
}
final ActivityMetricsLogger.TransitionInfoSnapshot info =
notifyWindowsDrawn(mTopActivity);
@@ -199,21 +199,27 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
// Assume that the process is started (ActivityBuilder has mocked the returned value of
// ATMS#getProcessController) but the activity has not attached process.
mTopActivity.app = null;
- assertWithMessage("Warm launch").that(launchTemplate.applyAsInt(false /* doRelaunch */))
+ assertWithMessage("Warm launch").that(launchTemplate.applyAsInt(null))
.isEqualTo(WaitResult.LAUNCH_STATE_WARM);
mTopActivity.app = app;
mNewActivityCreated = false;
- assertWithMessage("Hot launch").that(launchTemplate.applyAsInt(false /* doRelaunch */))
+ assertWithMessage("Hot launch").that(launchTemplate.applyAsInt(null))
.isEqualTo(WaitResult.LAUNCH_STATE_HOT);
- assertWithMessage("Relaunch").that(launchTemplate.applyAsInt(true /* doRelaunch */))
+ assertWithMessage("Relaunch").that(launchTemplate.applyAsInt(
+ () -> mActivityMetricsLogger.notifyActivityRelaunched(mTopActivity)))
.isEqualTo(WaitResult.LAUNCH_STATE_RELAUNCH);
+ assertWithMessage("Cold launch by restart").that(launchTemplate.applyAsInt(
+ () -> mActivityMetricsLogger.notifyBindApplication(
+ mTopActivity.info.applicationInfo)))
+ .isEqualTo(WaitResult.LAUNCH_STATE_COLD);
+
mTopActivity.app = null;
mNewActivityCreated = true;
doReturn(null).when(mAtm).getProcessController(app.mName, app.mUid);
- assertWithMessage("Cold launch").that(launchTemplate.applyAsInt(false /* doRelaunch */))
+ assertWithMessage("Cold launch").that(launchTemplate.applyAsInt(null))
.isEqualTo(WaitResult.LAUNCH_STATE_COLD);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 2b589bf59682..9842d7009444 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -74,7 +74,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -103,6 +102,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import android.service.voice.IVoiceInteractionSession;
@@ -159,6 +159,9 @@ public class ActivityStarterTests extends WindowTestsBase {
private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
private static final int UNIMPORTANT_UID = 12345;
private static final int UNIMPORTANT_UID2 = 12346;
+ private static final int SDK_SANDBOX_UID = Process.toSdkSandboxUid(UNIMPORTANT_UID);
+ private static final int SECONDARY_USER_SDK_SANDBOX_UID =
+ UserHandle.getUid(10, SDK_SANDBOX_UID);
private static final int CURRENT_IME_UID = 12347;
protected final DeviceConfigStateHelper mDeviceConfig = new DeviceConfigStateHelper(
@@ -958,6 +961,48 @@ public class ActivityStarterTests extends WindowTestsBase {
mockingSession.finishMocking();
}
+
+ @Test
+ public void testBackgroundActivityStartsAllowed_sdkSandboxClientAppHasVisibleWindow() {
+ doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
+ // The SDK's associated client app has a visible window
+ doReturn(true).when(mAtm).hasActiveVisibleWindow(
+ Process.getAppUidForSdkSandboxUid(SDK_SANDBOX_UID));
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "allowed_sdkSandboxClientAppHasVisibleWindow", false, SDK_SANDBOX_UID,
+ false, PROCESS_STATE_TOP, SDK_SANDBOX_UID, false,
+ PROCESS_STATE_TOP, true, false, false,
+ false, false, false, false, false);
+ }
+
+ @Test
+ public void testBackgroundActivityStartsDisallowed_sdkSandboxClientHasNoVisibleWindow() {
+ doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
+ // The SDK's associated client app does not have a visible window
+ doReturn(false).when(mAtm).hasActiveVisibleWindow(
+ Process.getAppUidForSdkSandboxUid(SDK_SANDBOX_UID));
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "disallowed_sdkSandboxClientHasNoVisibleWindow", true, SDK_SANDBOX_UID,
+ false, PROCESS_STATE_TOP, SDK_SANDBOX_UID, false,
+ PROCESS_STATE_TOP, true, false, false,
+ false, false, false, false, false);
+
+ }
+
+ @Test
+ public void testBackgroundActivityStartsAllowed_sdkSandboxMultiUserClientHasVisibleWindow() {
+ doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
+ // The SDK's associated client app has a visible window
+ doReturn(true).when(mAtm).hasActiveVisibleWindow(
+ Process.getAppUidForSdkSandboxUid(SECONDARY_USER_SDK_SANDBOX_UID));
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "allowed_sdkSandboxMultiUserClientHasVisibleWindow", false,
+ SECONDARY_USER_SDK_SANDBOX_UID, false, PROCESS_STATE_TOP,
+ SECONDARY_USER_SDK_SANDBOX_UID, false, PROCESS_STATE_TOP,
+ false, false, false, false,
+ false, false, false, false);
+ }
+
private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index f235d153c658..233a2076a867 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -52,7 +52,8 @@ public class DimmerTests extends WindowTestsBase {
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
final SurfaceControl mControl = mock(SurfaceControl.class);
- final SurfaceControl.Transaction mTransaction = spy(StubTransaction.class);
+ final SurfaceControl.Transaction mPendingTransaction = spy(StubTransaction.class);
+ final SurfaceControl.Transaction mSyncTransaction = spy(StubTransaction.class);
TestWindowContainer(WindowManagerService wm) {
super(wm);
@@ -65,12 +66,12 @@ public class DimmerTests extends WindowTestsBase {
@Override
public SurfaceControl.Transaction getSyncTransaction() {
- return mTransaction;
+ return mSyncTransaction;
}
@Override
public SurfaceControl.Transaction getPendingTransaction() {
- return mTransaction;
+ return mPendingTransaction;
}
}
@@ -144,7 +145,7 @@ public class DimmerTests extends WindowTestsBase {
mHost.addChild(child, 0);
final float alpha = 0.8f;
- mDimmer.dimAbove(mTransaction, child, alpha);
+ mDimmer.dimAbove(child, alpha);
int width = 100;
int height = 300;
@@ -161,13 +162,13 @@ public class DimmerTests extends WindowTestsBase {
mHost.addChild(child, 0);
final float alpha = 0.8f;
- mDimmer.dimAbove(mTransaction, child, alpha);
+ mDimmer.dimAbove(child, alpha);
SurfaceControl dimLayer = getDimLayer();
assertNotNull("Dimmer should have created a surface", dimLayer);
- verify(mTransaction).setAlpha(dimLayer, alpha);
- verify(mTransaction).setRelativeLayer(dimLayer, child.mControl, 1);
+ verify(mHost.getPendingTransaction()).setAlpha(dimLayer, alpha);
+ verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, child.mControl, 1);
}
@Test
@@ -176,13 +177,13 @@ public class DimmerTests extends WindowTestsBase {
mHost.addChild(child, 0);
final float alpha = 0.8f;
- mDimmer.dimBelow(mTransaction, child, alpha, 0);
+ mDimmer.dimBelow(child, alpha, 0);
SurfaceControl dimLayer = getDimLayer();
assertNotNull("Dimmer should have created a surface", dimLayer);
- verify(mTransaction).setAlpha(dimLayer, alpha);
- verify(mTransaction).setRelativeLayer(dimLayer, child.mControl, -1);
+ verify(mHost.getPendingTransaction()).setAlpha(dimLayer, alpha);
+ verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, child.mControl, -1);
}
@Test
@@ -191,7 +192,7 @@ public class DimmerTests extends WindowTestsBase {
mHost.addChild(child, 0);
final float alpha = 0.8f;
- mDimmer.dimAbove(mTransaction, child, alpha);
+ mDimmer.dimAbove(child, alpha);
SurfaceControl dimLayer = getDimLayer();
mDimmer.resetDimStates();
@@ -208,10 +209,10 @@ public class DimmerTests extends WindowTestsBase {
mHost.addChild(child, 0);
final float alpha = 0.8f;
- mDimmer.dimAbove(mTransaction, child, alpha);
+ mDimmer.dimAbove(child, alpha);
SurfaceControl dimLayer = getDimLayer();
mDimmer.resetDimStates();
- mDimmer.dimAbove(mTransaction, child, alpha);
+ mDimmer.dimAbove(child, alpha);
mDimmer.updateDims(mTransaction);
verify(mTransaction).show(dimLayer);
@@ -224,7 +225,7 @@ public class DimmerTests extends WindowTestsBase {
mHost.addChild(child, 0);
final float alpha = 0.8f;
- mDimmer.dimAbove(mTransaction, child, alpha);
+ mDimmer.dimAbove(child, alpha);
final Rect bounds = mDimmer.mDimState.mDimBounds;
SurfaceControl dimLayer = getDimLayer();
@@ -245,7 +246,7 @@ public class DimmerTests extends WindowTestsBase {
TestWindowContainer child = new TestWindowContainer(mWm);
mHost.addChild(child, 0);
- mDimmer.dimAbove(mTransaction, child, 1);
+ mDimmer.dimAbove(child, 1);
SurfaceControl dimLayer = getDimLayer();
mDimmer.updateDims(mTransaction);
verify(mTransaction, times(1)).show(dimLayer);
@@ -266,13 +267,13 @@ public class DimmerTests extends WindowTestsBase {
mHost.addChild(child, 0);
final int blurRadius = 50;
- mDimmer.dimBelow(mTransaction, child, 0, blurRadius);
+ mDimmer.dimBelow(child, 0, blurRadius);
SurfaceControl dimLayer = getDimLayer();
assertNotNull("Dimmer should have created a surface", dimLayer);
- verify(mTransaction).setBackgroundBlurRadius(dimLayer, blurRadius);
- verify(mTransaction).setRelativeLayer(dimLayer, child.mControl, -1);
+ verify(mHost.getPendingTransaction()).setBackgroundBlurRadius(dimLayer, blurRadius);
+ verify(mHost.getPendingTransaction()).setRelativeLayer(dimLayer, child.mControl, -1);
}
private SurfaceControl getDimLayer() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index adf3f3976f38..bd111ada8550 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -233,7 +233,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition) {
+ public void onKeyguardOccludedChangedLw(boolean occluded) {
}
public void setSafeMode(boolean safeMode) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index ed0c8ef489e5..d4fabf40d5d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -61,6 +61,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -1425,6 +1426,15 @@ public class TransitionTests extends WindowTestsBase {
// No need to wait for the activity in transient hide task.
assertEquals(WindowContainer.SYNC_STATE_NONE, activity1.mSyncState);
+ // An active transient launch overrides idle state to avoid clearing power mode before the
+ // transition is finished.
+ spyOn(mRootWindowContainer.mTransitionController);
+ doAnswer(invocation -> controller.isTransientLaunch(invocation.getArgument(0))).when(
+ mRootWindowContainer.mTransitionController).isTransientLaunch(any());
+ activity2.getTask().setResumedActivity(activity2, "test");
+ activity2.idle = true;
+ assertFalse(mRootWindowContainer.allResumedActivitiesIdle());
+
activity1.setVisibleRequested(false);
activity2.setVisibleRequested(true);
activity2.setVisible(true);
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
index 7fe8582f96de..c508fa968b14 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -59,6 +59,8 @@ public final class UsbAlsaDevice {
private String mDeviceName = "";
private String mDeviceDescription = "";
+ private boolean mHasJackDetect = true;
+
public UsbAlsaDevice(IAudioService audioService, int card, int device, String deviceAddress,
boolean hasOutput, boolean hasInput,
boolean isInputHeadset, boolean isOutputHeadset, boolean isDock) {
@@ -168,8 +170,14 @@ public final class UsbAlsaDevice {
if (mJackDetector != null) {
return;
}
+ if (!mHasJackDetect) {
+ return;
+ }
// If no jack detect capabilities exist, mJackDetector will be null.
mJackDetector = UsbAlsaJackDetector.startJackDetect(this);
+ if (mJackDetector == null) {
+ mHasJackDetect = false;
+ }
}
/** Stops a jack-detection thread. */
@@ -182,8 +190,8 @@ public final class UsbAlsaDevice {
/** Start using this device as the selected USB Audio Device. */
public synchronized void start() {
- startInput();
startOutput();
+ startInput();
}
/** Start using this device as the selected USB input device. */
@@ -208,8 +216,8 @@ public final class UsbAlsaDevice {
/** Stop using this device as the selected USB Audio Device. */
public synchronized void stop() {
- stopInput();
stopOutput();
+ stopInput();
}
/** Stop using this device as the selected USB input device. */
diff --git a/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java b/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java
index db369756c50e..346622f0f467 100644
--- a/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java
+++ b/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java
@@ -61,8 +61,11 @@ public final class BinaryTransparencyHostTest extends BaseHostJUnit4Test {
options.setTestMethodName("testCollectAllApexInfo");
// Collect APEX package names from /apex, then pass them as expectation to be verified.
+ // The package names are collected from the find name with deduplication (NB: we used to
+ // deduplicate by dropping directory names with '@', but there's a DCLA case where it only
+ // has one directory with '@'. So we have to keep it and deduplicate the current way).
CommandResult result = getDevice().executeShellV2Command(
- "ls -d /apex/*/ |grep -v @ |grep -v /apex/sharedlibs |cut -d/ -f3");
+ "ls -d /apex/*/ |grep -v /apex/sharedlibs |cut -d/ -f3 |cut -d@ -f1 |sort |uniq");
assertTrue(result.getStatus() == CommandStatus.SUCCESS);
String[] packageNames = result.getStdout().split("\n");
for (var i = 0; i < packageNames.length; i++) {
diff --git a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
index e56ce81e8ce6..63782f1bf955 100644
--- a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
+++ b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
@@ -45,7 +45,7 @@ class UnresponsiveGestureMonitorActivity : Activity() {
private lateinit var mInputMonitor: InputMonitor
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- val inputManager = getSystemService(InputManager::class.java)
+ val inputManager = checkNotNull(getSystemService(InputManager::class.java))
mInputMonitor = inputManager.monitorGestureInput(MONITOR_NAME, displayId)
mInputEventReceiver = UnresponsiveReceiver(
mInputMonitor.getInputChannel(), Looper.myLooper()!!)
diff --git a/tests/Internal/src/android/service/wallpaper/OWNERS b/tests/Internal/src/android/service/wallpaper/OWNERS
new file mode 100644
index 000000000000..5a26d0e1f62b
--- /dev/null
+++ b/tests/Internal/src/android/service/wallpaper/OWNERS
@@ -0,0 +1,4 @@
+dupin@google.com
+santie@google.com
+pomini@google.com
+poultney@google.com \ No newline at end of file
diff --git a/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java b/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java
index 153ca79e346b..0c5e8d481131 100644
--- a/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java
+++ b/tests/Internal/src/android/service/wallpaper/WallpaperServiceTest.java
@@ -85,4 +85,17 @@ public class WallpaperServiceTest {
assertEquals("onAmbientModeChanged should have been called", 2, zoomChangedCount[0]);
}
+ @Test
+ public void testNotifyColorsOfDestroyedEngine_doesntCrash() {
+ WallpaperService service = new WallpaperService() {
+ @Override
+ public Engine onCreateEngine() {
+ return new Engine();
+ }
+ };
+ WallpaperService.Engine engine = service.onCreateEngine();
+ engine.detach();
+
+ engine.notifyColorsChanged();
+ }
}
diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt
index 8a653045c97b..1a79a11a3718 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GainmapMetadataEditor.kt
@@ -99,23 +99,23 @@ class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
(view.getParent() as ViewGroup).removeView(view)
parent.addView(view)
- view.findViewById<Button>(R.id.gainmap_metadata_done)!!.setOnClickListener {
+ view.requireViewById<Button>(R.id.gainmap_metadata_done).setOnClickListener {
closeEditor()
}
- view.findViewById<Button>(R.id.gainmap_metadata_reset)!!.setOnClickListener {
+ view.requireViewById<Button>(R.id.gainmap_metadata_reset).setOnClickListener {
resetGainmapMetadata()
}
updateMetadataUi()
- val gainmapMinSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmin)
- val gainmapMaxSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmax)
- val capacityMinSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymin)
- val capacityMaxSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymax)
- val gammaSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_gamma)
- val offsetSdrSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_offsetsdr)
- val offsetHdrSeek = view.findViewById<SeekBar>(R.id.gainmap_metadata_offsethdr)
+ val gainmapMinSeek = view.requireViewById<SeekBar>(R.id.gainmap_metadata_gainmapmin)
+ val gainmapMaxSeek = view.requireViewById<SeekBar>(R.id.gainmap_metadata_gainmapmax)
+ val capacityMinSeek = view.requireViewById<SeekBar>(R.id.gainmap_metadata_capacitymin)
+ val capacityMaxSeek = view.requireViewById<SeekBar>(R.id.gainmap_metadata_capacitymax)
+ val gammaSeek = view.requireViewById<SeekBar>(R.id.gainmap_metadata_gamma)
+ val offsetSdrSeek = view.requireViewById<SeekBar>(R.id.gainmap_metadata_offsetsdr)
+ val offsetHdrSeek = view.requireViewById<SeekBar>(R.id.gainmap_metadata_offsethdr)
arrayOf(gainmapMinSeek, gainmapMaxSeek, capacityMinSeek, capacityMaxSeek, gammaSeek,
offsetSdrSeek, offsetHdrSeek).forEach {
it.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
@@ -140,13 +140,13 @@ class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
}
private fun updateMetadataUi() {
- val gainmapMinSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmin)
- val gainmapMaxSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_gainmapmax)
- val capacityMinSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymin)
- val capacityMaxSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_capacitymax)
- val gammaSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_gamma)
- val offsetSdrSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_offsetsdr)
- val offsetHdrSeek = parent.findViewById<SeekBar>(R.id.gainmap_metadata_offsethdr)
+ val gainmapMinSeek = parent.requireViewById<SeekBar>(R.id.gainmap_metadata_gainmapmin)
+ val gainmapMaxSeek = parent.requireViewById<SeekBar>(R.id.gainmap_metadata_gainmapmax)
+ val capacityMinSeek = parent.requireViewById<SeekBar>(R.id.gainmap_metadata_capacitymin)
+ val capacityMaxSeek = parent.requireViewById<SeekBar>(R.id.gainmap_metadata_capacitymax)
+ val gammaSeek = parent.requireViewById<SeekBar>(R.id.gainmap_metadata_gamma)
+ val offsetSdrSeek = parent.requireViewById<SeekBar>(R.id.gainmap_metadata_offsetsdr)
+ val offsetHdrSeek = parent.requireViewById<SeekBar>(R.id.gainmap_metadata_offsethdr)
gainmapMinSeek.setProgress(
((currentMetadata.ratioMin - minRatioMin) / maxRatioMin * maxProgress).toInt())
@@ -166,19 +166,19 @@ class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
((1.0 - Math.log(currentMetadata.offsetHdr.toDouble() / Math.log(3.0)) / -11.0)
.toFloat() * maxProgress).toInt())
- parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmin_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_gainmapmin_val).setText(
"%.3f".format(currentMetadata.ratioMin))
- parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmax_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_gainmapmax_val).setText(
"%.3f".format(currentMetadata.ratioMax))
- parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymin_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_capacitymin_val).setText(
"%.3f".format(currentMetadata.capacityMin))
- parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymax_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_capacitymax_val).setText(
"%.3f".format(currentMetadata.capacityMax))
- parent.findViewById<TextView>(R.id.gainmap_metadata_gamma_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_gamma_val).setText(
"%.3f".format(currentMetadata.gamma))
- parent.findViewById<TextView>(R.id.gainmap_metadata_offsetsdr_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_offsetsdr_val).setText(
"%.5f".format(currentMetadata.offsetSdr))
- parent.findViewById<TextView>(R.id.gainmap_metadata_offsethdr_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_offsethdr_val).setText(
"%.5f".format(currentMetadata.offsetHdr))
}
@@ -201,7 +201,7 @@ class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
private fun updateGainmapMin(normalized: Float) {
val newValue = minRatioMin + normalized * (maxRatioMin - minRatioMin)
- parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmin_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_gainmapmin_val).setText(
"%.3f".format(newValue))
currentMetadata.ratioMin = newValue
if (showingEdits) {
@@ -212,7 +212,7 @@ class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
private fun updateGainmapMax(normalized: Float) {
val newValue = minRatioMax + normalized * (maxRatioMax - minRatioMax)
- parent.findViewById<TextView>(R.id.gainmap_metadata_gainmapmax_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_gainmapmax_val).setText(
"%.3f".format(newValue))
currentMetadata.ratioMax = newValue
if (showingEdits) {
@@ -223,7 +223,7 @@ class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
private fun updateCapacityMin(normalized: Float) {
val newValue = minCapacityMin + normalized * (maxCapacityMin - minCapacityMin)
- parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymin_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_capacitymin_val).setText(
"%.3f".format(newValue))
currentMetadata.capacityMin = newValue
if (showingEdits) {
@@ -234,7 +234,7 @@ class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
private fun updateCapacityMax(normalized: Float) {
val newValue = minCapacityMax + normalized * (maxCapacityMax - minCapacityMax)
- parent.findViewById<TextView>(R.id.gainmap_metadata_capacitymax_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_capacitymax_val).setText(
"%.3f".format(newValue))
currentMetadata.capacityMax = newValue
if (showingEdits) {
@@ -245,7 +245,7 @@ class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
private fun updateGamma(normalized: Float) {
val newValue = minGamma + normalized * (maxGamma - minGamma)
- parent.findViewById<TextView>(R.id.gainmap_metadata_gamma_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_gamma_val).setText(
"%.3f".format(newValue))
currentMetadata.gamma = newValue
if (showingEdits) {
@@ -259,7 +259,7 @@ class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
if (normalized > 0.0f ) {
newValue = Math.pow(3.0, (1.0 - normalized.toDouble()) * -11.0).toFloat()
}
- parent.findViewById<TextView>(R.id.gainmap_metadata_offsetsdr_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_offsetsdr_val).setText(
"%.5f".format(newValue))
currentMetadata.offsetSdr = newValue
if (showingEdits) {
@@ -273,7 +273,7 @@ class GainmapMetadataEditor(val parent: ViewGroup, val renderView: View) {
if (normalized > 0.0f ) {
newValue = Math.pow(3.0, (1.0 - normalized.toDouble()) * -11.0).toFloat()
}
- parent.findViewById<TextView>(R.id.gainmap_metadata_offsethdr_val)!!.setText(
+ parent.requireViewById<TextView>(R.id.gainmap_metadata_offsethdr_val).setText(
"%.5f".format(newValue))
currentMetadata.offsetHdr = newValue
if (showingEdits) {
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
index 2f2578b87f35..41baeadf7a8c 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
@@ -190,9 +190,9 @@ class GlassView(context: Context, attributeSet: AttributeSet) : FrameLayout(cont
sensorManager?.unregisterListener(sensorListener)
}
- override fun onDraw(canvas: Canvas?) {
+ override fun onDraw(canvas: Canvas) {
updateGlassRenderNode()
- canvas?.drawRenderNode(renderNode)
+ canvas.drawRenderNode(renderNode)
}
fun resetGyroOffsets() {
@@ -227,4 +227,4 @@ class GlassView(context: Context, attributeSet: AttributeSet) : FrameLayout(cont
renderNodeIsDirty = false
}
}
-} \ No newline at end of file
+}
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
index 1400dde5781d..c1a7bd9e1d8f 100644
--- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -30,7 +30,7 @@ import org.junit.runners.model.Statement
*/
class LockStateTrackingRule : TestRule {
private val context: Context = getApplicationContext()
- private val windowManager = WindowManagerGlobal.getWindowManagerService()
+ private val windowManager = checkNotNull(WindowManagerGlobal.getWindowManagerService())
@Volatile lateinit var lockState: LockState
private set
diff --git a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
index 4189baae10cb..f1edca3ff86e 100644
--- a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
@@ -36,7 +36,7 @@ import org.junit.runners.model.Statement
class ScreenLockRule : TestRule {
private val context: Context = getApplicationContext()
private val uiDevice = UiDevice.getInstance(getInstrumentation())
- private val windowManager = WindowManagerGlobal.getWindowManagerService()
+ private val windowManager = checkNotNull(WindowManagerGlobal.getWindowManagerService())
private val lockPatternUtils = LockPatternUtils(context)
private var instantLockSavedValue = false