summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TEST_MAPPING11
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java364
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java1
-rw-r--r--apex/media/framework/api/current.txt1
-rw-r--r--apex/media/framework/java/android/media/MediaCommunicationManager.java22
-rw-r--r--cmds/bootanimation/BootAnimation.cpp22
-rw-r--r--core/api/current.txt9
-rw-r--r--core/api/system-current.txt31
-rw-r--r--core/java/Android.bp5
-rw-r--r--core/java/android/app/ActivityThread.java7
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java1
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java24
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java55
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java5
-rw-r--r--core/java/android/companion/Association.java30
-rw-r--r--core/java/android/hardware/display/DisplayManager.java4
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java6
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl2
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl3
-rw-r--r--core/java/android/hardware/input/InputDeviceVibrator.java93
-rw-r--r--core/java/android/hardware/input/InputManager.java27
-rw-r--r--core/java/android/net/NetworkIdentity.java8
-rw-r--r--core/java/android/net/NetworkState.java22
-rw-r--r--core/java/android/provider/Settings.java22
-rw-r--r--core/java/android/rotationresolver/RotationResolverInternal.java4
-rw-r--r--core/java/android/service/notification/INotificationListener.aidl2
-rw-r--r--core/java/android/text/FontConfig.java114
-rw-r--r--core/java/android/tracing/ITracingServiceProxy.aidl32
-rw-r--r--core/java/android/tracing/OWNERS2
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/android/uwb/SessionHandle.java7
-rw-r--r--core/java/android/view/DisplayEventReceiver.java14
-rw-r--r--core/java/android/view/Surface.java4
-rw-r--r--core/java/android/view/SurfaceControl.java79
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java2
-rw-r--r--core/java/android/view/SyncRtSurfaceTransactionApplier.java9
-rw-r--r--core/java/android/view/ViewRootImpl.java4
-rw-r--r--core/java/android/view/WindowlessWindowManager.java41
-rw-r--r--core/java/android/view/inputmethod/InlineSuggestionsRequest.java32
-rw-r--r--core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java9
-rw-r--r--core/java/com/android/internal/infra/ServiceConnector.java39
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java12
-rw-r--r--core/java/com/android/internal/os/CPU_OWNERS3
-rw-r--r--core/java/com/android/internal/os/OWNERS1
-rw-r--r--core/java/com/android/internal/os/Zygote.java7
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java16
-rw-r--r--core/jni/OWNERS3
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp36
-rw-r--r--core/jni/android_view_SurfaceControl.cpp207
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp32
-rw-r--r--core/res/res/layout/notification_template_part_chronometer.xml2
-rw-r--r--core/res/res/values/attrs.xml12
-rw-r--r--core/res/res/values/config.xml8
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/res/res/values/strings.xml5
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--core/tests/coretests/src/android/graphics/FontListParserTest.java245
-rw-r--r--core/tests/coretests/src/android/os/BrightnessLimit.java3
-rw-r--r--core/tests/coretests/src/com/android/internal/os/OWNERS3
-rw-r--r--data/etc/privapp-permissions-platform.xml4
-rw-r--r--graphics/java/android/graphics/FontListParser.java107
-rw-r--r--graphics/java/android/graphics/RenderEffect.java23
-rw-r--r--graphics/java/android/graphics/fonts/Font.java274
-rw-r--r--graphics/java/android/graphics/fonts/FontFamily.java15
-rw-r--r--graphics/java/android/graphics/fonts/NativeFont.java205
-rw-r--r--graphics/java/android/graphics/fonts/NativeFontBufferHelper.java62
-rw-r--r--graphics/java/android/graphics/text/PositionedGlyphs.java6
-rw-r--r--libs/WindowManager/Shell/res/layout/pip_menu.xml12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java32
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java70
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java55
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java104
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java38
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java51
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java178
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java70
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java56
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java45
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidTest.xml2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt116
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt22
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt36
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt42
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt41
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt47
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java53
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java29
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java3
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/apex/jni_runtime.cpp2
-rw-r--r--libs/hwui/jni/RenderEffect.cpp15
-rw-r--r--libs/hwui/jni/fonts/Font.cpp131
-rw-r--r--libs/hwui/jni/fonts/FontFamily.cpp16
-rw-r--r--libs/hwui/jni/fonts/NativeFont.cpp125
-rw-r--r--libs/hwui/jni/text/TextShaper.cpp10
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp8
-rw-r--r--libs/hwui/tests/common/TestContext.cpp8
-rw-r--r--libs/hwui/tests/common/TestContext.h6
-rw-r--r--libs/tracingproxy/Android.bp42
-rw-r--r--location/java/android/location/ILocationManager.aidl4
-rw-r--r--location/java/android/location/LocationManager.java83
-rw-r--r--location/java/android/location/provider/IProviderRequestListener.aidl26
-rw-r--r--location/java/android/location/provider/ProviderRequest.java11
-rw-r--r--media/java/android/media/CamcorderProfile.java13
-rw-r--r--media/java/android/media/session/ISession.aidl2
-rw-r--r--media/java/android/media/session/MediaSession.java2
-rw-r--r--media/jni/tuner/DemuxClient.h5
-rw-r--r--media/jni/tuner/DescramblerClient.cpp51
-rw-r--r--media/jni/tuner/DescramblerClient.h13
-rw-r--r--media/jni/tuner/FrontendClient.cpp27
-rw-r--r--media/jni/tuner/LnbClient.h2
-rw-r--r--media/jni/tuner/TunerClient.cpp136
-rw-r--r--media/jni/tuner/TunerClient.h2
-rw-r--r--packages/Connectivity/framework/src/android/net/ConnectivityManager.java11
-rw-r--r--packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl11
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkRequest.java69
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java7
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java5
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/Android.bp4
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml4
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml5
-rw-r--r--packages/SystemUI/res-keyguard/values/config.xml1
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml9
-rw-r--r--packages/SystemUI/res/values/dimens.xml5
-rw-r--r--packages/SystemUI/res/values/flags.xml3
-rw-r--r--packages/SystemUI/res/values/strings.xml13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java7
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java223
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java28
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java155
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java326
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java464
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java144
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java150
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java304
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java186
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java5
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java3
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java2
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java393
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java74
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java37
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java37
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java4
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java251
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java2
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java145
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java15
-rw-r--r--services/core/java/com/android/server/location/provider/LocationProviderManager.java41
-rw-r--r--services/core/java/com/android/server/media/MediaButtonReceiverHolder.java129
-rw-r--r--services/core/java/com/android/server/media/MediaKeyDispatcher.java7
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java5
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java3
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java18
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java149
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelperImpl.java16
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java23
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java31
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java29
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxy.java5
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java17
-rw-r--r--services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java3
-rw-r--r--services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java5
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java3
-rw-r--r--services/core/java/com/android/server/tracing/OWNERS2
-rw-r--r--services/core/java/com/android/server/tracing/TracingServiceProxy.java99
-rw-r--r--services/core/java/com/android/server/vcn/Vcn.java27
-rw-r--r--services/core/java/com/android/server/vcn/VcnGatewayConnection.java129
-rw-r--r--services/core/java/com/android/server/vcn/VcnNetworkProvider.java17
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java28
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java33
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java15
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java3
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java25
-rw-r--r--services/core/java/com/android/server/wm/Task.java34
-rw-r--r--services/core/java/com/android/server/wm/TaskChangeNotificationController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java26
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java19
-rw-r--r--services/core/java/com/android/server/wm/WindowOrientationListener.java122
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java11
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp16
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt271
-rw-r--r--services/tests/inprocesstests/AndroidTest.xml4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java193
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java188
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java18
-rw-r--r--services/tests/servicestests/res/layout/widget_preview.xml (renamed from packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml)9
-rw-r--r--services/tests/servicestests/res/xml/dummy_appwidget_info.xml2
-rw-r--r--services/tests/servicestests/src/com/android/server/VibratorServiceTest.java89
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/job/GracePeriodObserverTest.java106
-rw-r--r--services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java394
-rw-r--r--services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java245
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java151
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java19
-rw-r--r--telephony/java/android/telephony/SignalThresholdInfo.java24
-rw-r--r--telephony/java/android/telephony/ims/ImsRcsManager.java276
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl2
-rw-r--r--telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java30
-rw-r--r--telephony/java/android/telephony/ims/feature/RcsFeature.java33
-rw-r--r--tests/FlickerTests/AndroidTest.xml1
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt323
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt60
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt57
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt36
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt51
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt68
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt41
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt64
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt80
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt56
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt84
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt10
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt63
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt75
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt64
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt79
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt100
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java107
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt4
-rw-r--r--tests/net/integration/util/com/android/server/NetworkAgentWrapper.java2
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java10
-rw-r--r--tests/net/java/android/net/NetworkTemplateTest.kt6
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java28
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java17
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java60
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java78
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java19
290 files changed, 9408 insertions, 3564 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 2b12da291acb..6c265bc1a338 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -51,6 +51,17 @@
"exclude-annotation": "org.junit.Ignore"
}
]
+ },
+ {
+ "name": "FrameworksInProcessTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
}
],
"postsubmit-managedprofile-stress": [
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 18856f782b7d..82e967ae1a0b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -16,33 +16,43 @@
package com.android.server.job;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.UserSwitchObserver;
import android.app.job.JobInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.UserInfo;
import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseIntArray;
+import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.util.StatLogger;
import com.android.server.JobSchedulerBackgroundThread;
+import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.StateController;
+import com.android.server.pm.UserManagerInternal;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -65,13 +75,18 @@ class JobConcurrencyManager {
// Try to give higher priority types lower values.
static final int WORK_TYPE_NONE = 0;
static final int WORK_TYPE_TOP = 1 << 0;
- static final int WORK_TYPE_BG = 1 << 1;
- private static final int NUM_WORK_TYPES = 2;
+ static final int WORK_TYPE_EJ = 1 << 1;
+ static final int WORK_TYPE_BG = 1 << 2;
+ static final int WORK_TYPE_BGUSER = 1 << 3;
+ @VisibleForTesting
+ static final int NUM_WORK_TYPES = 4;
@IntDef(prefix = {"WORK_TYPE_"}, flag = true, value = {
WORK_TYPE_NONE,
WORK_TYPE_TOP,
- WORK_TYPE_BG
+ WORK_TYPE_EJ,
+ WORK_TYPE_BG,
+ WORK_TYPE_BGUSER
})
@Retention(RetentionPolicy.SOURCE)
public @interface WorkType {
@@ -94,49 +109,63 @@ class JobConcurrencyManager {
private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_ON =
new WorkConfigLimitsPerMemoryTrimLevel(
- new WorkTypeConfig("screen_on_normal", 8,
+ new WorkTypeConfig("screen_on_normal", 11,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 2)),
+ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_EJ, 3),
+ Pair.create(WORK_TYPE_BG, 2)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 6))),
- new WorkTypeConfig("screen_on_moderate", 8,
+ List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
+ ),
+ new WorkTypeConfig("screen_on_moderate", 9,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 2),
+ Pair.create(WORK_TYPE_BG, 2)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 4))),
- new WorkTypeConfig("screen_on_low", 5,
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
+ ),
+ new WorkTypeConfig("screen_on_low", 6,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 1),
+ Pair.create(WORK_TYPE_BG, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1))),
+ List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ ),
new WorkTypeConfig("screen_on_critical", 5,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1)))
+ List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ )
);
private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF =
new WorkConfigLimitsPerMemoryTrimLevel(
- new WorkTypeConfig("screen_off_normal", 10,
+ new WorkTypeConfig("screen_off_normal", 13,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3),
+ Pair.create(WORK_TYPE_BG, 2)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 6))),
- new WorkTypeConfig("screen_off_moderate", 10,
+ List.of(Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 4))
+ ),
+ new WorkTypeConfig("screen_off_moderate", 13,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
+ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_EJ, 3),
+ Pair.create(WORK_TYPE_BG, 2)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 4))),
- new WorkTypeConfig("screen_off_low", 5,
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))
+ ),
+ new WorkTypeConfig("screen_off_low", 7,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 2),
+ Pair.create(WORK_TYPE_BG, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1))),
+ List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ ),
new WorkTypeConfig("screen_off_critical", 5,
// defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
+ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 1)),
// defaultMax
- List.of(Pair.create(WORK_TYPE_BG, 1)))
+ List.of(Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))
+ )
);
/**
@@ -171,6 +200,10 @@ class JobConcurrencyManager {
"assignJobsToContexts",
"refreshSystemState",
});
+ @VisibleForTesting
+ GracePeriodObserver mGracePeriodObserver;
+ @VisibleForTesting
+ boolean mShouldRestrictBgUser;
interface Stats {
int ASSIGN_JOBS_TO_CONTEXTS = 0;
@@ -182,9 +215,13 @@ class JobConcurrencyManager {
JobConcurrencyManager(JobSchedulerService service) {
mService = service;
mLock = mService.mLock;
- mContext = service.getContext();
+ mContext = service.getTestableContext();
mHandler = JobSchedulerBackgroundThread.getHandler();
+
+ mGracePeriodObserver = new GracePeriodObserver(mContext);
+ mShouldRestrictBgUser = mContext.getResources().getBoolean(
+ R.bool.config_jobSchedulerRestrictBackgroundUser);
}
public void onSystemReady() {
@@ -193,10 +230,18 @@ class JobConcurrencyManager {
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mContext.registerReceiver(mReceiver, filter);
+ try {
+ ActivityManager.getService().registerUserSwitchObserver(mGracePeriodObserver, TAG);
+ } catch (RemoteException e) {
+ }
onInteractiveStateChanged(mPowerManager.isInteractive());
}
+ void onUserRemoved(int userId) {
+ mGracePeriodObserver.onUserRemoved(userId);
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -224,7 +269,7 @@ class JobConcurrencyManager {
Slog.d(TAG, "Interactive: " + interactive);
}
- final long nowRealtime = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final long nowRealtime = sElapsedRealtimeClock.millis();
if (interactive) {
mLastScreenOnRealtime = nowRealtime;
mEffectiveInteractiveState = true;
@@ -261,7 +306,7 @@ class JobConcurrencyManager {
if (mLastScreenOnRealtime > mLastScreenOffRealtime) {
return;
}
- final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ final long now = sElapsedRealtimeClock.millis();
if ((mLastScreenOffRealtime + mScreenOffAdjustmentDelayMs) > now) {
return;
}
@@ -723,6 +768,10 @@ class JobConcurrencyManager {
pw.print(mLastMemoryTrimLevel);
pw.println();
+ pw.print("User Grace Period: ");
+ pw.print(mGracePeriodObserver.mGracePeriodExpiration);
+ pw.println();
+
mStatLogger.dump(pw);
} finally {
pw.decreaseIndent();
@@ -748,15 +797,52 @@ class JobConcurrencyManager {
proto.end(token);
}
+ /**
+ * Decides whether a job is from the current foreground user or the equivalent.
+ */
+ @VisibleForTesting
+ boolean shouldRunAsFgUserJob(JobStatus job) {
+ if (!mShouldRestrictBgUser) return true;
+ int userId = job.getSourceUserId();
+ UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
+ UserInfo userInfo = um.getUserInfo(userId);
+
+ // If the user has a parent user (e.g. a work profile of another user), the user should be
+ // treated equivalent as its parent user.
+ if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+ && userInfo.profileGroupId != userId) {
+ userId = userInfo.profileGroupId;
+ userInfo = um.getUserInfo(userId);
+ }
+
+ int currentUser = LocalServices.getService(ActivityManagerInternal.class)
+ .getCurrentUserId();
+ // A user is treated as foreground user if any of the followings is true:
+ // 1. The user is current user
+ // 2. The user is primary user
+ // 3. The user's grace period has not expired
+ return currentUser == userId || userInfo.isPrimary()
+ || mGracePeriodObserver.isWithinGracePeriodForUser(userId);
+ }
+
int getJobWorkTypes(@NonNull JobStatus js) {
int classification = 0;
- // TODO(171305774): create dedicated work type for EJ and FGS
- if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP
- || js.shouldTreatAsExpeditedJob()) {
- classification |= WORK_TYPE_TOP;
+ // TODO: create dedicated work type for FGS
+ if (shouldRunAsFgUserJob(js)) {
+ if (js.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
+ classification |= WORK_TYPE_TOP;
+ } else {
+ classification |= WORK_TYPE_BG;
+ }
+
+ if (js.shouldTreatAsExpeditedJob()) {
+ classification |= WORK_TYPE_EJ;
+ }
} else {
- classification |= WORK_TYPE_BG;
+ // TODO(171305774): create dedicated slots for EJs of bg user
+ classification |= WORK_TYPE_BGUSER;
}
+
return classification;
}
@@ -765,9 +851,15 @@ class JobConcurrencyManager {
private static final String KEY_PREFIX_MAX_TOTAL =
CONFIG_KEY_PREFIX_CONCURRENCY + "max_total_";
private static final String KEY_PREFIX_MAX_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "max_top_";
+ private static final String KEY_PREFIX_MAX_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "max_ej_";
private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_";
+ private static final String KEY_PREFIX_MAX_BGUSER =
+ CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_";
private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_";
+ private static final String KEY_PREFIX_MIN_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "min_ej_";
private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_";
+ private static final String KEY_PREFIX_MIN_BGUSER =
+ CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_";
private final String mConfigIdentifier;
private int mMaxTotal;
@@ -811,10 +903,18 @@ class JobConcurrencyManager {
properties.getInt(KEY_PREFIX_MAX_TOP + mConfigIdentifier,
mDefaultMaxAllowedSlots.get(WORK_TYPE_TOP, mMaxTotal))));
mMaxAllowedSlots.put(WORK_TYPE_TOP, maxTop);
+ final int maxEj = Math.max(1, Math.min(mMaxTotal,
+ properties.getInt(KEY_PREFIX_MAX_EJ + mConfigIdentifier,
+ mDefaultMaxAllowedSlots.get(WORK_TYPE_EJ, mMaxTotal))));
+ mMaxAllowedSlots.put(WORK_TYPE_EJ, maxEj);
final int maxBg = Math.max(1, Math.min(mMaxTotal,
properties.getInt(KEY_PREFIX_MAX_BG + mConfigIdentifier,
mDefaultMaxAllowedSlots.get(WORK_TYPE_BG, mMaxTotal))));
mMaxAllowedSlots.put(WORK_TYPE_BG, maxBg);
+ final int maxBgUser = Math.max(1, Math.min(mMaxTotal,
+ properties.getInt(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
+ mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER, mMaxTotal))));
+ mMaxAllowedSlots.put(WORK_TYPE_BGUSER, maxBgUser);
int remaining = mMaxTotal;
mMinReservedSlots.clear();
@@ -824,11 +924,23 @@ class JobConcurrencyManager {
mDefaultMinReservedSlots.get(WORK_TYPE_TOP))));
mMinReservedSlots.put(WORK_TYPE_TOP, minTop);
remaining -= minTop;
+ // Ensure ej is in the range [0, min(maxEj, remaining)]
+ final int minEj = Math.max(0, Math.min(Math.min(maxEj, remaining),
+ properties.getInt(KEY_PREFIX_MIN_EJ + mConfigIdentifier,
+ mDefaultMinReservedSlots.get(WORK_TYPE_EJ))));
+ mMinReservedSlots.put(WORK_TYPE_EJ, minEj);
+ remaining -= minEj;
// Ensure bg is in the range [0, min(maxBg, remaining)]
final int minBg = Math.max(0, Math.min(Math.min(maxBg, remaining),
properties.getInt(KEY_PREFIX_MIN_BG + mConfigIdentifier,
mDefaultMinReservedSlots.get(WORK_TYPE_BG))));
mMinReservedSlots.put(WORK_TYPE_BG, minBg);
+ remaining -= minBg;
+ // Ensure bg user is in the range [0, min(maxBgUser, remaining)]
+ final int minBgUser = Math.max(0, Math.min(Math.min(maxBgUser, remaining),
+ properties.getInt(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
+ mDefaultMinReservedSlots.get(WORK_TYPE_BGUSER, 0))));
+ mMinReservedSlots.put(WORK_TYPE_BGUSER, minBgUser);
}
int getMaxTotal() {
@@ -849,10 +961,18 @@ class JobConcurrencyManager {
.println();
pw.print(KEY_PREFIX_MAX_TOP + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_TOP))
.println();
+ pw.print(KEY_PREFIX_MIN_EJ + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_EJ))
+ .println();
+ pw.print(KEY_PREFIX_MAX_EJ + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_EJ))
+ .println();
pw.print(KEY_PREFIX_MIN_BG + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_BG))
.println();
pw.print(KEY_PREFIX_MAX_BG + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BG))
.println();
+ pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier,
+ mMinReservedSlots.get(WORK_TYPE_BGUSER)).println();
+ pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier,
+ mMaxAllowedSlots.get(WORK_TYPE_BGUSER)).println();
}
}
@@ -873,6 +993,58 @@ class JobConcurrencyManager {
}
/**
+ * This class keeps the track of when a user's grace period expires.
+ */
+ @VisibleForTesting
+ static class GracePeriodObserver extends UserSwitchObserver {
+ // Key is UserId and Value is the time when grace period expires
+ @VisibleForTesting
+ final SparseLongArray mGracePeriodExpiration = new SparseLongArray();
+ private int mCurrentUserId;
+ @VisibleForTesting
+ int mGracePeriod;
+ private final UserManagerInternal mUserManagerInternal;
+ final Object mLock = new Object();
+
+
+ GracePeriodObserver(Context context) {
+ mCurrentUserId = LocalServices.getService(ActivityManagerInternal.class)
+ .getCurrentUserId();
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+ mGracePeriod = Math.max(0, context.getResources().getInteger(
+ R.integer.config_jobSchedulerUserGracePeriod));
+ }
+
+ @Override
+ public void onUserSwitchComplete(int newUserId) {
+ final long expiration = sElapsedRealtimeClock.millis() + mGracePeriod;
+ synchronized (mLock) {
+ if (mCurrentUserId != UserHandle.USER_NULL
+ && mUserManagerInternal.exists(mCurrentUserId)) {
+ mGracePeriodExpiration.append(mCurrentUserId, expiration);
+ }
+ mGracePeriodExpiration.delete(newUserId);
+ mCurrentUserId = newUserId;
+ }
+ }
+
+ void onUserRemoved(int userId) {
+ synchronized (mLock) {
+ mGracePeriodExpiration.delete(userId);
+ }
+ }
+
+ @VisibleForTesting
+ public boolean isWithinGracePeriodForUser(int userId) {
+ synchronized (mLock) {
+ return userId == mCurrentUserId
+ || sElapsedRealtimeClock.millis()
+ < mGracePeriodExpiration.get(userId, Long.MAX_VALUE);
+ }
+ }
+ }
+
+ /**
* This class decides, taking into account the current {@link WorkTypeConfig} and how many jobs
* are running/pending, how many more job can start.
*
@@ -892,20 +1064,21 @@ class JobConcurrencyManager {
private final SparseIntArray mNumPendingJobs = new SparseIntArray(NUM_WORK_TYPES);
private final SparseIntArray mNumRunningJobs = new SparseIntArray(NUM_WORK_TYPES);
private final SparseIntArray mNumStartingJobs = new SparseIntArray(NUM_WORK_TYPES);
- private int mNumUnspecialized = 0;
private int mNumUnspecializedRemaining = 0;
void setConfig(@NonNull WorkTypeConfig workTypeConfig) {
mConfigMaxTotal = workTypeConfig.getMaxTotal();
mConfigNumReservedSlots.put(WORK_TYPE_TOP,
workTypeConfig.getMinReserved(WORK_TYPE_TOP));
+ mConfigNumReservedSlots.put(WORK_TYPE_EJ, workTypeConfig.getMinReserved(WORK_TYPE_EJ));
mConfigNumReservedSlots.put(WORK_TYPE_BG, workTypeConfig.getMinReserved(WORK_TYPE_BG));
+ mConfigNumReservedSlots.put(WORK_TYPE_BGUSER,
+ workTypeConfig.getMinReserved(WORK_TYPE_BGUSER));
mConfigAbsoluteMaxSlots.put(WORK_TYPE_TOP, workTypeConfig.getMax(WORK_TYPE_TOP));
+ mConfigAbsoluteMaxSlots.put(WORK_TYPE_EJ, workTypeConfig.getMax(WORK_TYPE_EJ));
mConfigAbsoluteMaxSlots.put(WORK_TYPE_BG, workTypeConfig.getMax(WORK_TYPE_BG));
+ mConfigAbsoluteMaxSlots.put(WORK_TYPE_BGUSER, workTypeConfig.getMax(WORK_TYPE_BGUSER));
- mNumUnspecialized = mConfigMaxTotal;
- mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_TOP);
- mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_BG);
mNumUnspecializedRemaining = mConfigMaxTotal;
for (int i = mNumRunningJobs.size() - 1; i >= 0; --i) {
mNumUnspecializedRemaining -= Math.max(mNumRunningJobs.valueAt(i),
@@ -934,9 +1107,15 @@ class JobConcurrencyManager {
if ((workTypes & WORK_TYPE_TOP) == WORK_TYPE_TOP) {
mNumPendingJobs.put(WORK_TYPE_TOP, mNumPendingJobs.get(WORK_TYPE_TOP) + 1);
}
+ if ((workTypes & WORK_TYPE_EJ) == WORK_TYPE_EJ) {
+ mNumPendingJobs.put(WORK_TYPE_EJ, mNumPendingJobs.get(WORK_TYPE_EJ) + 1);
+ }
if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
mNumPendingJobs.put(WORK_TYPE_BG, mNumPendingJobs.get(WORK_TYPE_BG) + 1);
}
+ if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
+ mNumPendingJobs.put(WORK_TYPE_BGUSER, mNumPendingJobs.get(WORK_TYPE_BGUSER) + 1);
+ }
}
void stageJob(@WorkType int workType) {
@@ -1018,48 +1197,76 @@ class JobConcurrencyManager {
void onCountDone() {
// Calculate how many slots to reserve for each work type. "Unspecialized" slots will
- // be reserved for higher importance types first (ie. top before bg).
- mNumUnspecialized = mConfigMaxTotal;
- final int numTop = mNumRunningJobs.get(WORK_TYPE_TOP)
- + mNumPendingJobs.get(WORK_TYPE_TOP);
- int resTop = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_TOP), numTop);
- mNumActuallyReservedSlots.put(WORK_TYPE_TOP, resTop);
- mNumUnspecialized -= resTop;
- final int numBg = mNumRunningJobs.get(WORK_TYPE_BG) + mNumPendingJobs.get(WORK_TYPE_BG);
- int resBg = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_BG), numBg);
- mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg);
- mNumUnspecialized -= resBg;
-
- mNumUnspecializedRemaining = mNumUnspecialized;
- // Account for already running jobs after we've assigned the minimum number of slots.
- int unspecializedAssigned;
- int extraRunning = (mNumRunningJobs.get(WORK_TYPE_TOP) - resTop);
- if (extraRunning > 0) {
- unspecializedAssigned = Math.max(0,
- Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP) - resTop,
- extraRunning));
- resTop += unspecializedAssigned;
- mNumUnspecializedRemaining -= extraRunning;
- }
- extraRunning = (mNumRunningJobs.get(WORK_TYPE_BG) - resBg);
- if (extraRunning > 0) {
- unspecializedAssigned = Math.max(0,
- Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG) - resBg, extraRunning));
- resBg += unspecializedAssigned;
- mNumUnspecializedRemaining -= extraRunning;
- }
+ // be reserved for higher importance types first (ie. top before ej before bg).
+ // Steps:
+ // 1. Account for slots for already running jobs
+ // 2. Use remaining unaccounted slots to try and ensure minimum reserved slots
+ // 3. Allocate remaining up to max, based on importance
- // Assign remaining unspecialized based on ranking.
- unspecializedAssigned = Math.max(0,
+ mNumUnspecializedRemaining = mConfigMaxTotal;
+
+ // Step 1
+ int runTop = mNumRunningJobs.get(WORK_TYPE_TOP);
+ int resTop = runTop;
+ mNumUnspecializedRemaining -= resTop;
+ int runEj = mNumRunningJobs.get(WORK_TYPE_EJ);
+ int resEj = runEj;
+ mNumUnspecializedRemaining -= resEj;
+ int runBg = mNumRunningJobs.get(WORK_TYPE_BG);
+ int resBg = runBg;
+ mNumUnspecializedRemaining -= resBg;
+ int runBgUser = mNumRunningJobs.get(WORK_TYPE_BGUSER);
+ int resBgUser = runBgUser;
+ mNumUnspecializedRemaining -= resBgUser;
+
+ // Step 2
+ final int numTop = runTop + mNumPendingJobs.get(WORK_TYPE_TOP);
+ int fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
+ Math.min(numTop, mConfigNumReservedSlots.get(WORK_TYPE_TOP) - resTop)));
+ resTop += fillUp;
+ mNumUnspecializedRemaining -= fillUp;
+ final int numEj = runEj + mNumPendingJobs.get(WORK_TYPE_EJ);
+ fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
+ Math.min(numEj, mConfigNumReservedSlots.get(WORK_TYPE_EJ) - resEj)));
+ resEj += fillUp;
+ mNumUnspecializedRemaining -= fillUp;
+ final int numBg = runBg + mNumPendingJobs.get(WORK_TYPE_BG);
+ fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
+ Math.min(numBg, mConfigNumReservedSlots.get(WORK_TYPE_BG) - resBg)));
+ resBg += fillUp;
+ mNumUnspecializedRemaining -= fillUp;
+ final int numBgUser = runBgUser + mNumPendingJobs.get(WORK_TYPE_BGUSER);
+ fillUp = Math.max(0, Math.min(mNumUnspecializedRemaining,
+ Math.min(numBgUser,
+ mConfigNumReservedSlots.get(WORK_TYPE_BGUSER) - resBgUser)));
+ resBgUser += fillUp;
+ mNumUnspecializedRemaining -= fillUp;
+
+ // Step 3
+ int unspecializedAssigned = Math.max(0,
Math.min(mNumUnspecializedRemaining,
Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP), numTop) - resTop));
mNumActuallyReservedSlots.put(WORK_TYPE_TOP, resTop + unspecializedAssigned);
mNumUnspecializedRemaining -= unspecializedAssigned;
+
+ unspecializedAssigned = Math.max(0,
+ Math.min(mNumUnspecializedRemaining,
+ Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_EJ), numEj) - resEj));
+ mNumActuallyReservedSlots.put(WORK_TYPE_EJ, resEj + unspecializedAssigned);
+ mNumUnspecializedRemaining -= unspecializedAssigned;
+
unspecializedAssigned = Math.max(0,
Math.min(mNumUnspecializedRemaining,
Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG), numBg) - resBg));
mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg + unspecializedAssigned);
mNumUnspecializedRemaining -= unspecializedAssigned;
+
+ unspecializedAssigned = Math.max(0,
+ Math.min(mNumUnspecializedRemaining,
+ Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER), numBgUser)
+ - resBgUser));
+ mNumActuallyReservedSlots.put(WORK_TYPE_BGUSER, resBgUser + unspecializedAssigned);
+ mNumUnspecializedRemaining -= unspecializedAssigned;
}
int canJobStart(int workTypes) {
@@ -1072,6 +1279,15 @@ class JobConcurrencyManager {
return WORK_TYPE_TOP;
}
}
+ if ((workTypes & WORK_TYPE_EJ) == WORK_TYPE_EJ) {
+ final int maxAllowed = Math.min(
+ mConfigAbsoluteMaxSlots.get(WORK_TYPE_EJ),
+ mNumActuallyReservedSlots.get(WORK_TYPE_EJ) + mNumUnspecializedRemaining);
+ if (mNumRunningJobs.get(WORK_TYPE_EJ) + mNumStartingJobs.get(WORK_TYPE_EJ)
+ < maxAllowed) {
+ return WORK_TYPE_EJ;
+ }
+ }
if ((workTypes & WORK_TYPE_BG) == WORK_TYPE_BG) {
final int maxAllowed = Math.min(
mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG),
@@ -1081,6 +1297,16 @@ class JobConcurrencyManager {
return WORK_TYPE_BG;
}
}
+ if ((workTypes & WORK_TYPE_BGUSER) == WORK_TYPE_BGUSER) {
+ final int maxAllowed = Math.min(
+ mConfigAbsoluteMaxSlots.get(WORK_TYPE_BGUSER),
+ mNumActuallyReservedSlots.get(WORK_TYPE_BGUSER)
+ + mNumUnspecializedRemaining);
+ if (mNumRunningJobs.get(WORK_TYPE_BGUSER) + mNumStartingJobs.get(WORK_TYPE_BGUSER)
+ < maxAllowed) {
+ return WORK_TYPE_BGUSER;
+ }
+ }
return WORK_TYPE_NONE;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 7ce867c6c850..bfc153f5f2f7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -743,6 +743,7 @@ public class JobSchedulerService extends com.android.server.SystemService
mControllers.get(c).onUserRemovedLocked(userId);
}
}
+ mConcurrencyManager.onUserRemoved(userId);
} else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
// Has this package scheduled any jobs, such that we will take action
// if it were to be force-stopped?
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
index 8b9990f9e833..67fa9bb55202 100644
--- a/apex/media/framework/api/current.txt
+++ b/apex/media/framework/api/current.txt
@@ -29,6 +29,7 @@ package android.media {
}
public class MediaCommunicationManager {
+ method @IntRange(from=1) public int getVersion();
}
public class MediaController2 implements java.lang.AutoCloseable {
diff --git a/apex/media/framework/java/android/media/MediaCommunicationManager.java b/apex/media/framework/java/android/media/MediaCommunicationManager.java
index b8065ef8c597..e686076c871c 100644
--- a/apex/media/framework/java/android/media/MediaCommunicationManager.java
+++ b/apex/media/framework/java/android/media/MediaCommunicationManager.java
@@ -15,6 +15,7 @@
*/
package android.media;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemService;
import android.content.Context;
@@ -30,6 +31,16 @@ import com.android.modules.utils.build.SdkLevel;
public class MediaCommunicationManager {
private static final String TAG = "MediaCommunicationManager";
+ /**
+ * The manager version used from beginning.
+ */
+ private static final int VERSION_1 = 1;
+
+ /**
+ * Current manager version.
+ */
+ private static final int CURRENT_VERSION = VERSION_1;
+
private final Context mContext;
private final IMediaCommunicationService mService;
@@ -43,7 +54,14 @@ public class MediaCommunicationManager {
mContext = context;
mService = IMediaCommunicationService.Stub.asInterface(
MediaFrameworkInitializer.getMediaServiceManager()
- .getMediaCommunicationServiceRegisterer()
- .get());
+ .getMediaCommunicationServiceRegisterer()
+ .get());
+ }
+
+ /**
+ * Gets the version of this {@link MediaCommunicationManager}.
+ */
+ public @IntRange(from = 1) int getVersion() {
+ return CURRENT_VERSION;
}
}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index a7396faf7677..be82b2230183 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -43,7 +43,7 @@
#include <android-base/properties.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -65,6 +65,8 @@
namespace android {
+using ui::DisplayMode;
+
static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
static const char PRODUCT_BOOTANIMATION_DARK_FILE[] = "/product/media/bootanimation-dark.zip";
static const char PRODUCT_BOOTANIMATION_FILE[] = "/product/media/bootanimation.zip";
@@ -345,14 +347,14 @@ public:
continue;
}
- DisplayConfig displayConfig;
- const status_t error = SurfaceComposerClient::getActiveDisplayConfig(
- mBootAnimation->mDisplayToken, &displayConfig);
+ DisplayMode displayMode;
+ const status_t error = SurfaceComposerClient::getActiveDisplayMode(
+ mBootAnimation->mDisplayToken, &displayMode);
if (error != NO_ERROR) {
- SLOGE("Can't get active display configuration.");
+ SLOGE("Can't get active display mode.");
}
- mBootAnimation->resizeSurface(displayConfig.resolution.getWidth(),
- displayConfig.resolution.getHeight());
+ mBootAnimation->resizeSurface(displayMode.resolution.getWidth(),
+ displayMode.resolution.getHeight());
}
}
} while (numEvents > 0);
@@ -401,15 +403,15 @@ status_t BootAnimation::readyToRun() {
if (mDisplayToken == nullptr)
return NAME_NOT_FOUND;
- DisplayConfig displayConfig;
+ DisplayMode displayMode;
const status_t error =
- SurfaceComposerClient::getActiveDisplayConfig(mDisplayToken, &displayConfig);
+ SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &displayMode);
if (error != NO_ERROR)
return error;
mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
- ui::Size resolution = displayConfig.resolution;
+ ui::Size resolution = displayMode.resolution;
resolution = limitSurfaceSize(resolution.width, resolution.height);
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
diff --git a/core/api/current.txt b/core/api/current.txt
index f5c67c170931..838dd55e34d5 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1100,6 +1100,7 @@ package android {
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int preserveLegacyExternalStorage = 16844308; // 0x1010614
field public static final int previewImage = 16843482; // 0x10102da
+ field public static final int previewLayout = 16844327; // 0x1010627
field public static final int primaryContentAlpha = 16844114; // 0x1010552
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
@@ -8386,6 +8387,7 @@ package android.appwidget {
field public int minResizeWidth;
field public int minWidth;
field public int previewImage;
+ field @IdRes public int previewLayout;
field public android.content.ComponentName provider;
field public int resizeMode;
field public int updatePeriodMillis;
@@ -15795,6 +15797,7 @@ package android.graphics {
method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter);
method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float);
method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float, @NonNull android.graphics.RenderEffect);
+ method @NonNull public static android.graphics.RenderEffect createShaderEffect(@NonNull android.graphics.Shader);
}
public final class RenderNode {
@@ -20477,6 +20480,7 @@ package android.media {
field public static final int QUALITY_480P = 4; // 0x4
field public static final int QUALITY_4KDCI = 10; // 0xa
field public static final int QUALITY_720P = 5; // 0x5
+ field public static final int QUALITY_8KUHD = 13; // 0xd
field public static final int QUALITY_CIF = 3; // 0x3
field public static final int QUALITY_HIGH = 1; // 0x1
field public static final int QUALITY_HIGH_SPEED_1080P = 2004; // 0x7d4
@@ -20498,6 +20502,7 @@ package android.media {
field public static final int QUALITY_TIME_LAPSE_480P = 1004; // 0x3ec
field public static final int QUALITY_TIME_LAPSE_4KDCI = 1010; // 0x3f2
field public static final int QUALITY_TIME_LAPSE_720P = 1005; // 0x3ed
+ field public static final int QUALITY_TIME_LAPSE_8KUHD = 1013; // 0x3f5
field public static final int QUALITY_TIME_LAPSE_CIF = 1003; // 0x3eb
field public static final int QUALITY_TIME_LAPSE_HIGH = 1001; // 0x3e9
field public static final int QUALITY_TIME_LAPSE_LOW = 1000; // 0x3e8
@@ -42724,7 +42729,11 @@ package android.telephony.ims {
}
public class ImsRcsManager {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @NonNull public android.telephony.ims.RcsUceAdapter getUceAdapter();
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
field public static final String ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN = "android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 4d24cad699b6..5bb3e0517032 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1990,6 +1990,7 @@ package android.bluetooth {
field public static final int UUID_BYTES_128_BIT = 16; // 0x10
field public static final int UUID_BYTES_16_BIT = 2; // 0x2
field public static final int UUID_BYTES_32_BIT = 4; // 0x4
+ field @NonNull public static final android.os.ParcelUuid VOLUME_CONTROL;
}
public final class BufferConstraint implements android.os.Parcelable {
@@ -4666,6 +4667,7 @@ package android.location {
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String);
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+ method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerProviderRequestListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.Listener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
@@ -4674,6 +4676,7 @@ package android.location {
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
+ method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void unregisterProviderRequestListener(@NonNull android.location.provider.ProviderRequest.Listener);
}
public final class LocationRequest implements android.os.Parcelable {
@@ -4823,6 +4826,10 @@ package android.location.provider {
method @NonNull public android.location.provider.ProviderRequest.Builder setWorkSource(@NonNull android.os.WorkSource);
}
+ public static interface ProviderRequest.Listener {
+ method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest);
+ }
+
}
package android.media {
@@ -12952,6 +12959,17 @@ package android.telephony.ims {
method @Deprecated public void onRegistering(int);
}
+ public class ImsRcsManager {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addOnAvailabilityChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsRcsManager.OnAvailabilityChangedListener) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(int, int) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(int, int) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnAvailabilityChangedListener(@NonNull android.telephony.ims.ImsRcsManager.OnAvailabilityChangedListener);
+ }
+
+ public static interface ImsRcsManager.OnAvailabilityChangedListener {
+ method public void onAvailabilityChanged(int);
+ }
+
public final class ImsReasonInfo implements android.os.Parcelable {
field public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED = "Forbidden. Not Authorized for Service";
}
@@ -13592,11 +13610,24 @@ package android.telephony.ims.feature {
ctor public RcsFeature(@NonNull java.util.concurrent.Executor);
method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener);
+ method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities);
method public void onFeatureReady();
method public void onFeatureRemoved();
+ method public boolean queryCapabilityConfiguration(int, int);
+ method @NonNull public final android.telephony.ims.feature.RcsFeature.RcsImsCapabilities queryCapabilityStatus();
method public void removeCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase);
}
+ public static class RcsFeature.RcsImsCapabilities extends android.telephony.ims.feature.ImsFeature.Capabilities {
+ ctor public RcsFeature.RcsImsCapabilities(int);
+ method public void addCapabilities(int);
+ method public boolean isCapable(int);
+ method public void removeCapabilities(int);
+ field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0
+ field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1
+ field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
+ }
+
}
package android.telephony.ims.stub {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index fb27f74211fb..af5df769ffad 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -7,3 +7,8 @@ filegroup {
name: "IDropBoxManagerService.aidl",
srcs: ["com/android/internal/os/IDropBoxManagerService.aidl"],
}
+
+filegroup {
+ name: "ITracingServiceProxy.aidl",
+ srcs: ["android/tracing/ITracingServiceProxy.aidl"],
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e5a04c98b9e7..0774ac134d1b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5685,6 +5685,13 @@ public final class ActivityThread extends ClientTransactionHandler {
final Configuration finalOverrideConfig = createNewConfigAndUpdateIfNotNull(
amOverrideConfig, contextThemeWrapperOverrideConfig);
mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig, displayId);
+ final Resources res = activity.getResources();
+ if (res.hasOverrideDisplayAdjustments()) {
+ // If fixed rotation is applied while the activity is visible (e.g. PiP), the rotated
+ // configuration of activity may be sent later than the adjustments. In this case, the
+ // adjustments need to be updated for the consistency of display info.
+ res.getDisplayAdjustments().getConfiguration().updateFrom(finalOverrideConfig);
+ }
activity.mConfigChangeFlags = 0;
activity.mCurrentConfig = new Configuration(newConfig);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 82255c87c971..ff41d1c84e91 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -13328,6 +13328,7 @@ public class DevicePolicyManager {
* @return true if the app can grant device sensors-related permissions, false otherwise.
*/
public boolean canAdminGrantSensorsPermissions() {
+ throwIfParentInstance("canAdminGrantSensorsPermissions");
return canAdminGrantSensorsPermissionsForUser(myUserId());
}
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index e96e22c4764a..42214d047740 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -247,12 +247,29 @@ public class AppWidgetProviderInfo implements Parcelable {
* A preview of what the AppWidget will look like after it's configured.
* If not supplied, the AppWidget's icon will be used.
*
- * <p>This field corresponds to the <code>android:previewImage</code> attribute in
- * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ * <p>This field corresponds to the <code>android:previewImage</code> attribute in the AppWidget
+ * meta-data file.
*/
public int previewImage;
/**
+ * The layout resource id of a preview of what the AppWidget will look like after it's
+ * configured.
+ *
+ * <p>Unlike previewImage, previewLayout can better showcase AppWidget in different locales,
+ * system themes, display sizes & density etc.
+ *
+ * <p>If supplied, this will take precedence over the previewImage on supported widget hosts.
+ * Otherwise, previewImage will be used.
+ *
+ * <p>This field corresponds to the <code>android:previewLayout</code> attribute in the
+ * AppWidget meta-data file.
+ */
+ @SuppressLint("MutableBareField")
+ @IdRes
+ public int previewLayout;
+
+ /**
* The rules by which a widget can be resized. See {@link #RESIZE_NONE},
* {@link #RESIZE_NONE}, {@link #RESIZE_HORIZONTAL},
* {@link #RESIZE_VERTICAL}, {@link #RESIZE_BOTH}.
@@ -320,6 +337,7 @@ public class AppWidgetProviderInfo implements Parcelable {
this.label = in.readString();
this.icon = in.readInt();
this.previewImage = in.readInt();
+ this.previewLayout = in.readInt();
this.autoAdvanceViewId = in.readInt();
this.resizeMode = in.readInt();
this.widgetCategory = in.readInt();
@@ -429,6 +447,7 @@ public class AppWidgetProviderInfo implements Parcelable {
out.writeString(this.label);
out.writeInt(this.icon);
out.writeInt(this.previewImage);
+ out.writeInt(this.previewLayout);
out.writeInt(this.autoAdvanceViewId);
out.writeInt(this.resizeMode);
out.writeInt(this.widgetCategory);
@@ -453,6 +472,7 @@ public class AppWidgetProviderInfo implements Parcelable {
that.label = this.label;
that.icon = this.icon;
that.previewImage = this.previewImage;
+ that.previewLayout = this.previewLayout;
that.autoAdvanceViewId = this.autoAdvanceViewId;
that.resizeMode = this.resizeMode;
that.widgetCategory = this.widgetCategory;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 7eda50e5c9cb..ea7e5ea7c802 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3198,6 +3198,61 @@ public final class BluetoothAdapter {
}
/**
+ * Register a callback to receive events whenever the bluetooth stack goes down and back up,
+ * e.g. in the event the bluetooth is turned off/on via settings.
+ *
+ * If the bluetooth stack is currently up, there will not be an initial callback call.
+ * You can use the return value as an indication of this being the case.
+ *
+ * Callbacks will be delivered on a binder thread.
+ *
+ * @return whether bluetooth is already up currently
+ *
+ * @hide
+ */
+ public boolean registerServiceLifecycleCallback(ServiceLifecycleCallback callback) {
+ return getBluetoothService(callback.mRemote) != null;
+ }
+
+ /**
+ * Unregister a callback registered via {@link #registerServiceLifecycleCallback}
+ *
+ * @hide
+ */
+ public void unregisterServiceLifecycleCallback(ServiceLifecycleCallback callback) {
+ removeServiceStateCallback(callback.mRemote);
+ }
+
+ /**
+ * A callback for {@link #registerServiceLifecycleCallback}
+ *
+ * @hide
+ */
+ public abstract static class ServiceLifecycleCallback {
+
+ /** Called when the bluetooth stack is up */
+ public abstract void onBluetoothServiceUp();
+
+ /** Called when the bluetooth stack is down */
+ public abstract void onBluetoothServiceDown();
+
+ IBluetoothManagerCallback mRemote = new IBluetoothManagerCallback.Stub() {
+ @Override
+ public void onBluetoothServiceUp(IBluetooth bluetoothService) {
+ ServiceLifecycleCallback.this.onBluetoothServiceUp();
+ }
+
+ @Override
+ public void onBluetoothServiceDown() {
+ ServiceLifecycleCallback.this.onBluetoothServiceDown();
+ }
+
+ @Override
+ public void onBrEdrDown() {}
+ };
+ }
+
+ /**
* Starts a scan for Bluetooth LE devices.
*
* <p>Results of the scan are reported using the
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index c0736a6b7bba..d82cf19e8822 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -167,6 +167,11 @@ public final class BluetoothUuid {
/** @hide */
@NonNull
@SystemApi
+ public static final ParcelUuid VOLUME_CONTROL =
+ ParcelUuid.fromString("00001844-0000-1000-8000-00805F9B34FB");
+ /** @hide */
+ @NonNull
+ @SystemApi
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/core/java/android/companion/Association.java b/core/java/android/companion/Association.java
index 17bf11b3d4ef..960a08755cb8 100644
--- a/core/java/android/companion/Association.java
+++ b/core/java/android/companion/Association.java
@@ -38,7 +38,7 @@ public final class Association implements Parcelable {
private final @NonNull String mDeviceMacAddress;
private final @NonNull String mPackageName;
private final @Nullable String mDeviceProfile;
- private final boolean mKeepProfilePrivilegesWhenDeviceAway;
+ private final boolean mNotifyOnDeviceNearby;
/** @hide */
public int getUserId() {
@@ -47,7 +47,7 @@ public final class Association implements Parcelable {
- // Code below generated by codegen v1.0.21.
+ // Code below generated by codegen v1.0.22.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -71,7 +71,7 @@ public final class Association implements Parcelable {
@NonNull String deviceMacAddress,
@NonNull String packageName,
@Nullable String deviceProfile,
- boolean keepProfilePrivilegesWhenDeviceAway) {
+ boolean notifyOnDeviceNearby) {
this.mUserId = userId;
com.android.internal.util.AnnotationValidations.validate(
UserIdInt.class, null, mUserId);
@@ -82,7 +82,7 @@ public final class Association implements Parcelable {
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPackageName);
this.mDeviceProfile = deviceProfile;
- this.mKeepProfilePrivilegesWhenDeviceAway = keepProfilePrivilegesWhenDeviceAway;
+ this.mNotifyOnDeviceNearby = notifyOnDeviceNearby;
// onConstructed(); // You can define this method to get a callback
}
@@ -103,8 +103,8 @@ public final class Association implements Parcelable {
}
@DataClass.Generated.Member
- public boolean isKeepProfilePrivilegesWhenDeviceAway() {
- return mKeepProfilePrivilegesWhenDeviceAway;
+ public boolean isNotifyOnDeviceNearby() {
+ return mNotifyOnDeviceNearby;
}
@Override
@@ -118,7 +118,7 @@ public final class Association implements Parcelable {
"deviceMacAddress = " + mDeviceMacAddress + ", " +
"packageName = " + mPackageName + ", " +
"deviceProfile = " + mDeviceProfile + ", " +
- "keepProfilePrivilegesWhenDeviceAway = " + mKeepProfilePrivilegesWhenDeviceAway +
+ "notifyOnDeviceNearby = " + mNotifyOnDeviceNearby +
" }";
}
@@ -139,7 +139,7 @@ public final class Association implements Parcelable {
&& Objects.equals(mDeviceMacAddress, that.mDeviceMacAddress)
&& Objects.equals(mPackageName, that.mPackageName)
&& Objects.equals(mDeviceProfile, that.mDeviceProfile)
- && mKeepProfilePrivilegesWhenDeviceAway == that.mKeepProfilePrivilegesWhenDeviceAway;
+ && mNotifyOnDeviceNearby == that.mNotifyOnDeviceNearby;
}
@Override
@@ -153,7 +153,7 @@ public final class Association implements Parcelable {
_hash = 31 * _hash + Objects.hashCode(mDeviceMacAddress);
_hash = 31 * _hash + Objects.hashCode(mPackageName);
_hash = 31 * _hash + Objects.hashCode(mDeviceProfile);
- _hash = 31 * _hash + Boolean.hashCode(mKeepProfilePrivilegesWhenDeviceAway);
+ _hash = 31 * _hash + Boolean.hashCode(mNotifyOnDeviceNearby);
return _hash;
}
@@ -164,7 +164,7 @@ public final class Association implements Parcelable {
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (mKeepProfilePrivilegesWhenDeviceAway) flg |= 0x10;
+ if (mNotifyOnDeviceNearby) flg |= 0x10;
if (mDeviceProfile != null) flg |= 0x8;
dest.writeByte(flg);
dest.writeInt(mUserId);
@@ -185,7 +185,7 @@ public final class Association implements Parcelable {
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
- boolean keepProfilePrivilegesWhenDeviceAway = (flg & 0x10) != 0;
+ boolean notifyOnDeviceNearby = (flg & 0x10) != 0;
int userId = in.readInt();
String deviceMacAddress = in.readString();
String packageName = in.readString();
@@ -201,7 +201,7 @@ public final class Association implements Parcelable {
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPackageName);
this.mDeviceProfile = deviceProfile;
- this.mKeepProfilePrivilegesWhenDeviceAway = keepProfilePrivilegesWhenDeviceAway;
+ this.mNotifyOnDeviceNearby = notifyOnDeviceNearby;
// onConstructed(); // You can define this method to get a callback
}
@@ -221,10 +221,10 @@ public final class Association implements Parcelable {
};
@DataClass.Generated(
- time = 1606940835778L,
- codegenVersion = "1.0.21",
+ time = 1610482674799L,
+ codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/companion/Association.java",
- inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mDeviceProfile\nprivate final boolean mKeepProfilePrivilegesWhenDeviceAway\npublic int getUserId()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mDeviceProfile\nprivate final boolean mNotifyOnDeviceNearby\npublic int getUserId()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 9bae1ff4b906..bbf421da6b48 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -854,8 +854,8 @@ public final class DisplayManager {
*
* @hide Requires signature permission.
*/
- public void setTemporaryBrightness(float brightness) {
- mGlobal.setTemporaryBrightness(brightness);
+ public void setTemporaryBrightness(int displayId, float brightness) {
+ mGlobal.setTemporaryBrightness(displayId, brightness);
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 77ae9471dfb0..60fe5825d6a1 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -636,13 +636,13 @@ public final class DisplayManagerGlobal {
* Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission.
* </p>
*
- * @param brightness The brightness value from 0 to 255.
+ * @param brightness The brightness value from 0.0f to 1.0f.
*
* @hide Requires signature permission.
*/
- public void setTemporaryBrightness(float brightness) {
+ public void setTemporaryBrightness(int displayId, float brightness) {
try {
- mDm.setTemporaryBrightness(brightness);
+ mDm.setTemporaryBrightness(displayId, brightness);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index a9f78fa03a6d..ff8a7208a9f0 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -116,7 +116,7 @@ interface IDisplayManager {
boolean isMinimalPostProcessingRequested(int displayId);
// Temporarily sets the display brightness.
- void setTemporaryBrightness(float brightness);
+ void setTemporaryBrightness(int displayId, float brightness);
// Temporarily sets the auto brightness adjustment factor.
void setTemporaryAutoBrightnessAdjustment(float adjustment);
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index c69c47f80d01..eaa38f3e862c 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -26,6 +26,7 @@ import android.os.CombinedVibrationEffect;
import android.hardware.input.IInputSensorEventListener;
import android.hardware.input.InputSensorInfo;
import android.os.IBinder;
+import android.os.IVibratorStateListener;
import android.os.VibrationEffect;
import android.view.InputDevice;
import android.view.InputEvent;
@@ -92,6 +93,8 @@ interface IInputManager {
void cancelVibrate(int deviceId, IBinder token);
int[] getVibratorIds(int deviceId);
boolean isVibrating(int deviceId);
+ boolean registerVibratorStateListener(int deviceId, in IVibratorStateListener listener);
+ boolean unregisterVibratorStateListener(int deviceId, in IVibratorStateListener listener);
// Input device battery query.
int getBatteryStatus(int deviceId);
diff --git a/core/java/android/hardware/input/InputDeviceVibrator.java b/core/java/android/hardware/input/InputDeviceVibrator.java
index c60d6ce46fdb..f4d8a65d54c6 100644
--- a/core/java/android/hardware/input/InputDeviceVibrator.java
+++ b/core/java/android/hardware/input/InputDeviceVibrator.java
@@ -18,10 +18,18 @@ package android.hardware.input;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.app.ActivityThread;
+import android.content.Context;
import android.os.Binder;
+import android.os.IVibratorStateListener;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import java.util.concurrent.Executor;
@@ -29,12 +37,18 @@ import java.util.concurrent.Executor;
* Vibrator implementation that communicates with the input device vibrators.
*/
final class InputDeviceVibrator extends Vibrator {
+ private static final String TAG = "InputDeviceVibrator";
+
// mDeviceId represents InputDevice ID the vibrator belongs to
private final int mDeviceId;
private final int mVibratorId;
private final Binder mToken;
private final InputManager mInputManager;
+ @GuardedBy("mDelegates")
+ private final ArrayMap<OnVibratorStateChangedListener,
+ OnVibratorStateChangedListenerDelegate> mDelegates = new ArrayMap<>();
+
InputDeviceVibrator(InputManager inputManager, int deviceId, int vibratorId) {
mInputManager = inputManager;
mDeviceId = deviceId;
@@ -42,6 +56,23 @@ final class InputDeviceVibrator extends Vibrator {
mToken = new Binder();
}
+ private class OnVibratorStateChangedListenerDelegate extends
+ IVibratorStateListener.Stub {
+ private final Executor mExecutor;
+ private final OnVibratorStateChangedListener mListener;
+
+ OnVibratorStateChangedListenerDelegate(@NonNull OnVibratorStateChangedListener listener,
+ @NonNull Executor executor) {
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void onVibrating(boolean isVibrating) {
+ mExecutor.execute(() -> mListener.onVibratorStateChanged(isVibrating));
+ }
+ }
+
@Override
public boolean hasVibrator() {
return true;
@@ -52,25 +83,73 @@ final class InputDeviceVibrator extends Vibrator {
return mInputManager.isVibrating(mDeviceId);
}
- /* TODO: b/161634264 Support Vibrator listener API in input devices */
+ /**
+ * Adds a listener for vibrator state changes. Callbacks will be executed on the main thread.
+ * If the listener was previously added and not removed, this call will be ignored.
+ *
+ * @param listener listener to be added
+ */
@Override
public void addVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) {
- throw new UnsupportedOperationException(
- "addVibratorStateListener not supported in InputDeviceVibrator");
+ Preconditions.checkNotNull(listener);
+ Context context = ActivityThread.currentApplication();
+ addVibratorStateListener(context.getMainExecutor(), listener);
}
+ /**
+ * Adds a listener for vibrator state change. If the listener was previously added and not
+ * removed, this call will be ignored.
+ *
+ * @param listener Listener to be added.
+ * @param executor The {@link Executor} on which the listener's callbacks will be executed on.
+ */
@Override
public void addVibratorStateListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull OnVibratorStateChangedListener listener) {
- throw new UnsupportedOperationException(
- "addVibratorStateListener not supported in InputDeviceVibrator");
+ Preconditions.checkNotNull(listener);
+ Preconditions.checkNotNull(executor);
+
+ synchronized (mDelegates) {
+ // If listener is already registered, reject and return.
+ if (mDelegates.containsKey(listener)) {
+ Log.w(TAG, "Listener already registered.");
+ return;
+ }
+
+ final OnVibratorStateChangedListenerDelegate delegate =
+ new OnVibratorStateChangedListenerDelegate(listener, executor);
+ if (!mInputManager.registerVibratorStateListener(mDeviceId, delegate)) {
+ Log.w(TAG, "Failed to register vibrate state listener");
+ return;
+ }
+ mDelegates.put(listener, delegate);
+
+ }
}
+ /**
+ * Removes the listener for vibrator state changes. If the listener was not previously
+ * registered, this call will do nothing.
+ *
+ * @param listener Listener to be removed.
+ */
@Override
public void removeVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) {
- throw new UnsupportedOperationException(
- "removeVibratorStateListener not supported in InputDeviceVibrator");
+ Preconditions.checkNotNull(listener);
+
+ synchronized (mDelegates) {
+ // Check if the listener is registered, otherwise will return.
+ if (mDelegates.containsKey(listener)) {
+ final OnVibratorStateChangedListenerDelegate delegate = mDelegates.get(listener);
+
+ if (!mInputManager.unregisterVibratorStateListener(mDeviceId, delegate)) {
+ Log.w(TAG, "Failed to unregister vibrate state listener");
+ return;
+ }
+ mDelegates.remove(listener);
+ }
+ }
}
@Override
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 185c59d8ccfc..8a01c660ebd0 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -35,6 +35,7 @@ import android.os.Build;
import android.os.CombinedVibrationEffect;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IVibratorStateListener;
import android.os.InputEventInjectionSync;
import android.os.Looper;
import android.os.Message;
@@ -1484,6 +1485,32 @@ public final class InputManager {
}
/**
+ * Register input device vibrator state listener
+ *
+ * @hide
+ */
+ public boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
+ try {
+ return mIm.registerVibratorStateListener(deviceId, listener);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregister input device vibrator state listener
+ *
+ * @hide
+ */
+ public boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
+ try {
+ return mIm.unregisterVibratorStateListener(deviceId, listener);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Gets a sensor manager service associated with an input device, always create a new instance.
* @return The sensor manager, never null.
* @hide
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 5d8122b6ce90..32b19a462218 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -32,7 +32,7 @@ import java.util.Objects;
/**
* Network definition that includes strong identity. Analogous to combining
- * {@link NetworkInfo} and an IMSI.
+ * {@link NetworkCapabilities} and an IMSI.
*
* @hide
*/
@@ -160,7 +160,7 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
*/
public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state,
boolean defaultNetwork, @NetworkType int subType) {
- final int type = state.networkInfo.getType();
+ final int legacyType = state.legacyNetworkType;
String subscriberId = null;
String networkId = null;
@@ -171,7 +171,7 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
subscriberId = state.subscriberId;
- if (type == TYPE_WIFI) {
+ if (legacyType == TYPE_WIFI) {
if (state.networkCapabilities.getSsid() != null) {
networkId = state.networkCapabilities.getSsid();
if (networkId == null) {
@@ -184,7 +184,7 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
}
}
- return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered,
+ return new NetworkIdentity(legacyType, subType, subscriberId, networkId, roaming, metered,
defaultNetwork);
}
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index e1ef8b5ea5c9..e466d2e626be 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -41,6 +42,7 @@ public class NetworkState implements Parcelable {
public final Network network;
public final String subscriberId;
public final String networkId;
+ public final int legacyNetworkType;
private NetworkState() {
networkInfo = null;
@@ -49,17 +51,35 @@ public class NetworkState implements Parcelable {
network = null;
subscriberId = null;
networkId = null;
+ legacyNetworkType = 0;
}
+ public NetworkState(int legacyNetworkType, @NonNull LinkProperties linkProperties,
+ @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
+ @Nullable String subscriberId, @Nullable String networkId) {
+ this(legacyNetworkType, new NetworkInfo(legacyNetworkType, 0, null, null), linkProperties,
+ networkCapabilities, network, subscriberId, networkId);
+ }
+
+ // Constructor that used internally in ConnectivityService mainline module.
public NetworkState(@NonNull NetworkInfo networkInfo, @NonNull LinkProperties linkProperties,
@NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
String subscriberId, String networkId) {
+ this(networkInfo.getType(), networkInfo, linkProperties,
+ networkCapabilities, network, subscriberId, networkId);
+ }
+
+ public NetworkState(int legacyNetworkType, @NonNull NetworkInfo networkInfo,
+ @NonNull LinkProperties linkProperties,
+ @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
+ String subscriberId, String networkId) {
this.networkInfo = networkInfo;
this.linkProperties = linkProperties;
this.networkCapabilities = networkCapabilities;
this.network = network;
this.subscriberId = subscriberId;
this.networkId = networkId;
+ this.legacyNetworkType = legacyNetworkType;
// This object is an atomic view of a network, so the various components
// should always agree on roaming state.
@@ -80,6 +100,7 @@ public class NetworkState implements Parcelable {
network = in.readParcelable(null);
subscriberId = in.readString();
networkId = in.readString();
+ legacyNetworkType = in.readInt();
}
@Override
@@ -95,6 +116,7 @@ public class NetworkState implements Parcelable {
out.writeParcelable(network, flags);
out.writeString(subscriberId);
out.writeString(networkId);
+ out.writeInt(legacyNetworkType);
}
@UnsupportedAppUsage
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9603f4d43d8b..a29fcb17b083 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13580,28 +13580,6 @@ public final class Settings {
public static final String POWER_BUTTON_VERY_LONG_PRESS =
"power_button_very_long_press";
-
- /**
- * Keyguard should be on the left hand side of the screen, for wide screen layouts.
- *
- * @hide
- */
- public static final int ONE_HANDED_KEYGUARD_SIDE_LEFT = 0;
-
- /**
- * Keyguard should be on the right hand side of the screen, for wide screen layouts.
- *
- * @hide
- */
- public static final int ONE_HANDED_KEYGUARD_SIDE_RIGHT = 1;
- /**
- * In one handed mode, which side the keyguard should be on. Allowable values are one of
- * the ONE_HANDED_KEYGUARD_SIDE_* constants.
- *
- * @hide
- */
- public static final String ONE_HANDED_KEYGUARD_SIDE = "one_handed_keyguard_side";
-
/**
* Keys we no longer back up under the current schema, but want to continue to
* process when restoring historical backup datasets.
diff --git a/core/java/android/rotationresolver/RotationResolverInternal.java b/core/java/android/rotationresolver/RotationResolverInternal.java
index db879a7e3f8f..1f1a66c17d97 100644
--- a/core/java/android/rotationresolver/RotationResolverInternal.java
+++ b/core/java/android/rotationresolver/RotationResolverInternal.java
@@ -46,7 +46,6 @@ public abstract class RotationResolverInternal {
* error is captured. {@link RotationResolverCallbackInternal}
* @param proposedRotation the screen rotation that is proposed by the system.
* @param currentRotation the current screen rotation.
- * @param packageName the package name of the current activity that is running in foreground.
* @param timeoutMillis the timeout in millisecond for the query. If the query doesn't get
* fulfilled within this amount of time. It will be discarded and the
* callback will receive a failure result code {@link
@@ -55,8 +54,7 @@ public abstract class RotationResolverInternal {
*/
public abstract void resolveRotation(@NonNull RotationResolverCallbackInternal callback,
@Surface.Rotation int proposedRotation, @Surface.Rotation int currentRotation,
- String packageName, @DurationMillisLong long timeoutMillis,
- @NonNull CancellationSignal cancellationSignal);
+ @DurationMillisLong long timeoutMillis, @NonNull CancellationSignal cancellationSignal);
/**
* Internal interfaces for the rotation resolver callback.
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 44daeff76997..2b7cb1db174a 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -41,7 +41,7 @@ oneway interface INotificationListener
void onListenerHintsChanged(int hints);
void onInterruptionFilterChanged(int interruptionFilter);
- // companion device managers only
+ // companion device managers and assistants only
void onNotificationChannelModification(String pkgName, in UserHandle user, in NotificationChannel channel, int modificationType);
void onNotificationChannelGroupModification(String pkgName, in UserHandle user, in NotificationChannelGroup group, int modificationType);
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 2de755857b70..aef185c77633 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -36,6 +36,7 @@ import java.io.File;
import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
@@ -155,6 +156,32 @@ public final class FontConfig implements Parcelable {
}
};
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ FontConfig that = (FontConfig) o;
+ return mLastModifiedTimeMillis == that.mLastModifiedTimeMillis
+ && mConfigVersion == that.mConfigVersion
+ && Objects.equals(mFamilies, that.mFamilies)
+ && Objects.equals(mAliases, that.mAliases);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFamilies, mAliases, mLastModifiedTimeMillis, mConfigVersion);
+ }
+
+ @Override
+ public String toString() {
+ return "FontConfig{"
+ + "mFamilies=" + mFamilies
+ + ", mAliases=" + mAliases
+ + ", mLastModifiedTimeMillis=" + mLastModifiedTimeMillis
+ + ", mConfigVersion=" + mConfigVersion
+ + '}';
+ }
+
/**
* Represents single font entry in system font configuration.
*
@@ -317,6 +344,37 @@ public final class FontConfig implements Parcelable {
public boolean isItalic() {
return getStyle().getSlant() == FontStyle.FONT_SLANT_ITALIC;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Font font = (Font) o;
+ return mIndex == font.mIndex
+ && Objects.equals(mFile, font.mFile)
+ && Objects.equals(mOriginalFile, font.mOriginalFile)
+ && Objects.equals(mStyle, font.mStyle)
+ && Objects.equals(mFontVariationSettings, font.mFontVariationSettings)
+ && Objects.equals(mFontFamilyName, font.mFontFamilyName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFile, mOriginalFile, mStyle, mIndex, mFontVariationSettings,
+ mFontFamilyName);
+ }
+
+ @Override
+ public String toString() {
+ return "Font{"
+ + "mFile=" + mFile
+ + ", mOriginalFile=" + mOriginalFile
+ + ", mStyle=" + mStyle
+ + ", mIndex=" + mIndex
+ + ", mFontVariationSettings='" + mFontVariationSettings + '\''
+ + ", mFontFamilyName='" + mFontFamilyName + '\''
+ + '}';
+ }
}
/**
@@ -398,6 +456,30 @@ public final class FontConfig implements Parcelable {
return new Alias[size];
}
};
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Alias alias = (Alias) o;
+ return mWeight == alias.mWeight
+ && Objects.equals(mName, alias.mName)
+ && Objects.equals(mOriginal, alias.mOriginal);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mOriginal, mWeight);
+ }
+
+ @Override
+ public String toString() {
+ return "Alias{"
+ + "mName='" + mName + '\''
+ + ", mOriginal='" + mOriginal + '\''
+ + ", mWeight=" + mWeight
+ + '}';
+ }
}
/**
@@ -413,7 +495,7 @@ public final class FontConfig implements Parcelable {
public static final class FontFamily implements Parcelable {
private final @NonNull List<Font> mFonts;
private final @Nullable String mName;
- private final @Nullable LocaleList mLocaleList;
+ private final @NonNull LocaleList mLocaleList;
private final @Variant int mVariant;
/** @hide */
@@ -454,7 +536,7 @@ public final class FontConfig implements Parcelable {
* @hide Only system server can create this instance and passed via IPC.
*/
public FontFamily(@NonNull List<Font> fonts, @Nullable String name,
- @Nullable LocaleList localeList, @Variant int variant) {
+ @NonNull LocaleList localeList, @Variant int variant) {
mFonts = fonts;
mName = name;
mLocaleList = localeList;
@@ -493,8 +575,6 @@ public final class FontConfig implements Parcelable {
*
* The locale list will be used for deciding which font family should be used in fallback
* list.
- *
- * @return non-null if a locale list is available. Otherwise null.
*/
public @NonNull LocaleList getLocaleList() {
return mLocaleList;
@@ -559,5 +639,31 @@ public final class FontConfig implements Parcelable {
public @NonNull String getLanguages() {
return mLocaleList.toLanguageTags();
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ FontFamily that = (FontFamily) o;
+ return mVariant == that.mVariant
+ && Objects.equals(mFonts, that.mFonts)
+ && Objects.equals(mName, that.mName)
+ && Objects.equals(mLocaleList, that.mLocaleList);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFonts, mName, mLocaleList, mVariant);
+ }
+
+ @Override
+ public String toString() {
+ return "FontFamily{"
+ + "mFonts=" + mFonts
+ + ", mName='" + mName + '\''
+ + ", mLocaleList=" + mLocaleList
+ + ", mVariant=" + mVariant
+ + '}';
+ }
}
}
diff --git a/core/java/android/tracing/ITracingServiceProxy.aidl b/core/java/android/tracing/ITracingServiceProxy.aidl
new file mode 100644
index 000000000000..4520db3915a2
--- /dev/null
+++ b/core/java/android/tracing/ITracingServiceProxy.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.tracing;
+
+/**
+ * Binder interface for the TracingServiceProxy running in system_server.
+ *
+ * {@hide}
+ */
+interface ITracingServiceProxy
+{
+ /**
+ * Notifies system tracing app that a tracing session has ended. If a session is repurposed
+ * for use in a bugreport, sessionStolen can be set to indicate that tracing has ended but
+ * there is no buffer available to dump.
+ */
+ oneway void notifyTraceSessionEnded(boolean sessionStolen);
+}
diff --git a/core/java/android/tracing/OWNERS b/core/java/android/tracing/OWNERS
new file mode 100644
index 000000000000..f5de4eb05c54
--- /dev/null
+++ b/core/java/android/tracing/OWNERS
@@ -0,0 +1,2 @@
+cfijalkovich@google.com
+carmenjackson@google.com
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 790773fd83c5..b22921233f05 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -65,7 +65,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true");
DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
- DEFAULT_FLAGS.put("settings_silky_home", "true");
+ DEFAULT_FLAGS.put("settings_silky_home", "false");
DEFAULT_FLAGS.put("settings_contextual_home", "false");
DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "false");
}
diff --git a/core/java/android/uwb/SessionHandle.java b/core/java/android/uwb/SessionHandle.java
index 928fcbdcf1c7..b23f5ad603ff 100644
--- a/core/java/android/uwb/SessionHandle.java
+++ b/core/java/android/uwb/SessionHandle.java
@@ -19,6 +19,8 @@ package android.uwb;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* @hide
*/
@@ -73,6 +75,11 @@ public final class SessionHandle implements Parcelable {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(mId);
+ }
+
+ @Override
public String toString() {
return "SessionHandle [id=" + mId + "]";
}
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 5d4a4e52975a..e6cd25275ca2 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -58,11 +58,11 @@ public abstract class DisplayEventReceiver {
public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1;
/**
- * Specifies to generate config changed events from Surface Flinger.
+ * Specifies to generate mode changed events from Surface Flinger.
* <p>
* Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
*/
- public static final int EVENT_REGISTRATION_CONFIG_CHANGED_FLAG = 0x1;
+ public static final int EVENT_REGISTRATION_MODE_CHANGED_FLAG = 0x1;
/**
* Specifies to generate frame rate override events from Surface Flinger.
@@ -197,14 +197,14 @@ public abstract class DisplayEventReceiver {
}
/**
- * Called when a display config changed event is received.
+ * Called when a display mode changed event is received.
*
* @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
* timebase.
* @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
- * @param configId The new config Id
+ * @param modeId The new mode Id
*/
- public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
+ public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
}
/**
@@ -273,8 +273,8 @@ public abstract class DisplayEventReceiver {
// Called from native code.
@SuppressWarnings("unused")
- private void dispatchConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
- onConfigChanged(timestampNanos, physicalDisplayId, configId);
+ private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
+ onModeChanged(timestampNanos, physicalDisplayId, modeId);
}
// Called from native code.
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 24bc30874318..f8c4d1587f22 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -928,7 +928,9 @@ public class Surface implements Parcelable {
* seamless transition is one that doesn't have any visual interruptions, such as a black
* screen for a second or two. True indicates that any frame rate changes caused by this
* request should be seamless. False indicates that non-seamless refresh rates are also
- * acceptable.
+ * acceptable. Non-seamless switches might be used when the benefit of matching the content's
+ * frame rate outweighs the cost of the transition, for example when displaying
+ * long-running video content.
*
* @throws IllegalArgumentException If frameRate or compatibility are invalid.
*/
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 98b4acd302cb..6a629ca4e462 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -161,8 +161,8 @@ public final class SurfaceControl implements Parcelable {
int L, int T, int R, int B);
private static native void nativeSetDisplaySize(long transactionObj, IBinder displayToken,
int width, int height);
- private static native SurfaceControl.DisplayInfo nativeGetDisplayInfo(IBinder displayToken);
- private static native SurfaceControl.DisplayConfig[] nativeGetDisplayConfigs(
+ private static native DisplayInfo nativeGetDisplayInfo(IBinder displayToken);
+ private static native DisplayMode[] nativeGetDisplayModes(
IBinder displayToken);
private static native DisplayedContentSamplingAttributes
nativeGetDisplayedContentSamplingAttributes(IBinder displayToken);
@@ -170,13 +170,13 @@ public final class SurfaceControl implements Parcelable {
boolean enable, int componentMask, int maxFrames);
private static native DisplayedContentSample nativeGetDisplayedContentSample(
IBinder displayToken, long numFrames, long timestamp);
- private static native int nativeGetActiveConfig(IBinder displayToken);
- private static native boolean nativeSetDesiredDisplayConfigSpecs(IBinder displayToken,
- SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs);
- private static native SurfaceControl.DesiredDisplayConfigSpecs
- nativeGetDesiredDisplayConfigSpecs(IBinder displayToken);
+ private static native int nativeGetActiveDisplayMode(IBinder displayToken);
+ private static native boolean nativeSetDesiredDisplayModeSpecs(IBinder displayToken,
+ DesiredDisplayModeSpecs desiredDisplayModeSpecs);
+ private static native DesiredDisplayModeSpecs
+ nativeGetDesiredDisplayModeSpecs(IBinder displayToken);
private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
- private static native SurfaceControl.DisplayPrimaries nativeGetDisplayNativePrimaries(
+ private static native DisplayPrimaries nativeGetDisplayNativePrimaries(
IBinder displayToken);
private static native int[] nativeGetCompositionDataspaces();
private static native int nativeGetActiveColorMode(IBinder displayToken);
@@ -1743,11 +1743,11 @@ public final class SurfaceControl implements Parcelable {
*
* @hide
*/
- public static final class DisplayConfig {
+ public static final class DisplayMode {
/**
* Invalid display config id.
*/
- public static final int INVALID_DISPLAY_CONFIG_ID = -1;
+ public static final int INVALID_DISPLAY_MODE_ID = -1;
public int width;
public int height;
@@ -1764,7 +1764,7 @@ public final class SurfaceControl implements Parcelable {
* configs within the same group can be done seamlessly in most cases.
* @see: android.hardware.graphics.composer@2.4::IComposerClient::Attribute::CONFIG_GROUP
*/
- public int configGroup;
+ public int group;
@Override
public String toString() {
@@ -1775,7 +1775,7 @@ public final class SurfaceControl implements Parcelable {
+ ", refreshRate=" + refreshRate
+ ", appVsyncOffsetNanos=" + appVsyncOffsetNanos
+ ", presentationDeadlineNanos=" + presentationDeadlineNanos
- + ", configGroup=" + configGroup + "}";
+ + ", group=" + group + "}";
}
}
@@ -1802,21 +1802,21 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
- public static SurfaceControl.DisplayConfig[] getDisplayConfigs(IBinder displayToken) {
+ public static DisplayMode[] getDisplayModes(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetDisplayConfigs(displayToken);
+ return nativeGetDisplayModes(displayToken);
}
/**
* @hide
*/
- public static int getActiveConfig(IBinder displayToken) {
+ public static int getActiveDisplayMode(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetActiveConfig(displayToken);
+ return nativeGetActiveDisplayMode(displayToken);
}
/**
@@ -1863,8 +1863,8 @@ public final class SurfaceControl implements Parcelable {
*
* @hide
*/
- public static final class DesiredDisplayConfigSpecs {
- public int defaultConfig;
+ public static final class DesiredDisplayModeSpecs {
+ public int defaultMode;
/**
* The primary refresh rate range represents display manager's general guidance on the
* display configs surface flinger will consider when switching refresh rates. Unless
@@ -1889,16 +1889,16 @@ public final class SurfaceControl implements Parcelable {
*/
public boolean allowGroupSwitching;
- public DesiredDisplayConfigSpecs() {}
+ public DesiredDisplayModeSpecs() {}
- public DesiredDisplayConfigSpecs(DesiredDisplayConfigSpecs other) {
+ public DesiredDisplayModeSpecs(DesiredDisplayModeSpecs other) {
copyFrom(other);
}
- public DesiredDisplayConfigSpecs(int defaultConfig, boolean allowGroupSwitching,
+ public DesiredDisplayModeSpecs(int defaultMode, boolean allowGroupSwitching,
float primaryRefreshRateMin, float primaryRefreshRateMax,
float appRequestRefreshRateMin, float appRequestRefreshRateMax) {
- this.defaultConfig = defaultConfig;
+ this.defaultMode = defaultMode;
this.allowGroupSwitching = allowGroupSwitching;
this.primaryRefreshRateMin = primaryRefreshRateMin;
this.primaryRefreshRateMax = primaryRefreshRateMax;
@@ -1908,14 +1908,14 @@ public final class SurfaceControl implements Parcelable {
@Override
public boolean equals(@Nullable Object o) {
- return o instanceof DesiredDisplayConfigSpecs && equals((DesiredDisplayConfigSpecs) o);
+ return o instanceof DesiredDisplayModeSpecs && equals((DesiredDisplayModeSpecs) o);
}
/**
* Tests for equality.
*/
- public boolean equals(DesiredDisplayConfigSpecs other) {
- return other != null && defaultConfig == other.defaultConfig
+ public boolean equals(DesiredDisplayModeSpecs other) {
+ return other != null && defaultMode == other.defaultMode
&& primaryRefreshRateMin == other.primaryRefreshRateMin
&& primaryRefreshRateMax == other.primaryRefreshRateMax
&& appRequestRefreshRateMin == other.appRequestRefreshRateMin
@@ -1930,8 +1930,8 @@ public final class SurfaceControl implements Parcelable {
/**
* Copies the supplied object's values to this object.
*/
- public void copyFrom(DesiredDisplayConfigSpecs other) {
- defaultConfig = other.defaultConfig;
+ public void copyFrom(DesiredDisplayModeSpecs other) {
+ defaultMode = other.defaultMode;
primaryRefreshRateMin = other.primaryRefreshRateMin;
primaryRefreshRateMax = other.primaryRefreshRateMax;
appRequestRefreshRateMin = other.appRequestRefreshRateMin;
@@ -1942,7 +1942,7 @@ public final class SurfaceControl implements Parcelable {
public String toString() {
return String.format("defaultConfig=%d primaryRefreshRateRange=[%.0f %.0f]"
+ " appRequestRefreshRateRange=[%.0f %.0f]",
- defaultConfig, primaryRefreshRateMin, primaryRefreshRateMax,
+ defaultMode, primaryRefreshRateMin, primaryRefreshRateMax,
appRequestRefreshRateMin, appRequestRefreshRateMax);
}
}
@@ -1950,25 +1950,31 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
- public static boolean setDesiredDisplayConfigSpecs(IBinder displayToken,
- SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs) {
+ public static boolean setDesiredDisplayModeSpecs(IBinder displayToken,
+ DesiredDisplayModeSpecs desiredDisplayModeSpecs) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
+ if (desiredDisplayModeSpecs == null) {
+ throw new IllegalArgumentException("desiredDisplayModeSpecs must not be null");
+ }
+ if (desiredDisplayModeSpecs.defaultMode < 0) {
+ throw new IllegalArgumentException("defaultMode must be non-negative");
+ }
- return nativeSetDesiredDisplayConfigSpecs(displayToken, desiredDisplayConfigSpecs);
+ return nativeSetDesiredDisplayModeSpecs(displayToken, desiredDisplayModeSpecs);
}
/**
* @hide
*/
- public static SurfaceControl.DesiredDisplayConfigSpecs getDesiredDisplayConfigSpecs(
+ public static DesiredDisplayModeSpecs getDesiredDisplayModeSpecs(
IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeGetDesiredDisplayConfigSpecs(displayToken);
+ return nativeGetDesiredDisplayModeSpecs(displayToken);
}
/**
@@ -2039,7 +2045,7 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
- public static SurfaceControl.DisplayPrimaries getDisplayNativePrimaries(
+ public static DisplayPrimaries getDisplayNativePrimaries(
IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
@@ -3241,7 +3247,10 @@ public final class SurfaceControl implements Parcelable {
* interruptions, such as a black screen for a second or two. True
* indicates that any frame rate changes caused by this request
* should be seamless. False indicates that non-seamless refresh
- * rates are also acceptable.
+ * rates are also acceptable. Non-seamless switches might be
+ * used when the benefit of matching the content's frame rate
+ * outweighs the cost of the transition, for example when
+ * displaying long-running video content.
* @return This transaction object.
*/
@NonNull
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index f01964822897..18029af6a85e 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -162,7 +162,6 @@ public class SurfaceControlViewHost {
@NonNull WindowlessWindowManager wwm, boolean useSfChoreographer) {
mWm = wwm;
mViewRoot = new ViewRootImpl(c, d, mWm, useSfChoreographer);
- mViewRoot.forceDisableBLAST();
mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
}
@@ -188,7 +187,6 @@ public class SurfaceControlViewHost {
mWm = new WindowlessWindowManager(context.getResources().getConfiguration(),
mSurfaceControl, hostToken);
mViewRoot = new ViewRootImpl(context, display, mWm);
- mViewRoot.forceDisableBLAST();
mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection();
}
diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
index b10370aa5d4c..acbcbfad1a75 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -85,12 +85,13 @@ public class SyncRtSurfaceTransactionApplier {
for (int i = params.length - 1; i >= 0; i--) {
SurfaceParams surfaceParams = params[i];
SurfaceControl surface = surfaceParams.surface;
- if (frame > 0) {
- t.deferTransactionUntil(surface, mTargetSc, frame);
- }
applyParams(t, surfaceParams, mTmpFloat9);
}
- t.apply();
+ if (mTargetViewRootImpl != null) {
+ mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
+ } else {
+ t.apply();
+ }
}
public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 036a703f178c..56d98e78303e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -10137,9 +10137,11 @@ public final class ViewRootImpl implements ViewParent,
* Merges the transaction passed in with the next transaction in BLASTBufferQueue. This ensures
* you can add transactions to the upcoming frame.
*/
- void mergeWithNextTransaction(Transaction t, long frameNumber) {
+ public void mergeWithNextTransaction(Transaction t, long frameNumber) {
if (mBlastBufferQueue != null) {
mBlastBufferQueue.mergeWithNextTransaction(t, frameNumber);
+ } else {
+ t.apply();
}
}
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index b85f10799210..3aedda1a6bd3 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -71,7 +71,7 @@ public class WindowlessWindowManager implements IWindowSession {
new HashMap<IBinder, ResizeCompleteCallback>();
private final SurfaceSession mSurfaceSession = new SurfaceSession();
- private final SurfaceControl mRootSurface;
+ protected final SurfaceControl mRootSurface;
private final Configuration mConfiguration;
private final IWindowSession mRealWm;
private final IBinder mHostInputToken;
@@ -126,7 +126,7 @@ public class WindowlessWindowManager implements IWindowSession {
}
}
- protected void attachToParentSurface(SurfaceControl.Builder b) {
+ protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
b.setParent(mRootSurface);
}
@@ -140,10 +140,10 @@ public class WindowlessWindowManager implements IWindowSession {
InsetsSourceControl[] outActiveControls) {
final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
.setFormat(attrs.format)
- .setBufferSize(getSurfaceWidth(attrs), getSurfaceHeight(attrs))
+ .setBLASTLayer()
.setName(attrs.getTitle().toString())
.setCallsite("WindowlessWindowManager.addToDisplay");
- attachToParentSurface(b);
+ attachToParentSurface(window, b);
final SurfaceControl sc = b.build();
if (((attrs.inputFeatures &
@@ -162,7 +162,11 @@ public class WindowlessWindowManager implements IWindowSession {
mStateForWindow.put(window.asBinder(), state);
}
- return WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
+ final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE |
+ WindowManagerGlobal.ADD_FLAG_USE_BLAST;
+
+ // Include whether the window is in touch mode.
+ return isInTouchMode() ? res | WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE : res;
}
/**
@@ -210,6 +214,26 @@ public class WindowlessWindowManager implements IWindowSession {
return !PixelFormat.formatHasAlpha(attrs.format);
}
+ private boolean isInTouchMode() {
+ try {
+ return WindowManagerGlobal.getWindowSession().getInTouchMode();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to check if the window is in touch mode", e);
+ }
+ return false;
+ }
+
+ /** Access to package members for SystemWindow leashing
+ * @hide
+ */
+ protected IBinder getWindowBinder(View rootView) {
+ final ViewRootImpl root = rootView.getViewRootImpl();
+ if (root == null) {
+ return null;
+ }
+ return root.mWindow.asBinder();
+ }
+
/** @hide */
@Nullable
protected SurfaceControl getSurfaceControl(View rootView) {
@@ -254,8 +278,8 @@ public class WindowlessWindowManager implements IWindowSession {
WindowManager.LayoutParams attrs = state.mParams;
if (viewFlags == View.VISIBLE) {
- t.setBufferSize(sc, getSurfaceWidth(attrs), getSurfaceHeight(attrs))
- .setOpaque(sc, isOpaque(attrs)).show(sc).apply();
+ outSurfaceSize.set(getSurfaceWidth(attrs), getSurfaceHeight(attrs));
+ t.setOpaque(sc, isOpaque(attrs)).show(sc).apply();
outSurfaceControl.copyFrom(sc, "WindowlessWindowManager.relayout");
} else {
t.hide(sc).apply();
@@ -276,7 +300,8 @@ public class WindowlessWindowManager implements IWindowSession {
}
}
- return 0;
+ // Include whether the window is in touch mode.
+ return isInTouchMode() ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
}
@Override
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index 6300320f5eb5..0ab4e05227ba 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -19,6 +19,10 @@ package android.view.inputmethod;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.LocaleList;
@@ -69,7 +73,8 @@ public final class InlineSuggestionsRequest implements Parcelable {
/**
* The IME provided locales for the request. If non-empty, the inline suggestions should
- * return languages from the supported locales. If not provided, it'll default to system locale.
+ * return languages from the supported locales. If not provided, it'll default to be empty if
+ * target SDK is S or above, and default to system locale otherwise.
*
* <p>Note for Autofill Providers: It is <b>recommended</b> for the returned inline suggestions
* to have one locale to guarantee consistent UI rendering.</p>
@@ -156,7 +161,18 @@ public final class InlineSuggestionsRequest implements Parcelable {
return ActivityThread.currentPackageName();
}
+ /**
+ * The {@link InlineSuggestionsRequest#getSupportedLocales()} now returns empty locale list when
+ * it's not set, instead of the default system locale.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY = 169273070L;
+
private static LocaleList defaultSupportedLocales() {
+ if (CompatChanges.isChangeEnabled(IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY)) {
+ return LocaleList.getEmptyLocaleList();
+ }
return LocaleList.getDefault();
}
@@ -189,7 +205,7 @@ public final class InlineSuggestionsRequest implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.22.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -264,7 +280,8 @@ public final class InlineSuggestionsRequest implements Parcelable {
/**
* The IME provided locales for the request. If non-empty, the inline suggestions should
- * return languages from the supported locales. If not provided, it'll default to system locale.
+ * return languages from the supported locales. If not provided, it'll default to be empty if
+ * target SDK is S or above, and default to system locale otherwise.
*
* <p>Note for Autofill Providers: It is <b>recommended</b> for the returned inline suggestions
* to have one locale to guarantee consistent UI rendering.</p>
@@ -522,7 +539,8 @@ public final class InlineSuggestionsRequest implements Parcelable {
/**
* The IME provided locales for the request. If non-empty, the inline suggestions should
- * return languages from the supported locales. If not provided, it'll default to system locale.
+ * return languages from the supported locales. If not provided, it'll default to be empty if
+ * target SDK is S or above, and default to system locale otherwise.
*
* <p>Note for Autofill Providers: It is <b>recommended</b> for the returned inline suggestions
* to have one locale to guarantee consistent UI rendering.</p>
@@ -622,10 +640,10 @@ public final class InlineSuggestionsRequest implements Parcelable {
}
@DataClass.Generated(
- time = 1595457701315L,
- codegenVersion = "1.0.15",
+ time = 1612206506050L,
+ codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
- inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\nprivate static final @android.compat.annotation.ChangeId @android.compat.annotation.EnabledSince long IME_AUTOFILL_DEFAULT_SUPPORTED_LOCALES_IS_EMPTY\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
index 015238788191..c2ee6461e5e1 100644
--- a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
+++ b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
@@ -53,8 +53,10 @@ public class HeavyWeightSwitcherActivity extends Activity {
public static final String KEY_CUR_TASK = "cur_task";
/** Package of newly requested heavy-weight app. */
public static final String KEY_NEW_APP = "new_app";
+ public static final String KEY_ACTIVITY_OPTIONS = "activity_options";
IntentSender mStartIntent;
+ Bundle mActivityOptions;
boolean mHasResult;
String mCurApp;
int mCurTask;
@@ -65,8 +67,9 @@ public class HeavyWeightSwitcherActivity extends Activity {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
-
+
mStartIntent = (IntentSender)getIntent().getParcelableExtra(KEY_INTENT);
+ mActivityOptions = getIntent().getBundleExtra(KEY_ACTIVITY_OPTIONS);
mHasResult = getIntent().getBooleanExtra(KEY_HAS_RESULT, false);
mCurApp = getIntent().getStringExtra(KEY_CUR_APP);
mCurTask = getIntent().getIntExtra(KEY_CUR_TASK, 0);
@@ -148,9 +151,9 @@ public class HeavyWeightSwitcherActivity extends Activity {
if (mHasResult) {
startIntentSenderForResult(mStartIntent, -1, null,
Intent.FLAG_ACTIVITY_FORWARD_RESULT,
- Intent.FLAG_ACTIVITY_FORWARD_RESULT, 0);
+ Intent.FLAG_ACTIVITY_FORWARD_RESULT, 0, mActivityOptions);
} else {
- startIntentSenderForResult(mStartIntent, -1, null, 0, 0, 0);
+ startIntentSenderForResult(mStartIntent, -1, null, 0, 0, 0, mActivityOptions);
}
} catch (IntentSender.SendIntentException ex) {
Log.w("HeavyWeightSwitcherActivity", "Failure starting", ex);
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index fc95275c2e1b..af21f8183d3a 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -726,4 +726,43 @@ public interface ServiceConnector<I extends IInterface> {
}
}
}
+
+ /**
+ * A {@link ServiceConnector} that doesn't connect to anything.
+ *
+ * @param <T> the type of the {@link IInterface ipc interface} for the remote service
+ */
+ class NoOp<T extends IInterface> extends AndroidFuture<Object> implements ServiceConnector<T> {
+ {
+ completeExceptionally(new IllegalStateException("ServiceConnector is a no-op"));
+ }
+
+ @Override
+ public boolean run(@NonNull VoidJob<T> job) {
+ return false;
+ }
+
+ @Override
+ public AndroidFuture<Void> post(@NonNull VoidJob<T> job) {
+ return (AndroidFuture) this;
+ }
+
+ @Override
+ public <R> AndroidFuture<R> postForResult(@NonNull Job<T, R> job) {
+ return (AndroidFuture) this;
+ }
+
+ @Override
+ public <R> AndroidFuture<R> postAsync(@NonNull Job<T, CompletableFuture<R>> job) {
+ return (AndroidFuture) this;
+ }
+
+ @Override
+ public AndroidFuture<T> connect() {
+ return (AndroidFuture) this;
+ }
+
+ @Override
+ public void unbind() {}
+ }
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 3d896c866c8b..6e9bc84156f1 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -18,10 +18,12 @@ package com.android.internal.jank;
import static com.android.internal.jank.FrameTracker.ChoreographerWrapper;
import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_ICON;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_APPEAR;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PASSWORD_DISAPPEAR;
@@ -114,6 +116,8 @@ public class InteractionJankMonitor {
public static final int CUJ_LOCKSCREEN_PIN_DISAPPEAR = 22;
public static final int CUJ_LOCKSCREEN_TRANSITION_FROM_AOD = 23;
public static final int CUJ_LOCKSCREEN_TRANSITION_TO_AOD = 24;
+ public static final int CUJ_LAUNCHER_OPEN_ALL_APPS = 25;
+ public static final int CUJ_LAUNCHER_ALL_APPS_SCROLL = 26;
private static final int NO_STATSD_LOGGING = -1;
@@ -147,6 +151,8 @@ public class InteractionJankMonitor {
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_PIN_DISAPPEAR,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_FROM_AOD,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_TO_AOD,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_ALL_APPS,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL,
};
private static volatile InteractionJankMonitor sInstance;
@@ -191,6 +197,8 @@ public class InteractionJankMonitor {
CUJ_LOCKSCREEN_PIN_DISAPPEAR,
CUJ_LOCKSCREEN_TRANSITION_FROM_AOD,
CUJ_LOCKSCREEN_TRANSITION_TO_AOD,
+ CUJ_LAUNCHER_OPEN_ALL_APPS,
+ CUJ_LAUNCHER_ALL_APPS_SCROLL,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -457,6 +465,10 @@ public class InteractionJankMonitor {
return "CUJ_LOCKSCREEN_TRANSITION_FROM_AOD";
case CUJ_LOCKSCREEN_TRANSITION_TO_AOD:
return "CUJ_LOCKSCREEN_TRANSITION_TO_AOD";
+ case CUJ_LAUNCHER_OPEN_ALL_APPS :
+ return "CUJ_LAUNCHER_OPEN_ALL_APPS";
+ case CUJ_LAUNCHER_ALL_APPS_SCROLL:
+ return "CUJ_LAUNCHER_ALL_APPS_SCROLL";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/os/CPU_OWNERS b/core/java/com/android/internal/os/CPU_OWNERS
new file mode 100644
index 000000000000..5d3473cc0c9e
--- /dev/null
+++ b/core/java/com/android/internal/os/CPU_OWNERS
@@ -0,0 +1,3 @@
+connoro@google.com
+dplotnikov@google.com
+rslawik@google.com # Android Telemetry
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 1b07aa0cf0b7..0aa54f556b92 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -1,5 +1,6 @@
per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS
per-file *Zygote* = file:/ZYGOTE_OWNERS
+per-file *Cpu* = file:CPU_OWNERS
# BatteryStats
per-file BatterySipper.java = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index d196d4af2e42..c8afea9b0982 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -1091,4 +1091,11 @@ public final class Zygote {
* fully-feature Memory Tagging, rather than the static Tagged Pointers.
*/
public static native boolean nativeSupportsTaggedPointers();
+
+ /**
+ * Returns the current native tagging level, as one of the
+ * MEMORY_TAG_LEVEL_* constants. Returns zero if no tagging is present, or
+ * we failed to determine the level.
+ */
+ public static native int nativeCurrentTaggingLevel();
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 94e21e5a5965..f2ed50ef6a07 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -787,9 +787,19 @@ public class ZygoteInit {
Zygote.applyInvokeWithSystemProperty(parsedArgs);
if (Zygote.nativeSupportsMemoryTagging()) {
- /* The system server is more privileged than regular app processes, so it has async
- * tag checks enabled on hardware that supports memory tagging. */
- parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
+ /* The system server has ASYNC MTE by default, in order to allow
+ * system services to specify their own MTE level later, as you
+ * can't re-enable MTE once it's disabled. */
+ String mode = SystemProperties.get("arm64.memtag.process.system_server", "async");
+ if (mode.equals("async")) {
+ parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
+ } else if (mode.equals("sync")) {
+ parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
+ } else if (!mode.equals("off")) {
+ /* When we have an invalid memory tag level, keep the current level. */
+ parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
+ Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\"");
+ }
} else if (Zygote.nativeSupportsTaggedPointers()) {
/* Enable pointer tagging in the system server. Hardware support for this is present
* in all ARMv8 CPUs. */
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 2279d5796c02..35d1d7bd7946 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -5,6 +5,9 @@ per-file *Camera*,*camera* = shuzhenwang@google.com, yinchiayeh@google.com, zhij
# Connectivity
per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
+# CPU
+per-file *Cpu* = file:/core/java/com/android/internal/os/CPU_OWNERS
+
# Display
per-file android_hardware_display_* = file:/services/core/java/com/android/server/display/OWNERS
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 6337680147a5..8977b97fc541 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -40,7 +40,7 @@ static struct {
jmethodID dispatchVsync;
jmethodID dispatchHotplug;
- jmethodID dispatchConfigChanged;
+ jmethodID dispatchModeChanged;
jmethodID dispatchFrameRateOverrides;
struct {
@@ -69,8 +69,8 @@ private:
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
VsyncEventData vsyncEventData) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
- void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
- int32_t configId, nsecs_t vsyncPeriod) override;
+ void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
+ nsecs_t vsyncPeriod) override;
void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
std::vector<FrameRateOverride> overrides) override;
void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
@@ -129,20 +129,19 @@ void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisp
mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
}
-void NativeDisplayEventReceiver::dispatchConfigChanged(
- nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId, nsecs_t) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
+void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
+ int32_t modeId, nsecs_t) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
- ScopedLocalRef<jobject> receiverObj(env,
- jniGetReferent(env, mReceiverWeakGlobal));
- if (receiverObj.get()) {
- ALOGV("receiver %p ~ Invoking config changed handler.", this);
- env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchConfigChanged,
- timestamp, displayId.value, configId);
- ALOGV("receiver %p ~ Returned from config changed handler.", this);
- }
+ ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
+ if (receiverObj.get()) {
+ ALOGV("receiver %p ~ Invoking mode changed handler.", this);
+ env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeChanged,
+ timestamp, displayId.value, modeId);
+ ALOGV("receiver %p ~ Returned from mode changed handler.", this);
+ }
- mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged");
+ mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
}
void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
@@ -173,7 +172,7 @@ void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
ALOGV("receiver %p ~ Returned from FrameRateOverride handler.", this);
}
- mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged");
+ mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
}
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
@@ -243,8 +242,9 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
"(JJIJJ)V");
gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
- gDisplayEventReceiverClassInfo.dispatchConfigChanged = GetMethodIDOrDie(env,
- gDisplayEventReceiverClassInfo.clazz, "dispatchConfigChanged", "(JJI)V");
+ gDisplayEventReceiverClassInfo.dispatchModeChanged =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
+ "(JJI)V");
gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
"dispatchFrameRateOverrides",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 859730872e8c..7a3366acce27 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -44,8 +44,8 @@
#include <ui/BlurRegion.h>
#include <ui/ConfigStoreTypes.h>
#include <ui/DeviceProductInfo.h>
-#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
+#include <ui/DisplayMode.h>
#include <ui/DisplayedFrameStats.h>
#include <ui/FrameStats.h>
#include <ui/GraphicTypes.h>
@@ -98,8 +98,8 @@ static struct {
jfieldID refreshRate;
jfieldID appVsyncOffsetNanos;
jfieldID presentationDeadlineNanos;
- jfieldID configGroup;
-} gDisplayConfigClassInfo;
+ jfieldID group;
+} gDisplayModeClassInfo;
static struct {
jfieldID bottom;
@@ -202,13 +202,13 @@ static struct {
static struct {
jclass clazz;
jmethodID ctor;
- jfieldID defaultConfig;
+ jfieldID defaultMode;
jfieldID allowGroupSwitching;
jfieldID primaryRefreshRateMin;
jfieldID primaryRefreshRateMax;
jfieldID appRequestRefreshRateMin;
jfieldID appRequestRefreshRateMax;
-} gDesiredDisplayConfigSpecsClassInfo;
+} gDesiredDisplayModeSpecsClassInfo;
static struct {
jclass clazz;
@@ -1028,101 +1028,97 @@ static jobject nativeGetDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj)
return object;
}
-static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz, jobject tokenObj) {
- Vector<DisplayConfig> configs;
+static jobjectArray nativeGetDisplayModes(JNIEnv* env, jclass clazz, jobject tokenObj) {
+ Vector<ui::DisplayMode> modes;
if (const auto token = ibinderForJavaObject(env, tokenObj); !token ||
- SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
- configs.isEmpty()) {
+ SurfaceComposerClient::getDisplayModes(token, &modes) != NO_ERROR || modes.isEmpty()) {
return nullptr;
}
- jobjectArray configArray =
- env->NewObjectArray(configs.size(), gDisplayConfigClassInfo.clazz, nullptr);
-
- for (size_t c = 0; c < configs.size(); ++c) {
- const DisplayConfig& config = configs[c];
- jobject object =
- env->NewObject(gDisplayConfigClassInfo.clazz, gDisplayConfigClassInfo.ctor);
- env->SetIntField(object, gDisplayConfigClassInfo.width, config.resolution.getWidth());
- env->SetIntField(object, gDisplayConfigClassInfo.height, config.resolution.getHeight());
- env->SetFloatField(object, gDisplayConfigClassInfo.xDpi, config.xDpi);
- env->SetFloatField(object, gDisplayConfigClassInfo.yDpi, config.yDpi);
-
- env->SetFloatField(object, gDisplayConfigClassInfo.refreshRate, config.refreshRate);
- env->SetLongField(object, gDisplayConfigClassInfo.appVsyncOffsetNanos,
- config.appVsyncOffset);
- env->SetLongField(object, gDisplayConfigClassInfo.presentationDeadlineNanos,
- config.presentationDeadline);
- env->SetIntField(object, gDisplayConfigClassInfo.configGroup, config.configGroup);
- env->SetObjectArrayElement(configArray, static_cast<jsize>(c), object);
+ jobjectArray modesArray =
+ env->NewObjectArray(modes.size(), gDisplayModeClassInfo.clazz, nullptr);
+
+ for (size_t c = 0; c < modes.size(); ++c) {
+ const ui::DisplayMode& mode = modes[c];
+ jobject object = env->NewObject(gDisplayModeClassInfo.clazz, gDisplayModeClassInfo.ctor);
+ env->SetIntField(object, gDisplayModeClassInfo.width, mode.resolution.getWidth());
+ env->SetIntField(object, gDisplayModeClassInfo.height, mode.resolution.getHeight());
+ env->SetFloatField(object, gDisplayModeClassInfo.xDpi, mode.xDpi);
+ env->SetFloatField(object, gDisplayModeClassInfo.yDpi, mode.yDpi);
+
+ env->SetFloatField(object, gDisplayModeClassInfo.refreshRate, mode.refreshRate);
+ env->SetLongField(object, gDisplayModeClassInfo.appVsyncOffsetNanos, mode.appVsyncOffset);
+ env->SetLongField(object, gDisplayModeClassInfo.presentationDeadlineNanos,
+ mode.presentationDeadline);
+ env->SetIntField(object, gDisplayModeClassInfo.group, mode.group);
+ env->SetObjectArrayElement(modesArray, static_cast<jsize>(c), object);
env->DeleteLocalRef(object);
}
- return configArray;
+ return modesArray;
}
-static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jobject tokenObj,
- jobject desiredDisplayConfigSpecs) {
+static jboolean nativeSetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobject tokenObj,
+ jobject DesiredDisplayModeSpecs) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == nullptr) return JNI_FALSE;
- jint defaultConfig = env->GetIntField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.defaultConfig);
+ size_t defaultMode =
+ static_cast<size_t>(env->GetIntField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.defaultMode));
jboolean allowGroupSwitching =
- env->GetBooleanField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.allowGroupSwitching);
+ env->GetBooleanField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.allowGroupSwitching);
jfloat primaryRefreshRateMin =
- env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin);
+ env->GetFloatField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMin);
jfloat primaryRefreshRateMax =
- env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax);
+ env->GetFloatField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMax);
jfloat appRequestRefreshRateMin =
- env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMin);
+ env->GetFloatField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMin);
jfloat appRequestRefreshRateMax =
- env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax);
-
- size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(token, defaultConfig,
- allowGroupSwitching,
- primaryRefreshRateMin,
- primaryRefreshRateMax,
- appRequestRefreshRateMin,
- appRequestRefreshRateMax);
+ env->GetFloatField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMax);
+
+ size_t result = SurfaceComposerClient::setDesiredDisplayModeSpecs(token, defaultMode,
+ allowGroupSwitching,
+ primaryRefreshRateMin,
+ primaryRefreshRateMax,
+ appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
-static jobject nativeGetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jobject tokenObj) {
+static jobject nativeGetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == nullptr) return nullptr;
- int32_t defaultConfig;
+ size_t defaultMode;
bool allowGroupSwitching;
float primaryRefreshRateMin;
float primaryRefreshRateMax;
float appRequestRefreshRateMin;
float appRequestRefreshRateMax;
- if (SurfaceComposerClient::getDesiredDisplayConfigSpecs(token, &defaultConfig,
- &allowGroupSwitching,
- &primaryRefreshRateMin,
- &primaryRefreshRateMax,
- &appRequestRefreshRateMin,
- &appRequestRefreshRateMax) !=
- NO_ERROR) {
+ if (SurfaceComposerClient::getDesiredDisplayModeSpecs(token, &defaultMode, &allowGroupSwitching,
+ &primaryRefreshRateMin,
+ &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax) != NO_ERROR) {
return nullptr;
}
- return env->NewObject(gDesiredDisplayConfigSpecsClassInfo.clazz,
- gDesiredDisplayConfigSpecsClassInfo.ctor, defaultConfig,
- allowGroupSwitching, primaryRefreshRateMin, primaryRefreshRateMax,
- appRequestRefreshRateMin, appRequestRefreshRateMax);
+ return env->NewObject(gDesiredDisplayModeSpecsClassInfo.clazz,
+ gDesiredDisplayModeSpecsClassInfo.ctor, defaultMode, allowGroupSwitching,
+ primaryRefreshRateMin, primaryRefreshRateMax, appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
}
-static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
+static jint nativeGetActiveDisplayMode(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return -1;
- return static_cast<jint>(SurfaceComposerClient::getActiveConfig(token));
+ return static_cast<jint>(SurfaceComposerClient::getActiveDisplayModeId(token));
}
static jintArray nativeGetDisplayColorModes(JNIEnv* env, jclass, jobject tokenObj) {
@@ -1784,16 +1780,16 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetDisplaySize },
{"nativeGetDisplayInfo", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayInfo;",
(void*)nativeGetDisplayInfo },
- {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$DisplayConfig;",
- (void*)nativeGetDisplayConfigs },
- {"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
- (void*)nativeGetActiveConfig },
- {"nativeSetDesiredDisplayConfigSpecs",
- "(Landroid/os/IBinder;Landroid/view/SurfaceControl$DesiredDisplayConfigSpecs;)Z",
- (void*)nativeSetDesiredDisplayConfigSpecs },
- {"nativeGetDesiredDisplayConfigSpecs",
- "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DesiredDisplayConfigSpecs;",
- (void*)nativeGetDesiredDisplayConfigSpecs },
+ {"nativeGetDisplayModes", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$DisplayMode;",
+ (void*)nativeGetDisplayModes },
+ {"nativeGetActiveDisplayMode", "(Landroid/os/IBinder;)I",
+ (void*)nativeGetActiveDisplayMode },
+ {"nativeSetDesiredDisplayModeSpecs",
+ "(Landroid/os/IBinder;Landroid/view/SurfaceControl$DesiredDisplayModeSpecs;)Z",
+ (void*)nativeSetDesiredDisplayModeSpecs },
+ {"nativeGetDesiredDisplayModeSpecs",
+ "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DesiredDisplayModeSpecs;",
+ (void*)nativeGetDesiredDisplayModeSpecs },
{"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
(void*)nativeGetDisplayColorModes},
{"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
@@ -1902,19 +1898,19 @@ int register_android_view_SurfaceControl(JNIEnv* env)
GetFieldIDOrDie(env, infoClazz, "deviceProductInfo",
"Landroid/hardware/display/DeviceProductInfo;");
- jclass configClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayConfig");
- gDisplayConfigClassInfo.clazz = MakeGlobalRefOrDie(env, configClazz);
- gDisplayConfigClassInfo.ctor = GetMethodIDOrDie(env, configClazz, "<init>", "()V");
- gDisplayConfigClassInfo.width = GetFieldIDOrDie(env, configClazz, "width", "I");
- gDisplayConfigClassInfo.height = GetFieldIDOrDie(env, configClazz, "height", "I");
- gDisplayConfigClassInfo.xDpi = GetFieldIDOrDie(env, configClazz, "xDpi", "F");
- gDisplayConfigClassInfo.yDpi = GetFieldIDOrDie(env, configClazz, "yDpi", "F");
- gDisplayConfigClassInfo.refreshRate = GetFieldIDOrDie(env, configClazz, "refreshRate", "F");
- gDisplayConfigClassInfo.appVsyncOffsetNanos =
- GetFieldIDOrDie(env, configClazz, "appVsyncOffsetNanos", "J");
- gDisplayConfigClassInfo.presentationDeadlineNanos =
- GetFieldIDOrDie(env, configClazz, "presentationDeadlineNanos", "J");
- gDisplayConfigClassInfo.configGroup = GetFieldIDOrDie(env, configClazz, "configGroup", "I");
+ jclass modeClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayMode");
+ gDisplayModeClassInfo.clazz = MakeGlobalRefOrDie(env, modeClazz);
+ gDisplayModeClassInfo.ctor = GetMethodIDOrDie(env, modeClazz, "<init>", "()V");
+ gDisplayModeClassInfo.width = GetFieldIDOrDie(env, modeClazz, "width", "I");
+ gDisplayModeClassInfo.height = GetFieldIDOrDie(env, modeClazz, "height", "I");
+ gDisplayModeClassInfo.xDpi = GetFieldIDOrDie(env, modeClazz, "xDpi", "F");
+ gDisplayModeClassInfo.yDpi = GetFieldIDOrDie(env, modeClazz, "yDpi", "F");
+ gDisplayModeClassInfo.refreshRate = GetFieldIDOrDie(env, modeClazz, "refreshRate", "F");
+ gDisplayModeClassInfo.appVsyncOffsetNanos =
+ GetFieldIDOrDie(env, modeClazz, "appVsyncOffsetNanos", "J");
+ gDisplayModeClassInfo.presentationDeadlineNanos =
+ GetFieldIDOrDie(env, modeClazz, "presentationDeadlineNanos", "J");
+ gDisplayModeClassInfo.group = GetFieldIDOrDie(env, modeClazz, "group", "I");
jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
@@ -2005,24 +2001,23 @@ int register_android_view_SurfaceControl(JNIEnv* env)
gDisplayPrimariesClassInfo.white = GetFieldIDOrDie(env, displayPrimariesClazz, "white",
"Landroid/view/SurfaceControl$CieXyz;");
- jclass desiredDisplayConfigSpecsClazz =
- FindClassOrDie(env, "android/view/SurfaceControl$DesiredDisplayConfigSpecs");
- gDesiredDisplayConfigSpecsClassInfo.clazz =
- MakeGlobalRefOrDie(env, desiredDisplayConfigSpecsClazz);
- gDesiredDisplayConfigSpecsClassInfo.ctor =
- GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IZFFFF)V");
- gDesiredDisplayConfigSpecsClassInfo.defaultConfig =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "defaultConfig", "I");
- gDesiredDisplayConfigSpecsClassInfo.allowGroupSwitching =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "allowGroupSwitching", "Z");
- gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "primaryRefreshRateMin", "F");
- gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "primaryRefreshRateMax", "F");
- gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMin =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMin", "F");
- gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMax", "F");
+ jclass DesiredDisplayModeSpecsClazz =
+ FindClassOrDie(env, "android/view/SurfaceControl$DesiredDisplayModeSpecs");
+ gDesiredDisplayModeSpecsClassInfo.clazz = MakeGlobalRefOrDie(env, DesiredDisplayModeSpecsClazz);
+ gDesiredDisplayModeSpecsClassInfo.ctor =
+ GetMethodIDOrDie(env, gDesiredDisplayModeSpecsClassInfo.clazz, "<init>", "(IZFFFF)V");
+ gDesiredDisplayModeSpecsClassInfo.defaultMode =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "defaultMode", "I");
+ gDesiredDisplayModeSpecsClassInfo.allowGroupSwitching =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "allowGroupSwitching", "Z");
+ gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMin =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "primaryRefreshRateMin", "F");
+ gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMax =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "primaryRefreshRateMax", "F");
+ gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMin =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRefreshRateMin", "F");
+ gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMax =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRefreshRateMax", "F");
jclass captureArgsClazz = FindClassOrDie(env, "android/view/SurfaceControl$CaptureArgs");
gCaptureArgsClassInfo.pixelFormat = GetFieldIDOrDie(env, captureArgsClazz, "mPixelFormat", "I");
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 3d1c38d4b5ca..e8017253fc29 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -2506,6 +2506,36 @@ static jboolean com_android_internal_os_Zygote_nativeSupportsTaggedPointers(JNIE
#endif
}
+static jint com_android_internal_os_Zygote_nativeCurrentTaggingLevel(JNIEnv* env, jclass) {
+#if defined(__aarch64__)
+ int level = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+ if (level < 0) {
+ ALOGE("Failed to get memory tag level: %s", strerror(errno));
+ return 0;
+ } else if (!(level & PR_TAGGED_ADDR_ENABLE)) {
+ return 0;
+ }
+ // TBI is only possible on non-MTE hardware.
+ if (!mte_supported()) {
+ return MEMORY_TAG_LEVEL_TBI;
+ }
+
+ switch (level & PR_MTE_TCF_MASK) {
+ case PR_MTE_TCF_NONE:
+ return 0;
+ case PR_MTE_TCF_SYNC:
+ return MEMORY_TAG_LEVEL_SYNC;
+ case PR_MTE_TCF_ASYNC:
+ return MEMORY_TAG_LEVEL_ASYNC;
+ default:
+ ALOGE("Unknown memory tagging level: %i", level);
+ return 0;
+ }
+#else // defined(__aarch64__)
+ return 0;
+#endif // defined(__aarch64__)
+}
+
static const JNINativeMethod gMethods[] = {
{"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
@@ -2545,6 +2575,8 @@ static const JNINativeMethod gMethods[] = {
(void*)com_android_internal_os_Zygote_nativeSupportsMemoryTagging},
{"nativeSupportsTaggedPointers", "()Z",
(void*)com_android_internal_os_Zygote_nativeSupportsTaggedPointers},
+ {"nativeCurrentTaggingLevel", "()I",
+ (void*)com_android_internal_os_Zygote_nativeCurrentTaggingLevel},
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/res/res/layout/notification_template_part_chronometer.xml b/core/res/res/layout/notification_template_part_chronometer.xml
index c5ffbeadc525..e4ebc76c113a 100644
--- a/core/res/res/layout/notification_template_part_chronometer.xml
+++ b/core/res/res/layout/notification_template_part_chronometer.xml
@@ -15,7 +15,7 @@
-->
<Chronometer android:id="@+id/chronometer" xmlns:android="http://schemas.android.com/apk/res/android"
- android:textAppearance="@style/TextAppearance.Material.Notification.Time"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 14df77527a08..e567c3d7d486 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7969,9 +7969,17 @@
<!-- A class name in the AppWidget's package to be launched to configure.
If not supplied, then no activity will be launched. -->
<attr name="configure" format="string" />
- <!-- A preview of what the AppWidget will look like after it's configured.
- If not supplied, the AppWidget's icon will be used. -->
+ <!-- A preview, in a drawable resource id, of what the AppWidget will look like after it's
+ configured.
+ If not supplied, the AppWidget's icon will be used. -->
<attr name="previewImage" format="reference" />
+ <!-- The layout resource id of a preview of what the AppWidget will look like after it's
+ configured.
+ Unlike previewImage, previewLayout can better showcase AppWidget in different locales,
+ system themes, display sizes & density etc.
+ If supplied, this will take precedence over the previewImage on supported widget hosts.
+ Otherwise, previewImage will be used. -->
+ <attr name="previewLayout" format="reference" />
<!-- The view id of the AppWidget subview which should be auto-advanced.
by the widget's host. -->
<attr name="autoAdvanceViewId" format="reference" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3790aa4fb072..8c5f454d204d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3477,6 +3477,11 @@
<!-- The alarm window (in milliseconds) that JobScheduler uses to enter the idle state -->
<integer name="config_jobSchedulerIdleWindowSlop">300000</integer>
+ <!-- If true, jobs from background user will be restricted -->
+ <bool name="config_jobSchedulerRestrictBackgroundUser">false</bool>
+ <!-- The length of grace period after user becomes background user -->
+ <integer name="config_jobSchedulerUserGracePeriod">60000</integer>
+
<!-- If true, all guest users created on the device will be ephemeral. -->
<bool name="config_guestUserEphemeral">false</bool>
@@ -4707,7 +4712,4 @@
<!-- Whether to select voice/data/sms preference without user confirmation -->
<bool name="config_voice_data_sms_auto_fallback">false</bool>
-
- <!-- Whether to enable the one-handed keyguard on the lock screen for wide-screen devices. -->
- <bool name="config_enableOneHandedKeyguard">false</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 30cfb8986035..97ec0f4fa71e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3061,6 +3061,7 @@
<public name="nativeHeapZeroInit" />
<!-- @hide @SystemApi -->
<public name="hotwordDetectionService" />
+ <public name="previewLayout" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f6d1b7da78f0..9b5f67091a2a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4532,9 +4532,8 @@
shown in the warning dialog about the accessibility shortcut. -->
<string name="color_correction_feature_name">Color Correction</string>
- <!-- TODO(b/170970602): remove translatable=false when RBC has official name and strings -->
- <!-- Title of Reduce Bright Colors feature, shown in the warning dialog about the accessibility shortcut. [CHAR LIMIT=none] -->
- <string name="reduce_bright_colors_feature_name" translatable="false">Reduce Bright Colors</string>
+ <!-- Title of Reduce Brightness feature, shown in the warning dialog about the accessibility shortcut. [CHAR LIMIT=none] -->
+ <string name="reduce_bright_colors_feature_name">Reduce Brightness</string>
<!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility service. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_enabling_service">Held volume keys. <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> turned on.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ae5e2f597952..c41b78e4a680 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2680,6 +2680,8 @@
<java-symbol type="integer" name="config_jobSchedulerInactivityIdleThreshold" />
<java-symbol type="integer" name="config_jobSchedulerIdleWindowSlop" />
+ <java-symbol type="bool" name="config_jobSchedulerRestrictBackgroundUser" />
+ <java-symbol type="integer" name="config_jobSchedulerUserGracePeriod" />
<java-symbol type="style" name="Animation.ImmersiveModeConfirmation" />
@@ -4176,6 +4178,4 @@
<java-symbol type="bool" name="config_telephony5gNonStandalone" />
<java-symbol type="bool" name="config_voice_data_sms_auto_fallback" />
-
- <java-symbol type="bool" name="config_enableOneHandedKeyguard" />
</resources>
diff --git a/core/tests/coretests/src/android/graphics/FontListParserTest.java b/core/tests/coretests/src/android/graphics/FontListParserTest.java
new file mode 100644
index 000000000000..eae41e37e5f3
--- /dev/null
+++ b/core/tests/coretests/src/android/graphics/FontListParserTest.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import static android.graphics.fonts.FontStyle.FONT_SLANT_ITALIC;
+import static android.graphics.fonts.FontStyle.FONT_SLANT_UPRIGHT;
+import static android.graphics.fonts.FontStyle.FONT_WEIGHT_NORMAL;
+import static android.text.FontConfig.FontFamily.VARIANT_COMPACT;
+import static android.text.FontConfig.FontFamily.VARIANT_DEFAULT;
+import static android.text.FontConfig.FontFamily.VARIANT_ELEGANT;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.graphics.fonts.FontStyle;
+import android.os.LocaleList;
+import android.text.FontConfig;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class FontListParserTest {
+
+ @Test
+ public void named() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<family name='sans-serif'>"
+ + " <font>test.ttf</font>"
+ + "</family>";
+ FontConfig.FontFamily expected = new FontConfig.FontFamily(
+ Arrays.asList(
+ new FontConfig.Font(new File("test.ttf"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
+ 0, "", null)),
+ "sans-serif", LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT);
+
+ FontConfig.FontFamily family = readFamily(xml);
+ assertThat(family).isEqualTo(expected);
+
+ String serialized = writeFamily(family);
+ assertWithMessage("serialized = " + serialized)
+ .that(readFamily(serialized)).isEqualTo(expected);
+ }
+
+ @Test
+ public void fallback() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<family lang='en'>"
+ + " <font>test.ttf</font>"
+ + " <font fallbackFor='serif'>test.ttf</font>"
+ + "</family>";
+ FontConfig.FontFamily expected = new FontConfig.FontFamily(
+ Arrays.asList(
+ new FontConfig.Font(new File("test.ttf"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
+ 0, "", null),
+ new FontConfig.Font(new File("test.ttf"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
+ 0, "", "serif")),
+ null, LocaleList.forLanguageTags("en"), VARIANT_DEFAULT);
+
+ FontConfig.FontFamily family = readFamily(xml);
+ assertThat(family).isEqualTo(expected);
+
+ String serialized = writeFamily(family);
+ assertWithMessage("serialized = " + serialized)
+ .that(readFamily(serialized)).isEqualTo(expected);
+ }
+
+ @Test
+ public void compact() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<family lang='en' variant='compact'>"
+ + " <font>test.ttf</font>"
+ + "</family>";
+ FontConfig.FontFamily expected = new FontConfig.FontFamily(
+ Arrays.asList(
+ new FontConfig.Font(new File("test.ttf"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
+ 0, "", null)),
+ null, LocaleList.forLanguageTags("en"), VARIANT_COMPACT);
+
+ FontConfig.FontFamily family = readFamily(xml);
+ assertThat(family).isEqualTo(expected);
+
+ String serialized = writeFamily(family);
+ assertWithMessage("serialized = " + serialized)
+ .that(readFamily(serialized)).isEqualTo(expected);
+ }
+
+ @Test
+ public void elegant() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<family lang='en' variant='elegant'>"
+ + " <font>test.ttf</font>"
+ + "</family>";
+ FontConfig.FontFamily expected = new FontConfig.FontFamily(
+ Arrays.asList(
+ new FontConfig.Font(new File("test.ttf"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
+ 0, "", null)),
+ null, LocaleList.forLanguageTags("en"), VARIANT_ELEGANT);
+
+ FontConfig.FontFamily family = readFamily(xml);
+ assertThat(family).isEqualTo(expected);
+
+ String serialized = writeFamily(family);
+ assertWithMessage("serialized = " + serialized)
+ .that(readFamily(serialized)).isEqualTo(expected);
+ }
+
+ @Test
+ public void styles() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<family name='sans-serif'>"
+ + " <font style='normal'>normal.ttf</font>"
+ + " <font weight='100'>weight.ttf</font>"
+ + " <font style='italic'>italic.ttf</font>"
+ + "</family>";
+ FontConfig.FontFamily expected = new FontConfig.FontFamily(
+ Arrays.asList(
+ new FontConfig.Font(new File("normal.ttf"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
+ 0, "", null),
+ new FontConfig.Font(new File("weight.ttf"), null,
+ new FontStyle(100, FONT_SLANT_UPRIGHT),
+ 0, "", null),
+ new FontConfig.Font(new File("italic.ttf"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_ITALIC),
+ 0, "", null)),
+ "sans-serif", LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT);
+ FontConfig.FontFamily family = readFamily(xml);
+ assertThat(family).isEqualTo(expected);
+
+ String serialized = writeFamily(family);
+ assertWithMessage("serialized = " + serialized)
+ .that(readFamily(serialized)).isEqualTo(expected);
+ }
+
+ @Test
+ public void variable() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<family name='sans-serif'>"
+ + " <font>test-VF.ttf"
+ + " <axis tag='wdth' stylevalue='100' />"
+ + " <axis tag='wght' stylevalue='200' />"
+ + " </font>"
+ + " <font>test-VF.ttf"
+ + " <axis tag='wdth' stylevalue='400' />"
+ + " <axis tag='wght' stylevalue='700' />"
+ + " </font>"
+ + "</family>";
+ FontConfig.FontFamily expected = new FontConfig.FontFamily(
+ Arrays.asList(
+ new FontConfig.Font(new File("test-VF.ttf"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
+ 0, "'wdth' 100.0,'wght' 200.0", null),
+ new FontConfig.Font(new File("test-VF.ttf"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
+ 0, "'wdth' 400.0,'wght' 700.0", null)),
+ "sans-serif", LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT);
+ FontConfig.FontFamily family = readFamily(xml);
+ assertThat(family).isEqualTo(expected);
+
+ String serialized = writeFamily(family);
+ assertWithMessage("serialized = " + serialized)
+ .that(readFamily(serialized)).isEqualTo(expected);
+ }
+
+ @Test
+ public void ttc() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<family name='sans-serif'>"
+ + " <font index='0'>test.ttc</font>"
+ + " <font index='1'>test.ttc</font>"
+ + "</family>";
+ FontConfig.FontFamily expected = new FontConfig.FontFamily(
+ Arrays.asList(
+ new FontConfig.Font(new File("test.ttc"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
+ 0, "", null),
+ new FontConfig.Font(new File("test.ttc"), null,
+ new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
+ 1, "", null)),
+ "sans-serif", LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT);
+ FontConfig.FontFamily family = readFamily(xml);
+ assertThat(family).isEqualTo(expected);
+
+ String serialized = writeFamily(family);
+ assertWithMessage("serialized = " + serialized)
+ .that(readFamily(serialized)).isEqualTo(expected);
+ }
+
+ private FontConfig.FontFamily readFamily(String xml)
+ throws IOException, XmlPullParserException {
+ StandardCharsets.UTF_8.name();
+ ByteArrayInputStream buffer = new ByteArrayInputStream(
+ xml.getBytes(StandardCharsets.UTF_8));
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(buffer, "UTF-8");
+ parser.nextTag();
+ return FontListParser.readFamily(parser, "", null);
+ }
+
+ private String writeFamily(FontConfig.FontFamily family) throws IOException {
+ TypedXmlSerializer out = Xml.newFastSerializer();
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ out.setOutput(buffer, "UTF-8");
+ out.startTag(null, "family");
+ FontListParser.writeFamily(out, family);
+ out.endTag(null, "family");
+ out.endDocument();
+ return buffer.toString("UTF-8");
+ }
+}
diff --git a/core/tests/coretests/src/android/os/BrightnessLimit.java b/core/tests/coretests/src/android/os/BrightnessLimit.java
index be7935545543..219f741d8a08 100644
--- a/core/tests/coretests/src/android/os/BrightnessLimit.java
+++ b/core/tests/coretests/src/android/os/BrightnessLimit.java
@@ -42,7 +42,8 @@ public class BrightnessLimit extends Activity implements OnClickListener {
public void onClick(View v) {
DisplayManager dm = getSystemService(DisplayManager.class);
- dm.setTemporaryBrightness(0.0f);
+ final int displayId = getBaseContext().getDisplay().getDisplayId();
+ dm.setTemporaryBrightness(displayId, 0.0f);
Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 0);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/OWNERS b/core/tests/coretests/src/com/android/internal/os/OWNERS
index 4068e2bc03b7..3f8f9e29c6a0 100644
--- a/core/tests/coretests/src/com/android/internal/os/OWNERS
+++ b/core/tests/coretests/src/com/android/internal/os/OWNERS
@@ -1 +1,4 @@
include /BATTERY_STATS_OWNERS
+
+# CPU
+per-file *Cpu* = file:/core/java/com/android/internal/os/CPU_OWNERS
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index bab36e61393a..0484a9ab582e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -465,6 +465,8 @@ applications that come with the platform
<permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
<!-- Permission required for CTS test CarrierMessagingServiceWrapperTest -->
<permission name="android.permission.BIND_CARRIER_SERVICES"/>
+ <!-- Permission required for CTS test - MusicRecognitionManagerTest -->
+ <permission name="android.permission.MANAGE_MUSIC_RECOGNITION" />
<!-- Permission required for CTS test - CallLogTest -->
<permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
<permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
@@ -485,6 +487,8 @@ applications that come with the platform
<permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/>
<!-- Permissions required for quick settings tile -->
<permission name="android.permission.STATUS_BAR"/>
+ <!-- Permissions required to query Betterbug -->
+ <permission name="android.permission.QUERY_ALL_PACKAGES"/>
</privapp-permissions>
<privapp-permissions package="com.android.tv">
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index bb795cd99e6e..63df0db99764 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -25,6 +25,8 @@ import android.graphics.fonts.FontVariationAxis;
import android.os.Build;
import android.os.LocaleList;
import android.text.FontConfig;
+import android.text.TextUtils;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
@@ -45,6 +47,27 @@ import java.util.regex.Pattern;
*/
public class FontListParser {
+ // XML constants for FontFamily.
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_LANG = "lang";
+ private static final String ATTR_VARIANT = "variant";
+ private static final String TAG_FONT = "font";
+ private static final String VARIANT_COMPACT = "compact";
+ private static final String VARIANT_ELEGANT = "elegant";
+
+ // XML constants for Font.
+ public static final String ATTR_INDEX = "index";
+ public static final String ATTR_WEIGHT = "weight";
+ public static final String ATTR_STYLE = "style";
+ public static final String ATTR_FALLBACK_FOR = "fallbackFor";
+ public static final String STYLE_ITALIC = "italic";
+ public static final String STYLE_NORMAL = "normal";
+ public static final String TAG_AXIS = "axis";
+
+ // XML constants for FontVariationAxis.
+ public static final String ATTR_TAG = "tag";
+ public static final String ATTR_STYLEVALUE = "stylevalue";
+
/* Parse fallback list (no names) */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException {
@@ -148,7 +171,7 @@ public class FontListParser {
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
final String tag = parser.getName();
- if (tag.equals("font")) {
+ if (tag.equals(TAG_FONT)) {
fonts.add(readFont(parser, fontDir, updatableFontMap));
} else {
skip(parser);
@@ -156,15 +179,41 @@ public class FontListParser {
}
int intVariant = FontConfig.FontFamily.VARIANT_DEFAULT;
if (variant != null) {
- if (variant.equals("compact")) {
+ if (variant.equals(VARIANT_COMPACT)) {
intVariant = FontConfig.FontFamily.VARIANT_COMPACT;
- } else if (variant.equals("elegant")) {
+ } else if (variant.equals(VARIANT_ELEGANT)) {
intVariant = FontConfig.FontFamily.VARIANT_ELEGANT;
}
}
return new FontConfig.FontFamily(fonts, name, LocaleList.forLanguageTags(lang), intVariant);
}
+ /**
+ * Write a family tag representing {@code fontFamily}. The tag should be started by the caller.
+ */
+ public static void writeFamily(TypedXmlSerializer out, FontConfig.FontFamily fontFamily)
+ throws IOException {
+ if (!TextUtils.isEmpty(fontFamily.getName())) {
+ out.attribute(null, ATTR_NAME, fontFamily.getName());
+ }
+ if (!fontFamily.getLocaleList().isEmpty()) {
+ out.attribute(null, ATTR_LANG, fontFamily.getLocaleList().toLanguageTags());
+ }
+ switch (fontFamily.getVariant()) {
+ case FontConfig.FontFamily.VARIANT_COMPACT:
+ out.attribute(null, ATTR_VARIANT, VARIANT_COMPACT);
+ break;
+ case FontConfig.FontFamily.VARIANT_ELEGANT:
+ out.attribute(null, ATTR_VARIANT, VARIANT_ELEGANT);
+ break;
+ }
+ for (FontConfig.Font font : fontFamily.getFontList()) {
+ out.startTag(null, TAG_FONT);
+ writeFont(out, font);
+ out.endTag(null, TAG_FONT);
+ }
+ }
+
/** Matches leading and trailing XML whitespace. */
private static final Pattern FILENAME_WHITESPACE_PATTERN =
Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
@@ -175,13 +224,13 @@ public class FontListParser {
@Nullable Map<String, File> updatableFontMap)
throws XmlPullParserException, IOException {
- String indexStr = parser.getAttributeValue(null, "index");
+ String indexStr = parser.getAttributeValue(null, ATTR_INDEX);
int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
List<FontVariationAxis> axes = new ArrayList<>();
- String weightStr = parser.getAttributeValue(null, "weight");
- int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
- boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
- String fallbackFor = parser.getAttributeValue(null, "fallbackFor");
+ String weightStr = parser.getAttributeValue(null, ATTR_WEIGHT);
+ int weight = weightStr == null ? FontStyle.FONT_WEIGHT_NORMAL : Integer.parseInt(weightStr);
+ boolean isItalic = STYLE_ITALIC.equals(parser.getAttributeValue(null, ATTR_STYLE));
+ String fallbackFor = parser.getAttributeValue(null, ATTR_FALLBACK_FOR);
StringBuilder filename = new StringBuilder();
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() == XmlPullParser.TEXT) {
@@ -189,7 +238,7 @@ public class FontListParser {
}
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
String tag = parser.getName();
- if (tag.equals("axis")) {
+ if (tag.equals(TAG_AXIS)) {
axes.add(readAxis(parser));
} else {
skip(parser);
@@ -237,14 +286,48 @@ public class FontListParser {
return null;
}
+ private static void writeFont(TypedXmlSerializer out, FontConfig.Font font)
+ throws IOException {
+ if (font.getTtcIndex() != 0) {
+ out.attributeInt(null, ATTR_INDEX, font.getTtcIndex());
+ }
+ if (font.getStyle().getWeight() != FontStyle.FONT_WEIGHT_NORMAL) {
+ out.attributeInt(null, ATTR_WEIGHT, font.getStyle().getWeight());
+ }
+ if (font.getStyle().getSlant() == FontStyle.FONT_SLANT_ITALIC) {
+ out.attribute(null, ATTR_STYLE, STYLE_ITALIC);
+ } else {
+ out.attribute(null, ATTR_STYLE, STYLE_NORMAL);
+ }
+ if (!TextUtils.isEmpty(font.getFontFamilyName())) {
+ out.attribute(null, ATTR_FALLBACK_FOR, font.getFontFamilyName());
+ }
+ out.text(font.getFile().getName());
+ FontVariationAxis[] axes =
+ FontVariationAxis.fromFontVariationSettings(font.getFontVariationSettings());
+ if (axes != null) {
+ for (FontVariationAxis axis : axes) {
+ out.startTag(null, TAG_AXIS);
+ writeAxis(out, axis);
+ out.endTag(null, TAG_AXIS);
+ }
+ }
+ }
+
private static FontVariationAxis readAxis(XmlPullParser parser)
throws XmlPullParserException, IOException {
- String tagStr = parser.getAttributeValue(null, "tag");
- String styleValueStr = parser.getAttributeValue(null, "stylevalue");
+ String tagStr = parser.getAttributeValue(null, ATTR_TAG);
+ String styleValueStr = parser.getAttributeValue(null, ATTR_STYLEVALUE);
skip(parser); // axis tag is empty, ignore any contents and consume end tag
return new FontVariationAxis(tagStr, Float.parseFloat(styleValueStr));
}
+ private static void writeAxis(TypedXmlSerializer out, FontVariationAxis axis)
+ throws IOException {
+ out.attribute(null, ATTR_TAG, axis.getTag());
+ out.attributeFloat(null, ATTR_STYLEVALUE, axis.getStyleValue());
+ }
+
/**
* Reads alias elements
*/
@@ -255,7 +338,7 @@ public class FontListParser {
String weightStr = parser.getAttributeValue(null, "weight");
int weight;
if (weightStr == null) {
- weight = 400;
+ weight = FontStyle.FONT_WEIGHT_NORMAL;
} else {
weight = Integer.parseInt(weightStr);
}
diff --git a/graphics/java/android/graphics/RenderEffect.java b/graphics/java/android/graphics/RenderEffect.java
index 496e4707dbff..ad4c3fe86175 100644
--- a/graphics/java/android/graphics/RenderEffect.java
+++ b/graphics/java/android/graphics/RenderEffect.java
@@ -190,7 +190,7 @@ public final class RenderEffect {
}
/**
- * Create a filter that applies the color filter to the provided RenderEffect
+ * Create a {@link RenderEffect} that applies the color filter to the provided RenderEffect
*
* @param colorFilter ColorFilter applied to the content in the input RenderEffect
* @param renderEffect Source to be transformed by the specified {@link ColorFilter}
@@ -209,7 +209,7 @@ public final class RenderEffect {
}
/**
- * Create a filter that applies the color filter to the contents of the
+ * Create a {@link RenderEffect} that applies the color filter to the contents of the
* {@link android.graphics.RenderNode} that this RenderEffect is installed on
* @param colorFilter ColorFilter applied to the content in the input RenderEffect
*/
@@ -224,7 +224,7 @@ public final class RenderEffect {
}
/**
- * {@link RenderEffect} that is a composition of 2 other {@link RenderEffect} instances
+ * Create a {@link RenderEffect} that is a composition of 2 other {@link RenderEffect} instances
* combined by the specified {@link BlendMode}
*
* @param dst The Dst pixels used in blending
@@ -248,8 +248,8 @@ public final class RenderEffect {
}
/**
- * Create a filter that composes 'inner' with 'outer', such that the results of 'inner' are
- * treated as the source bitmap passed to 'outer', i.e.
+ * Create a {@link RenderEffect} that composes 'inner' with 'outer', such that the results of
+ * 'inner' are treated as the source bitmap passed to 'outer', i.e.
*
* <pre>
* {@code
@@ -278,6 +278,18 @@ public final class RenderEffect {
);
}
+ /**
+ * Create a {@link RenderEffect} that renders the contents of the input {@link Shader}.
+ * This is useful to create an input for other {@link RenderEffect} types such as
+ * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, TileMode)}
+ * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, TileMode)} or
+ * {@link RenderEffect#createColorFilterEffect(ColorFilter, RenderEffect)}.
+ */
+ @NonNull
+ public static RenderEffect createShaderEffect(@NonNull Shader shader) {
+ return new RenderEffect(nativeCreateShaderEffect(shader.getNativeInstance()));
+ }
+
private final long mNativeRenderEffect;
/* only constructed from static factory methods */
@@ -305,5 +317,6 @@ public final class RenderEffect {
private static native long nativeCreateColorFilterEffect(long colorFilter, long nativeInput);
private static native long nativeCreateBlendModeEffect(long dst, long src, int blendmode);
private static native long nativeCreateChainEffect(long outer, long inner);
+ private static native long nativeCreateShaderEffect(long shader);
private static native long nativeGetFinalizer();
}
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 9214ff1eb088..b153c995a7f4 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -26,8 +26,7 @@ import android.graphics.Paint;
import android.graphics.RectF;
import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
-import android.util.Log;
-import android.util.LongSparseArray;
+import android.text.TextUtils;
import android.util.LongSparseLongArray;
import android.util.TypedValue;
@@ -44,7 +43,6 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
@@ -61,14 +59,9 @@ public final class Font {
private static final int STYLE_ITALIC = 1;
private static final int STYLE_NORMAL = 0;
- private static final Object MAP_LOCK = new Object();
- // We need to have mapping from native ptr to Font object for later accessing from TextShape
- // result since Typeface doesn't have reference to Font object and it is not always created from
- // Font object. Sometimes Typeface is created in native layer only and there might not be Font
- // object in Java layer. So, if not found in this cache, create new Font object for API user.
- @GuardedBy("MAP_LOCK")
- private static final LongSparseArray<WeakReference<Font>> FONT_PTR_MAP =
- new LongSparseArray<>();
+ private static final NativeAllocationRegistry BUFFER_REGISTRY =
+ NativeAllocationRegistry.createMalloced(
+ ByteBuffer.class.getClassLoader(), nGetReleaseNativeFont());
private static final Object SOURCE_ID_LOCK = new Object();
@GuardedBy("SOURCE_ID_LOCK")
@@ -79,9 +72,7 @@ public final class Font {
* A builder class for creating new Font.
*/
public static final class Builder {
- private static final NativeAllocationRegistry sFontRegistry =
- NativeAllocationRegistry.createMalloced(Font.class.getClassLoader(),
- nGetReleaseNativeFont());
+
private @Nullable ByteBuffer mBuffer;
private @Nullable File mFile;
@@ -484,26 +475,15 @@ public final class Font {
final String filePath = mFile == null ? "" : mFile.getAbsolutePath();
long ptr;
- int fontIdentifier;
+ final Font font;
if (mFont == null) {
ptr = nBuild(builderPtr, readonlyBuffer, filePath, mLocaleList, mWeight, italic,
mTtcIndex);
- long fontBufferPtr = nGetFontBufferAddress(ptr);
- synchronized (SOURCE_ID_LOCK) {
- long id = FONT_SOURCE_ID_MAP.get(fontBufferPtr, -1);
- if (id == -1) {
- id = FONT_SOURCE_ID_MAP.size();
- FONT_SOURCE_ID_MAP.put(fontBufferPtr, id);
- }
- fontIdentifier = (int) id;
- }
+ font = new Font(ptr);
} else {
ptr = nClone(mFont.getNativePtr(), builderPtr, mWeight, italic, mTtcIndex);
- fontIdentifier = mFont.mSourceIdentifier;
+ font = new Font(ptr);
}
- final Font font = new Font(ptr, readonlyBuffer, mFile,
- new FontStyle(mWeight, slant), mTtcIndex, mAxes, mLocaleList, fontIdentifier);
- sFontRegistry.registerNativeAllocation(font, ptr);
return font;
}
@@ -525,33 +505,32 @@ public final class Font {
}
private final long mNativePtr; // address of the shared ptr of minikin::Font
- private final @NonNull ByteBuffer mBuffer;
- private final @Nullable File mFile;
- private final FontStyle mFontStyle;
- private final @IntRange(from = 0) int mTtcIndex;
- private final @Nullable FontVariationAxis[] mAxes;
- private final @NonNull String mLocaleList;
- private final int mSourceIdentifier; // An identifier of font source data.
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private @NonNull ByteBuffer mBuffer = null;
+ @GuardedBy("mLock")
+ private boolean mIsFileInitialized = false;
+ @GuardedBy("mLock")
+ private @Nullable File mFile = null;
+ @GuardedBy("mLock")
+ private FontStyle mFontStyle = null;
+ @GuardedBy("mLock")
+ private @Nullable FontVariationAxis[] mAxes = null;
+ @GuardedBy("mLock")
+ private @NonNull LocaleList mLocaleList = null;
+ @GuardedBy("mLock")
+ private int mSourceIdentifier = -1;
/**
* Use Builder instead
+ *
+ * Caller must increment underlying minikin::Font ref count.
+ *
+ * @hide
*/
- private Font(long nativePtr, @NonNull ByteBuffer buffer, @Nullable File file,
- @NonNull FontStyle fontStyle, @IntRange(from = 0) int ttcIndex,
- @Nullable FontVariationAxis[] axes, @NonNull String localeList,
- int sourceIdentifier) {
- mBuffer = buffer;
- mFile = file;
- mFontStyle = fontStyle;
+ public Font(long nativePtr) {
mNativePtr = nativePtr;
- mTtcIndex = ttcIndex;
- mAxes = axes;
- mLocaleList = localeList;
- mSourceIdentifier = sourceIdentifier;
-
- synchronized (MAP_LOCK) {
- FONT_PTR_MAP.append(nGetNativeFontPtr(mNativePtr), new WeakReference<>(this));
- }
}
/**
@@ -563,7 +542,22 @@ public final class Font {
* @return a font buffer
*/
public @NonNull ByteBuffer getBuffer() {
- return mBuffer;
+ synchronized (mLock) {
+ if (mBuffer == null) {
+ // Create new instance of native FontWrapper, i.e. incrementing ref count of
+ // minikin Font instance for keeping buffer fo ByteBuffer reference which may live
+ // longer than this object.
+ long ref = nCloneFont(mNativePtr);
+ ByteBuffer fromNative = nNewByteBuffer(mNativePtr);
+
+ // Bind ByteBuffer's lifecycle with underlying font object.
+ BUFFER_REGISTRY.registerNativeAllocation(fromNative, ref);
+
+ // JNI NewDirectBuffer creates writable ByteBuffer even if it is mmaped readonly.
+ mBuffer = fromNative.asReadOnlyBuffer();
+ }
+ return mBuffer;
+ }
}
/**
@@ -574,7 +568,16 @@ public final class Font {
* @return a file path of the font
*/
public @Nullable File getFile() {
- return mFile;
+ synchronized (mLock) {
+ if (!mIsFileInitialized) {
+ String path = nGetFontPath(mNativePtr);
+ if (!TextUtils.isEmpty(path)) {
+ mFile = new File(path);
+ }
+ mIsFileInitialized = true;
+ }
+ return mFile;
+ }
}
/**
@@ -585,7 +588,16 @@ public final class Font {
* @return a font style
*/
public @NonNull FontStyle getStyle() {
- return mFontStyle;
+ synchronized (mLock) {
+ if (mFontStyle == null) {
+ int packedStyle = nGetPackedStyle(mNativePtr);
+ mFontStyle = new FontStyle(
+ FontFileUtil.unpackWeight(packedStyle),
+ FontFileUtil.unpackItalic(packedStyle)
+ ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);
+ }
+ return mFontStyle;
+ }
}
/**
@@ -597,7 +609,7 @@ public final class Font {
* @return a TTC index value
*/
public @IntRange(from = 0) int getTtcIndex() {
- return mTtcIndex;
+ return nGetIndex(mNativePtr);
}
/**
@@ -608,7 +620,23 @@ public final class Font {
* @return font variation settings
*/
public @Nullable FontVariationAxis[] getAxes() {
- return mAxes == null ? null : mAxes.clone();
+ synchronized (mLock) {
+ if (mAxes == null) {
+ int axisCount = nGetAxisCount(mNativePtr);
+ mAxes = new FontVariationAxis[axisCount];
+ char[] charBuffer = new char[4];
+ for (int i = 0; i < axisCount; ++i) {
+ long packedAxis = nGetAxisInfo(mNativePtr, i);
+ float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
+ charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >>> 56);
+ charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >>> 48);
+ charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >>> 40);
+ charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >>> 32);
+ mAxes[i] = new FontVariationAxis(new String(charBuffer), value);
+ }
+ }
+ }
+ return mAxes;
}
/**
@@ -618,7 +646,17 @@ public final class Font {
* @return a locale list
*/
public @NonNull LocaleList getLocaleList() {
- return LocaleList.forLanguageTags(mLocaleList);
+ synchronized (mLock) {
+ if (mLocaleList == null) {
+ String langTags = nGetLocaleList(mNativePtr);
+ if (TextUtils.isEmpty(langTags)) {
+ mLocaleList = LocaleList.getEmptyLocaleList();
+ } else {
+ mLocaleList = LocaleList.forLanguageTags(langTags);
+ }
+ }
+ return mLocaleList;
+ }
}
/**
@@ -713,7 +751,20 @@ public final class Font {
* @return an unique identifier for the font source data.
*/
public int getSourceIdentifier() {
- return mSourceIdentifier;
+ synchronized (mLock) {
+ if (mSourceIdentifier == -1) {
+ long bufferAddress = nGetBufferAddress(mNativePtr);
+ synchronized (SOURCE_ID_LOCK) {
+ long id = FONT_SOURCE_ID_MAP.get(bufferAddress, -1);
+ if (id == -1) {
+ id = FONT_SOURCE_ID_MAP.size();
+ FONT_SOURCE_ID_MAP.append(bufferAddress, id);
+ }
+ mSourceIdentifier = (int) id;
+ }
+ }
+ return mSourceIdentifier;
+ }
}
/**
@@ -736,13 +787,16 @@ public final class Font {
private boolean isSameSource(@NonNull Font other) {
Objects.requireNonNull(other);
+ ByteBuffer myBuffer = getBuffer();
+ ByteBuffer otherBuffer = other.getBuffer();
+
// Shortcut for the same instance.
- if (mBuffer == other.mBuffer) {
+ if (myBuffer == otherBuffer) {
return true;
}
// Shortcut for different font buffer check by comparing size.
- if (mBuffer.capacity() != other.mBuffer.capacity()) {
+ if (myBuffer.capacity() != otherBuffer.capacity()) {
return false;
}
@@ -750,15 +804,15 @@ public final class Font {
// underlying native font object holds buffer address, check if this buffer points exactly
// the same address as a shortcut of equality. For being compatible with of API30 or before,
// check buffer position even if the buffer points the same address.
- if (mSourceIdentifier == other.mSourceIdentifier
- && mBuffer.position() == other.mBuffer.position()) {
+ if (getSourceIdentifier() == other.getSourceIdentifier()
+ && myBuffer.position() == otherBuffer.position()) {
return true;
}
// Unfortunately, need to compare bytes one-by-one since the buffer may be different font
// file but has the same file size, or two font has same content but they are allocated
// differently. For being compatible with API30 ore before, compare with ByteBuffer#equals.
- return mBuffer.equals(other.mBuffer);
+ return myBuffer.equals(otherBuffer);
}
@Override
@@ -769,10 +823,20 @@ public final class Font {
if (!(o instanceof Font)) {
return false;
}
+
Font f = (Font) o;
- boolean paramEqual = mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex
- && Arrays.equals(f.mAxes, mAxes) && Objects.equals(f.mLocaleList, mLocaleList)
- && Objects.equals(mFile, f.mFile);
+
+ // The underlying minikin::Font object is the source of the truth of font information. Thus,
+ // Pointer equality is the object equality.
+ if (nGetMinikinFontPtr(mNativePtr) == nGetMinikinFontPtr(f.mNativePtr)) {
+ return true;
+ }
+
+ boolean paramEqual = f.getStyle().equals(getStyle())
+ && f.getTtcIndex() == getTtcIndex()
+ && Arrays.equals(f.getAxes(), getAxes())
+ && Objects.equals(f.getLocaleList(), getLocaleList())
+ && Objects.equals(getFile(), f.getFile());
if (!paramEqual) {
return false;
@@ -784,64 +848,42 @@ public final class Font {
@Override
public int hashCode() {
return Objects.hash(
- mFontStyle,
- mTtcIndex,
- Arrays.hashCode(mAxes),
+ getStyle(),
+ getTtcIndex(),
+ Arrays.hashCode(getAxes()),
// Use Buffer size instead of ByteBuffer#hashCode since ByteBuffer#hashCode traverse
// data which is not performant e.g. for HashMap. The hash collision are less likely
// happens because it is unlikely happens the different font files has exactly the
// same size.
- mLocaleList);
+ getLocaleList());
}
@Override
public String toString() {
return "Font {"
- + "path=" + mFile
- + ", style=" + mFontStyle
- + ", ttcIndex=" + mTtcIndex
- + ", axes=" + FontVariationAxis.toFontVariationSettings(mAxes)
- + ", localeList=" + mLocaleList
- + ", buffer=" + mBuffer
+ + "path=" + getFile()
+ + ", style=" + getStyle()
+ + ", ttcIndex=" + getTtcIndex()
+ + ", axes=" + FontVariationAxis.toFontVariationSettings(getAxes())
+ + ", localeList=" + getLocaleList()
+ + ", buffer=" + getBuffer()
+ "}";
}
- /**
- * Lookup Font object from native pointer or create new one if not found.
- * @hide
- */
- public static Font findOrCreateFontFromNativePtr(long ptr) {
- // First, lookup from known mapps.
- synchronized (MAP_LOCK) {
- WeakReference<Font> fontRef = FONT_PTR_MAP.get(ptr);
- if (fontRef != null) {
- Font font = fontRef.get();
- if (font != null) {
- return font;
- }
- }
+ @CriticalNative
+ private static native long nGetMinikinFontPtr(long font);
- // If not found, create Font object from native object for Java API users.
- ByteBuffer buffer = NativeFontBufferHelper.refByteBuffer(ptr);
- NativeFont.Font font = NativeFont.readNativeFont(ptr);
+ @CriticalNative
+ private static native long nCloneFont(long font);
- Font.Builder builder = new Font.Builder(buffer, font.getFile(), "")
- .setWeight(font.getStyle().getWeight())
- .setSlant(font.getStyle().getSlant())
- .setTtcIndex(font.getIndex())
- .setFontVariationSettings(font.getAxes());
+ @FastNative
+ private static native ByteBuffer nNewByteBuffer(long font);
- Font newFont = null;
- try {
- newFont = builder.build();
- FONT_PTR_MAP.append(ptr, new WeakReference<>(newFont));
- } catch (IOException e) {
- // This must not happen since the buffer was already created once.
- Log.e("Font", "Failed to create font object from existing buffer.", e);
- }
- return newFont;
- }
- }
+ @CriticalNative
+ private static native long nGetBufferAddress(long font);
+
+ @CriticalNative
+ private static native long nGetReleaseNativeFont();
@FastNative
private static native float nGetGlyphBounds(long font, int glyphId, long paint, RectF rect);
@@ -849,9 +891,21 @@ public final class Font {
@FastNative
private static native float nGetFontMetrics(long font, long paint, Paint.FontMetrics metrics);
+ @FastNative
+ private static native String nGetFontPath(long fontPtr);
+
+ @FastNative
+ private static native String nGetLocaleList(long familyPtr);
+
+ @CriticalNative
+ private static native int nGetPackedStyle(long fontPtr);
+
+ @CriticalNative
+ private static native int nGetIndex(long fontPtr);
+
@CriticalNative
- private static native long nGetNativeFontPtr(long ptr);
+ private static native int nGetAxisCount(long fontPtr);
@CriticalNative
- private static native long nGetFontBufferAddress(long font);
+ private static native long nGetAxisInfo(long fontPtr, int i);
}
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index 77f86fe726f3..8c13d3e7e51d 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -143,12 +143,10 @@ public final class FontFamily {
private static native long nGetReleaseNativeFamily();
}
- private final ArrayList<Font> mFonts;
private final long mNativePtr;
// Use Builder instead.
private FontFamily(@NonNull ArrayList<Font> fonts, long ptr) {
- mFonts = fonts;
mNativePtr = ptr;
}
@@ -176,7 +174,10 @@ public final class FontFamily {
* @return a registered font
*/
public @NonNull Font getFont(@IntRange(from = 0) int index) {
- return mFonts.get(index);
+ if (index < 0 || getSize() <= index) {
+ throw new IndexOutOfBoundsException();
+ }
+ return new Font(nGetFont(mNativePtr, index));
}
/**
@@ -185,7 +186,7 @@ public final class FontFamily {
* @return the number of fonts registered in this family.
*/
public @IntRange(from = 1) int getSize() {
- return mFonts.size();
+ return nGetFontSize(mNativePtr);
}
/** @hide */
@@ -193,6 +194,12 @@ public final class FontFamily {
return mNativePtr;
}
+ @CriticalNative
+ private static native int nGetFontSize(long family);
+
+ @CriticalNative
+ private static native long nGetFont(long family, int i);
+
@FastNative
private static native String nGetLangTags(long family);
diff --git a/graphics/java/android/graphics/fonts/NativeFont.java b/graphics/java/android/graphics/fonts/NativeFont.java
deleted file mode 100644
index 9e9d76a89385..000000000000
--- a/graphics/java/android/graphics/fonts/NativeFont.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics.fonts;
-
-import android.graphics.Typeface;
-
-import dalvik.annotation.optimization.CriticalNative;
-import dalvik.annotation.optimization.FastNative;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Read native font objects.
- *
- * @hide
- */
-public class NativeFont {
-
- /**
- * Represents native font object.
- */
- public static final class Font {
- private final File mFile;
- private final int mIndex;
- private final FontVariationAxis[] mAxes;
- private final FontStyle mStyle;
-
- public Font(File file, int index, FontVariationAxis[] axes, FontStyle style) {
- mFile = file;
- mIndex = index;
- mAxes = axes;
- mStyle = style;
- }
-
- public File getFile() {
- return mFile;
- }
-
- public FontVariationAxis[] getAxes() {
- return mAxes;
- }
-
- public FontStyle getStyle() {
- return mStyle;
- }
-
- public int getIndex() {
- return mIndex;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Font font = (Font) o;
- return mIndex == font.mIndex && mFile.equals(font.mFile)
- && Arrays.equals(mAxes, font.mAxes) && mStyle.equals(font.mStyle);
- }
-
- @Override
- public int hashCode() {
- int result = Objects.hash(mFile, mIndex, mStyle);
- result = 31 * result + Arrays.hashCode(mAxes);
- return result;
- }
- }
-
- /**
- * Represents native font family object.
- */
- public static final class Family {
- private final List<Font> mFonts;
- private final String mLocale;
-
- public Family(List<Font> fonts, String locale) {
- mFonts = fonts;
- mLocale = locale;
- }
-
- public List<Font> getFonts() {
- return mFonts;
- }
-
- public String getLocale() {
- return mLocale;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Family family = (Family) o;
- return mFonts.equals(family.mFonts) && mLocale.equals(family.mLocale);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mFonts, mLocale);
- }
- }
-
- /**
- * Get underlying font families from Typeface
- *
- * @param typeface a typeface
- * @return list of family
- */
- public static List<Family> readTypeface(Typeface typeface) {
- int familyCount = nGetFamilyCount(typeface.native_instance);
- List<Family> result = new ArrayList<>(familyCount);
- for (int i = 0; i < familyCount; ++i) {
- result.add(readNativeFamily(nGetFamily(typeface.native_instance, i)));
- }
- return result;
- }
-
- /**
- * Read family object from native pointer
- *
- * @param familyPtr a font family pointer
- * @return a family
- */
- public static Family readNativeFamily(long familyPtr) {
- int fontCount = nGetFontCount(familyPtr);
- List<Font> result = new ArrayList<>(fontCount);
- for (int i = 0; i < fontCount; ++i) {
- result.add(readNativeFont(nGetFont(familyPtr, i)));
- }
- String localeList = nGetLocaleList(familyPtr);
- return new Family(result, localeList);
- }
-
- /**
- * Read font object from native pointer.
- *
- * @param ptr a font pointer
- * @return a font
- */
- public static Font readNativeFont(long ptr) {
- long packed = nGetFontInfo(ptr);
- int weight = (int) (packed & 0x0000_0000_0000_FFFFL);
- boolean italic = (packed & 0x0000_0000_0001_0000L) != 0;
- int ttcIndex = (int) ((packed & 0x0000_FFFF_0000_0000L) >> 32);
- int axisCount = (int) ((packed & 0xFFFF_0000_0000_0000L) >> 48);
- FontVariationAxis[] axes = new FontVariationAxis[axisCount];
- char[] charBuffer = new char[4];
- for (int i = 0; i < axisCount; ++i) {
- long packedAxis = nGetAxisInfo(ptr, i);
- float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
- charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >> 56);
- charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >> 48);
- charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >> 40);
- charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >> 32);
- axes[i] = new FontVariationAxis(new String(charBuffer), value);
- }
- String path = nGetFontPath(ptr);
- File file = (path == null) ? null : new File(path);
- FontStyle style = new FontStyle(weight,
- italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);
-
- return new Font(file, ttcIndex, axes, style);
- }
-
- @CriticalNative
- private static native int nGetFamilyCount(long ptr);
-
- @CriticalNative
- private static native long nGetFamily(long ptr, int index);
-
- @FastNative
- private static native String nGetLocaleList(long familyPtr);
-
- @CriticalNative
- private static native long nGetFont(long familyPtr, int fontIndex);
-
- @CriticalNative
- private static native int nGetFontCount(long familyPtr);
-
- @CriticalNative
- private static native long nGetFontInfo(long fontPtr);
-
- @CriticalNative
- private static native long nGetAxisInfo(long fontPtr, int i);
-
- @FastNative
- private static native String nGetFontPath(long fontPtr);
-}
diff --git a/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java b/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java
deleted file mode 100644
index 5655e7fafc1b..000000000000
--- a/graphics/java/android/graphics/fonts/NativeFontBufferHelper.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics.fonts;
-
-import android.annotation.NonNull;
-
-import dalvik.annotation.optimization.CriticalNative;
-import dalvik.annotation.optimization.FastNative;
-
-import libcore.util.NativeAllocationRegistry;
-
-import java.nio.ByteBuffer;
-
-/**
- * This is a helper class for showing native allocated buffer in Java API.
- *
- * @hide
- */
-public class NativeFontBufferHelper {
- private NativeFontBufferHelper() {}
-
- private static final NativeAllocationRegistry REGISTRY =
- NativeAllocationRegistry.createMalloced(
- ByteBuffer.class.getClassLoader(), nGetReleaseFunc());
-
- /**
- * Wrap native buffer with ByteBuffer with adding reference to it.
- */
- public static @NonNull ByteBuffer refByteBuffer(long fontPtr) {
- long refPtr = nRefFontBuffer(fontPtr);
- ByteBuffer buffer = nWrapByteBuffer(refPtr);
-
- // Releasing native object so that decreasing shared pointer ref count when the byte buffer
- // is GCed.
- REGISTRY.registerNativeAllocation(buffer, refPtr);
-
- return buffer;
- }
-
- @CriticalNative
- private static native long nRefFontBuffer(long fontPtr);
-
- @FastNative
- private static native ByteBuffer nWrapByteBuffer(long refPtr);
-
- @CriticalNative
- private static native long nGetReleaseFunc();
-}
diff --git a/graphics/java/android/graphics/text/PositionedGlyphs.java b/graphics/java/android/graphics/text/PositionedGlyphs.java
index c2de0acebca9..8d20e9cee7d7 100644
--- a/graphics/java/android/graphics/text/PositionedGlyphs.java
+++ b/graphics/java/android/graphics/text/PositionedGlyphs.java
@@ -184,7 +184,7 @@ public final class PositionedGlyphs {
long ptr = nGetFont(layoutPtr, i);
if (prevPtr != ptr) {
prevPtr = ptr;
- prevFont = Font.findOrCreateFontFromNativePtr(ptr);
+ prevFont = new Font(ptr);
}
mFonts.add(prevFont);
}
@@ -224,9 +224,7 @@ public final class PositionedGlyphs {
if (getGlyphId(i) != that.getGlyphId(i)) return false;
if (getGlyphX(i) != that.getGlyphX(i)) return false;
if (getGlyphY(i) != that.getGlyphY(i)) return false;
- // Intentionally using reference equality since font equality is heavy due to buffer
- // compare.
- if (getFont(i) != that.getFont(i)) return false;
+ if (!getFont(i).equals(that.getFont(i))) return false;
}
return true;
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu.xml b/libs/WindowManager/Shell/res/layout/pip_menu.xml
index 93a6e7b70c54..b581f555c234 100644
--- a/libs/WindowManager/Shell/res/layout/pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/pip_menu.xml
@@ -97,14 +97,4 @@
android:padding="@dimen/pip_resize_handle_padding"
android:src="@drawable/pip_resize_handle"
android:background="?android:selectableItemBackgroundBorderless" />
-
- <!-- invisible layer to trap the focus, b/169372603 -->
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- android:defaultFocusHighlightEnabled="false"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:focusedByDefault="true" />
-t </FrameLayout>
+</FrameLayout>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index fe97e24fac41..982cc006e331 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -25,6 +25,7 @@ import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import java.io.PrintWriter;
import java.util.Optional;
@@ -38,7 +39,7 @@ public final class ShellCommandHandlerImpl {
private static final String TAG = ShellCommandHandlerImpl.class.getSimpleName();
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
- private final Optional<SplitScreen> mSplitScreenOptional;
+ private final Optional<SplitScreenController> mSplitScreenOptional;
private final Optional<Pip> mPipOptional;
private final Optional<OneHanded> mOneHandedOptional;
private final Optional<HideDisplayCutout> mHideDisplayCutout;
@@ -50,7 +51,7 @@ public final class ShellCommandHandlerImpl {
public static ShellCommandHandler create(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
- Optional<SplitScreen> splitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout,
@@ -64,7 +65,7 @@ public final class ShellCommandHandlerImpl {
private ShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
- Optional<SplitScreen> splitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index 0958a070c82d..925bf4bbb01c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -25,6 +25,7 @@ import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -39,7 +40,7 @@ public class ShellInitImpl {
private final DragAndDropController mDragAndDropController;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
- private final Optional<SplitScreen> mSplitScreenOptional;
+ private final Optional<SplitScreenController> mSplitScreenOptional;
private final Optional<AppPairs> mAppPairsOptional;
private final FullscreenTaskListener mFullscreenTaskListener;
private final ShellExecutor mMainExecutor;
@@ -51,7 +52,7 @@ public class ShellInitImpl {
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
- Optional<SplitScreen> splitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
@@ -71,7 +72,7 @@ public class ShellInitImpl {
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
- Optional<SplitScreen> splitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
@@ -97,7 +98,7 @@ public class ShellInitImpl {
mShellTaskOrganizer.registerOrganizer();
mAppPairsOptional.ifPresent(AppPairs::onOrganizerRegistered);
- mSplitScreenOptional.ifPresent(SplitScreen::onOrganizerRegistered);
+ mSplitScreenOptional.ifPresent(SplitScreenController::onOrganizerRegistered);
// Bind the splitscreen impl to the drag drop controller
mDragAndDropController.initialize(mSplitScreenOptional);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 616f24a874bc..fb70cbe502b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -40,9 +40,11 @@ import android.view.IWindowSessionCallback;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.SurfaceControl;
+import android.view.SurfaceSession;
import android.view.SurfaceControlViewHost;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
import android.window.ClientWindowFrames;
@@ -251,6 +253,8 @@ public class SystemWindows {
public class SysUiWindowManager extends WindowlessWindowManager {
final int mDisplayId;
ContainerWindow mContainerWindow;
+ final HashMap<IBinder, SurfaceControl> mLeashForWindow =
+ new HashMap<IBinder, SurfaceControl>();
public SysUiWindowManager(int displayId, Context ctx, SurfaceControl rootSurface,
ContainerWindow container) {
super(ctx.getResources().getConfiguration(), rootSurface, null /* hostInputToken */);
@@ -263,7 +267,33 @@ public class SystemWindows {
}
SurfaceControl getSurfaceControlForWindow(View rootView) {
- return getSurfaceControl(rootView);
+ synchronized (this) {
+ return mLeashForWindow.get(getWindowBinder(rootView));
+ }
+ }
+
+ protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+ SurfaceControl leash = new SurfaceControl.Builder(new SurfaceSession())
+ .setContainerLayer()
+ .setName("SystemWindowLeash")
+ .setHidden(false)
+ .setParent(mRootSurface)
+ .setCallsite("SysUiWIndowManager#attachToParentSurface").build();
+ synchronized (this) {
+ mLeashForWindow.put(window.asBinder(), leash);
+ }
+ b.setParent(leash);
+ }
+
+ @Override
+ public void remove(android.view.IWindow window) throws RemoteException {
+ super.remove(window);
+ synchronized(this) {
+ IBinder token = window.asBinder();
+ new SurfaceControl.Transaction().remove(mLeashForWindow.get(token))
+ .apply();
+ mLeashForWindow.remove(token);
+ }
}
void setTouchableRegionForWindow(View rootView, Region region) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 7f9c34f5df7a..728f60d93497 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -87,7 +87,7 @@ public final class SplitWindowManager extends WindowlessWindowManager {
}
@Override
- protected void attachToParentSurface(SurfaceControl.Builder b) {
+ protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
mParentContainerCallbacks.attachToParentSurface(b);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index c8938ad40aba..17709438baba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -53,6 +53,7 @@ import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.Optional;
@@ -66,7 +67,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
private final Context mContext;
private final DisplayController mDisplayController;
- private SplitScreen mSplitScreen;
+ private SplitScreenController mSplitScreen;
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
@@ -76,7 +77,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
mDisplayController = displayController;
}
- public void initialize(Optional<SplitScreen> splitscreen) {
+ public void initialize(Optional<SplitScreenController> splitscreen) {
mSplitScreen = splitscreen.orElse(null);
mDisplayController.addDisplayWindowListener(this);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 35dcdd5923a8..6f5f2eb5723c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -64,7 +64,9 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreen.StagePosition;
+import com.android.wm.shell.splitscreen.SplitScreen.StageType;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -81,18 +83,18 @@ public class DragAndDropPolicy {
private final Context mContext;
private final ActivityTaskManager mActivityTaskManager;
private final Starter mStarter;
- private final SplitScreen mSplitScreen;
+ private final SplitScreenController mSplitScreen;
private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
private DragSession mSession;
- public DragAndDropPolicy(Context context, SplitScreen splitScreen) {
+ public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
this(context, ActivityTaskManager.getInstance(), splitScreen, new DefaultStarter(context));
}
@VisibleForTesting
DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager,
- SplitScreen splitScreen, Starter starter) {
+ SplitScreenController splitScreen, Starter starter) {
mContext = context;
mActivityTaskManager = activityTaskManager;
mSplitScreen = splitScreen;
@@ -200,8 +202,8 @@ public class DragAndDropPolicy {
final boolean inSplitScreen = mSplitScreen != null && mSplitScreen.isSplitScreenVisible();
final boolean leftOrTop = target.type == TYPE_SPLIT_TOP || target.type == TYPE_SPLIT_LEFT;
- @SplitScreen.StageType int stage = STAGE_TYPE_UNDEFINED;
- @SplitScreen.StagePosition int position = STAGE_POSITION_UNDEFINED;
+ @StageType int stage = STAGE_TYPE_UNDEFINED;
+ @StagePosition int position = STAGE_POSITION_UNDEFINED;
if (target.type != TYPE_FULLSCREEN && mSplitScreen != null) {
// Update launch options for the split side we are targeting.
position = leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -213,7 +215,28 @@ public class DragAndDropPolicy {
final ClipDescription description = data.getDescription();
final Intent dragData = mSession.dragData;
- mStarter.startClipDescription(description, dragData, stage, position);
+ startClipDescription(description, dragData, stage, position);
+ }
+
+ private void startClipDescription(ClipDescription description, Intent intent,
+ @StageType int stage, @StagePosition int position) {
+ final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
+ final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
+ final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)
+ ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : new Bundle();
+
+ if (isTask) {
+ final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
+ mStarter.startTask(taskId, stage, position, opts);
+ } else if (isShortcut) {
+ final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
+ final String id = intent.getStringExtra(EXTRA_SHORTCUT_ID);
+ final UserHandle user = intent.getParcelableExtra(EXTRA_USER);
+ mStarter.startShortcut(packageName, id, stage, position, opts, user);
+ } else {
+ mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT), stage, position,
+ opts);
+ }
}
/**
@@ -267,34 +290,13 @@ public class DragAndDropPolicy {
/**
* Interface for actually committing the task launches.
*/
- @VisibleForTesting
public interface Starter {
- default void startClipDescription(ClipDescription description, Intent intent,
- @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position) {
- final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
- final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
- final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)
- ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : new Bundle();
-
- if (isTask) {
- final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
- startTask(taskId, stage, position, opts);
- } else if (isShortcut) {
- final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
- final String id = intent.getStringExtra(EXTRA_SHORTCUT_ID);
- final UserHandle user = intent.getParcelableExtra(EXTRA_USER);
- startShortcut(packageName, id, stage, position, opts, user);
- } else {
- startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT), stage, position, opts);
- }
- }
- void startTask(int taskId, @SplitScreen.StageType int stage,
- @SplitScreen.StagePosition int position, @Nullable Bundle options);
- void startShortcut(String packageName, String shortcutId,
- @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
- @Nullable Bundle options, UserHandle user);
- void startIntent(PendingIntent intent, @SplitScreen.StageType int stage,
- @SplitScreen.StagePosition int position, @Nullable Bundle options);
+ void startTask(int taskId, @StageType int stage, @StagePosition int position,
+ @Nullable Bundle options);
+ void startShortcut(String packageName, String shortcutId, @StageType int stage,
+ @StagePosition int position, @Nullable Bundle options, UserHandle user);
+ void startIntent(PendingIntent intent, @StageType int stage, @StagePosition int position,
+ @Nullable Bundle options);
void enterSplitScreen(int taskId, boolean leftOrTop);
void exitSplitScreen();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 82c4e440fb15..b3423362347f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -42,7 +42,7 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.ArrayList;
@@ -61,7 +61,7 @@ public class DragLayout extends View {
private boolean mIsShowing;
private boolean mHasDropped;
- public DragLayout(Context context, SplitScreen splitscreen) {
+ public DragLayout(Context context, SplitScreenController splitscreen) {
super(context);
mPolicy = new DragAndDropPolicy(context, splitscreen);
mDisplayMargin = context.getResources().getDimensionPixelSize(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
index e13a1dbe22d6..a18d106abea4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
@@ -862,14 +862,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
* assigned to it.
*/
private SurfaceControl getWindowSurfaceControl() {
- final ViewRootImpl root = getViewRootImpl();
- if (root == null) {
- return null;
- }
- SurfaceControl out = root.getSurfaceControl();
- if (out != null && out.isValid()) {
- return out;
- }
return mWindowManager.mSystemWindows.getViewSurface(this);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 45aa3870ecb6..5ffa9885a143 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -16,6 +16,9 @@
package com.android.wm.shell.pip;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
import android.animation.AnimationHandler;
import android.animation.Animator;
import android.animation.RectEvaluator;
@@ -24,11 +27,13 @@ import android.annotation.IntDef;
import android.app.TaskInfo;
import android.graphics.Rect;
import android.view.Choreographer;
+import android.view.Surface;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.DisplayLayout;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -132,15 +137,21 @@ public class PipAnimationController {
* leash bounds before transformation/any animation. This is so when we try to construct
* the different transformation matrices for the animation, we are constructing this based off
* the PiP original bounds, rather than the {@param startBounds}, which is post-transformed.
+ *
+ * If non-zero {@param rotationDelta} is given, it means that the display will be rotated by
+ * leaving PiP to fullscreen, and the {@param endBounds} is the fullscreen bounds before the
+ * rotation change.
*/
@VisibleForTesting
public PipTransitionAnimator getAnimator(TaskInfo taskInfo, SurfaceControl leash,
Rect baseBounds, Rect startBounds, Rect endBounds, Rect sourceHintRect,
- @PipAnimationController.TransitionDirection int direction, float startingAngle) {
+ @PipAnimationController.TransitionDirection int direction, float startingAngle,
+ @Surface.Rotation int rotationDelta) {
if (mCurrentAnimator == null) {
mCurrentAnimator = setupPipTransitionAnimator(
PipTransitionAnimator.ofBounds(taskInfo, leash, startBounds, startBounds,
- endBounds, sourceHintRect, direction, 0 /* startingAngle */));
+ endBounds, sourceHintRect, direction, 0 /* startingAngle */,
+ rotationDelta));
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
&& mCurrentAnimator.isRunning()) {
// If we are still animating the fade into pip, then just move the surface and ensure
@@ -156,7 +167,7 @@ public class PipAnimationController {
mCurrentAnimator.cancel();
mCurrentAnimator = setupPipTransitionAnimator(
PipTransitionAnimator.ofBounds(taskInfo, leash, baseBounds, startBounds,
- endBounds, sourceHintRect, direction, startingAngle));
+ endBounds, sourceHintRect, direction, startingAngle, rotationDelta));
}
return mCurrentAnimator;
}
@@ -410,7 +421,8 @@ public class PipAnimationController {
static PipTransitionAnimator<Rect> ofBounds(TaskInfo taskInfo, SurfaceControl leash,
Rect baseValue, Rect startValue, Rect endValue, Rect sourceHintRect,
- @PipAnimationController.TransitionDirection int direction, float startingAngle) {
+ @PipAnimationController.TransitionDirection int direction, float startingAngle,
+ @Surface.Rotation int rotationDelta) {
// Just for simplicity we'll interpolate between the source rect hint insets and empty
// insets to calculate the window crop
final Rect initialSourceValue;
@@ -431,6 +443,16 @@ public class PipAnimationController {
}
final Rect sourceInsets = new Rect(0, 0, 0, 0);
+ final Rect rotatedEndRect;
+ if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
+ // Rotate the end bounds according to the rotation delta because the display will
+ // be rotated to the same orientation.
+ rotatedEndRect = new Rect(endValue);
+ DisplayLayout.rotateBounds(rotatedEndRect, endValue, rotationDelta);
+ } else {
+ rotatedEndRect = null;
+ }
+
// construct new Rect instances in case they are recycled
return new PipTransitionAnimator<Rect>(taskInfo, leash, ANIM_TYPE_BOUNDS,
endValue, new Rect(baseValue), new Rect(startValue), new Rect(endValue),
@@ -444,6 +466,12 @@ public class PipAnimationController {
final Rect base = getBaseValue();
final Rect start = getStartValue();
final Rect end = getEndValue();
+ if (rotatedEndRect != null) {
+ // Animate the bounds in a different orientation. It only happens when
+ // leaving PiP to fullscreen.
+ applyRotation(tx, leash, fraction, start, end, rotatedEndRect);
+ return;
+ }
Rect bounds = mRectEvaluator.evaluate(fraction, start, end);
float angle = (1.0f - fraction) * startingAngle;
setCurrentValue(bounds);
@@ -469,6 +497,25 @@ public class PipAnimationController {
tx.apply();
}
+ private void applyRotation(SurfaceControl.Transaction tx, SurfaceControl leash,
+ float fraction, Rect start, Rect end, Rect rotatedEndRect) {
+ final Rect bounds = mRectEvaluator.evaluate(fraction, start, rotatedEndRect);
+ setCurrentValue(bounds);
+ final float degree, x, y;
+ if (rotationDelta == ROTATION_90) {
+ degree = 90 * fraction;
+ x = fraction * (end.right - start.left) + start.left;
+ y = fraction * (end.top - start.top) + start.top;
+ } else {
+ degree = -90 * fraction;
+ x = fraction * (end.left - start.left) + start.left;
+ y = fraction * (end.bottom - start.top) + start.top;
+ }
+ getSurfaceTransactionHelper().rotateAndScaleWithCrop(tx, leash, bounds,
+ rotatedEndRect, degree, x, y);
+ tx.apply();
+ }
+
@Override
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
getSurfaceTransactionHelper()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index a777a2766ee7..97aeda4b053f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -127,6 +127,32 @@ public class PipSurfaceTransactionHelper {
}
/**
+ * Operates the rotation according to the given degrees and scale (setMatrix) according to the
+ * source bounds and rotated destination bounds. The crop will be the unscaled source bounds.
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper rotateAndScaleWithCrop(SurfaceControl.Transaction tx,
+ SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, float degrees,
+ float positionX, float positionY) {
+ mTmpDestinationRect.set(sourceBounds);
+ final int dw = destinationBounds.width();
+ final int dh = destinationBounds.height();
+ // Scale by the short side so there won't be empty area if the aspect ratio of source and
+ // destination are different.
+ final float scale = dw <= dh
+ ? (float) sourceBounds.width() / dw
+ : (float) sourceBounds.height() / dh;
+ // Inverse scale for crop to fit in screen coordinates.
+ mTmpDestinationRect.scale(1 / scale);
+ mTmpTransform.setRotate(degrees);
+ mTmpTransform.postScale(scale, scale);
+ mTmpTransform.postTranslate(positionX, positionY);
+ tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
+ .setWindowCrop(leash, mTmpDestinationRect.width(), mTmpDestinationRect.height());
+ return this;
+ }
+
+ /**
* Resets the scale (setMatrix) on a given transaction and leash if there's any
*
* @return same {@link PipSurfaceTransactionHelper} instance for method chaining
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 fb83006e8522..ad6f435ea907 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
@@ -48,13 +48,12 @@ import android.app.TaskInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
import android.graphics.Rect;
-import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.Rational;
import android.view.Display;
+import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
@@ -72,8 +71,6 @@ import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
@@ -134,7 +131,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private final PipUiEventLogger mPipUiEventLoggerLogger;
private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
- private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
private final Optional<LegacySplitScreen> mSplitScreenOptional;
protected final ShellTaskOrganizer mTaskOrganizer;
protected final ShellExecutor mMainExecutor;
@@ -192,6 +188,12 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private boolean mWaitForFixedRotation;
/**
+ * The rotation that the display will apply after expanding PiP to fullscreen. This is only
+ * meaningful if {@link #mWaitForFixedRotation} is true.
+ */
+ private @Surface.Rotation int mNextRotation;
+
+ /**
* If set to {@code true}, no entering PiP transition would be kicked off and most likely
* it's due to the fact that Launcher is handling the transition directly when swiping
* auto PiP-able Activity to home.
@@ -313,61 +315,40 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return;
}
- final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
- if (initialConfig == null) {
- Log.wtf(TAG, "Token not in record, this should not happen mToken=" + mToken);
- return;
- }
mPipUiEventLoggerLogger.log(
PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
- final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation()
- != mPipBoundsState.getDisplayLayout().rotation();
final WindowContainerTransaction wct = new WindowContainerTransaction();
- final Rect destinationBounds = initialConfig.windowConfiguration.getBounds();
+ final Rect destinationBounds = mPipBoundsState.getDisplayBounds();
final int direction = syncWithSplitScreenBounds(destinationBounds)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_LEAVE_PIP;
- if (orientationDiffers) {
- mState = State.EXITING_PIP;
- // Send started callback though animation is ignored.
- sendOnPipTransitionStarted(direction);
- // Don't bother doing an animation if the display rotation differs or if it's in
- // a non-supported windowing mode
- applyWindowingModeChangeOnExit(wct, direction);
- mTaskOrganizer.applyTransaction(wct);
- // Send finished callback though animation is ignored.
- sendOnPipTransitionFinished(direction);
- } else {
- final SurfaceControl.Transaction tx =
- mSurfaceControlTransactionFactory.getTransaction();
- mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds,
- mPipBoundsState.getBounds());
- tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
- // We set to fullscreen here for now, but later it will be set to UNDEFINED for
- // the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
- wct.setActivityWindowingMode(mToken,
- direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
- ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
- : WINDOWING_MODE_FULLSCREEN);
- wct.setBounds(mToken, destinationBounds);
- wct.setBoundsChangeTransaction(mToken, tx);
- mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() {
- @Override
- public void onTransactionReady(int id, SurfaceControl.Transaction t) {
- mMainExecutor.execute(() -> {
- t.apply();
- // Make sure to grab the latest source hint rect as it could have been
- // updated right after applying the windowing mode change.
- final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
- mPictureInPictureParams, destinationBounds);
- scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds,
- 0 /* startingAngle */, sourceHintRect, direction,
- animationDurationMs, null /* updateBoundsCallback */);
- mState = State.EXITING_PIP;
- });
- }
- });
- }
+ final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
+ mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds, mPipBoundsState.getBounds());
+ tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
+ // We set to fullscreen here for now, but later it will be set to UNDEFINED for
+ // the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
+ wct.setActivityWindowingMode(mToken,
+ direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
+ ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ : WINDOWING_MODE_FULLSCREEN);
+ wct.setBounds(mToken, destinationBounds);
+ wct.setBoundsChangeTransaction(mToken, tx);
+ mTaskOrganizer.applySyncTransaction(wct, new WindowContainerTransactionCallback() {
+ @Override
+ public void onTransactionReady(int id, SurfaceControl.Transaction t) {
+ mMainExecutor.execute(() -> {
+ t.apply();
+ // Make sure to grab the latest source hint rect as it could have been
+ // updated right after applying the windowing mode change.
+ final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
+ mPictureInPictureParams, destinationBounds);
+ scheduleAnimateResizePip(mPipBoundsState.getBounds(), destinationBounds,
+ 0 /* startingAngle */, sourceHintRect, direction,
+ animationDurationMs, null /* updateBoundsCallback */);
+ mState = State.EXITING_PIP;
+ });
+ }
+ });
}
private void applyWindowingModeChangeOnExit(WindowContainerTransaction wct, int direction) {
@@ -399,7 +380,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration)
.start();
- mInitialState.remove(mToken.asBinder());
mState = State.EXITING_PIP;
}
@@ -424,7 +404,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mToken = mTaskInfo.token;
mState = State.TASK_APPEARED;
mLeash = leash;
- mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));
mPictureInPictureParams = mTaskInfo.pictureInPictureParams;
setBoundsStateForEntry(mTaskInfo.topActivity, mPictureInPictureParams,
mTaskInfo.topActivityInfo);
@@ -606,6 +585,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@Override
public void onFixedRotationStarted(int displayId, int newRotation) {
+ mNextRotation = newRotation;
mWaitForFixedRotation = true;
}
@@ -645,7 +625,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipAnimationController.getCurrentAnimator();
if (animator == null || !animator.isRunning()
|| animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) {
- if (mState.isInPip() && fromRotation) {
+ if (mState.isInPip() && fromRotation && !mWaitForFixedRotation) {
// Update bounds state to final destination first. It's important to do this
// before finishing & cancelling the transition animation so that the MotionHelper
// bounds are synchronized to the destination bounds when the animation ends.
@@ -1052,11 +1032,14 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
Log.w(TAG, "Abort animation, invalid leash");
return;
}
+ final int rotationDelta = mWaitForFixedRotation
+ ? ((mNextRotation - mPipBoundsState.getDisplayLayout().rotation()) + 4) % 4
+ : Surface.ROTATION_0;
Rect baseBounds = direction == TRANSITION_DIRECTION_SNAP_AFTER_RESIZE
? mPipBoundsState.getBounds() : currentBounds;
mPipAnimationController
.getAnimator(mTaskInfo, mLeash, baseBounds, currentBounds, destinationBounds,
- sourceHintRect, direction, startingAngle)
+ sourceHintRect, direction, startingAngle, rotationDelta)
.setTransitionDirection(direction)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(durationMs)
@@ -1101,11 +1084,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
pw.println(innerPrefix + "mState=" + mState);
pw.println(innerPrefix + "mOneShotAnimationType=" + mOneShotAnimationType);
pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
- pw.println(innerPrefix + "mInitialState:");
- for (Map.Entry<IBinder, Configuration> e : mInitialState.entrySet()) {
- pw.println(innerPrefix + " binder=" + e.getKey()
- + " winConfig=" + e.getValue().windowConfiguration);
- }
}
@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 91e8c9939244..9b6909b2bd51 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
@@ -30,6 +30,7 @@ import android.app.TaskInfo;
import android.content.Context;
import android.graphics.Rect;
import android.os.IBinder;
+import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -112,7 +113,7 @@ public class PipTransition extends PipTransitionController {
taskInfo.pictureInPictureParams, currentBounds);
animator = mPipAnimationController.getAnimator(taskInfo, leash,
currentBounds, currentBounds, destinationBounds, sourceHintRect,
- TRANSITION_DIRECTION_TO_PIP, 0 /* startingAngle */);
+ TRANSITION_DIRECTION_TO_PIP, 0 /* startingAngle */, Surface.ROTATION_0);
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
t.setAlpha(leash, 0f);
t.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index a57eee83ef59..ae5300502993 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -198,8 +198,7 @@ public class PhonePipMenuController implements PipMenuController {
* {@code null}), it will get the leash that the WindowlessWM has assigned to it.
*/
public SurfaceControl getSurfaceControl() {
- SurfaceControl sf = mPipMenuView.getWindowSurfaceControl();
- return sf != null ? sf : mSystemWindows.getViewSurface(mPipMenuView);
+ return mSystemWindows.getViewSurface(mPipMenuView);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
index 6d12752d9218..3eeba6eb5366 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
@@ -31,7 +31,6 @@ public class PipMenuIconsAlgorithm {
private static final String TAG = "PipMenuIconsAlgorithm";
- private boolean mFinishedLayout = false;
protected ViewGroup mViewRoot;
protected ViewGroup mTopEndContainer;
protected View mDragHandle;
@@ -51,27 +50,16 @@ public class PipMenuIconsAlgorithm {
mDragHandle = dragHandle;
mSettingsButton = settingsButton;
mDismissButton = dismissButton;
+
+ bindInitialViewState();
}
/**
* Updates the position of the drag handle based on where the PIP window is on the screen.
*/
public void onBoundsChanged(Rect bounds) {
- if (mViewRoot == null || mTopEndContainer == null || mDragHandle == null
- || mSettingsButton == null || mDismissButton == null) {
- Log.e(TAG, "One if the required views is null.");
- return;
- }
-
- //We only need to calculate the layout once since it does not change.
- if (!mFinishedLayout) {
- mTopEndContainer.removeView(mSettingsButton);
- mViewRoot.addView(mSettingsButton);
-
- setLayoutGravity(mDragHandle, Gravity.START | Gravity.TOP);
- setLayoutGravity(mSettingsButton, Gravity.START | Gravity.TOP);
- mFinishedLayout = true;
- }
+ // On phones, the menu icons are always static and will never move based on the PIP window
+ // position. No need to do anything here.
}
/**
@@ -84,4 +72,22 @@ public class PipMenuIconsAlgorithm {
v.setLayoutParams(params);
}
}
+
+ /** Calculate the initial state of the menu icons. Called when the menu is first created. */
+ private void bindInitialViewState() {
+ if (mViewRoot == null || mTopEndContainer == null || mDragHandle == null
+ || mSettingsButton == null || mDismissButton == null) {
+ Log.e(TAG, "One of the required views is null.");
+ return;
+ }
+ // The menu view layout starts out with the settings button aligned at the top|end of the
+ // view group next to the dismiss button. On phones, the settings button should be aligned
+ // to the top|start of the view, so move it to parent view group to then align it to the
+ // top|start of the menu.
+ mTopEndContainer.removeView(mSettingsButton);
+ mViewRoot.addView(mSettingsButton);
+
+ setLayoutGravity(mDragHandle, Gravity.START | Gravity.TOP);
+ setLayoutGravity(mSettingsButton, Gravity.START | Gravity.TOP);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index b91ba34c4464..53571ff70c6f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -107,6 +107,7 @@ public class PipResizeGestureHandler {
private boolean mThresholdCrossed0;
private boolean mThresholdCrossed1;
private boolean mUsingPinchToZoom = false;
+ private float mAngle = 0;
int mFirstIndex = -1;
int mSecondIndex = -1;
@@ -420,18 +421,25 @@ public class PipResizeGestureHandler {
float down1X = mDownSecondaryPoint.x;
float down1Y = mDownSecondaryPoint.y;
- // Top right + Bottom left pinch to zoom.
- if ((down0X > focusX && down0Y < focusY && down1X < focusX && down1Y > focusY)
- || (down1X > focusX && down1Y < focusY
- && down0X < focusX && down0Y > focusY)) {
+ if (down0X > focusX && down0Y < focusY && down1X < focusX && down1Y > focusY) {
+ // Top right + Bottom left pinch to zoom.
mAngle = calculateRotationAngle(mLastResizeBounds.centerX(),
mLastResizeBounds.centerY(), x0, y0, x1, y1, true);
- } else if ((down0X < focusX && down0Y < focusY
- && down1X > focusX && down1Y > focusY)
- || (down1X < focusX && down1Y < focusY
- && down0X > focusX && down0Y > focusY)) {
+ } else if (down1X > focusX && down1Y < focusY
+ && down0X < focusX && down0Y > focusY) {
+ // Top right + Bottom left pinch to zoom.
+ mAngle = calculateRotationAngle(mLastResizeBounds.centerX(),
+ mLastResizeBounds.centerY(), x1, y1, x0, y0, true);
+ } else if (down0X < focusX && down0Y < focusY
+ && down1X > focusX && down1Y > focusY) {
+ // Top left + bottom right pinch to zoom.
mAngle = calculateRotationAngle(mLastResizeBounds.centerX(),
mLastResizeBounds.centerY(), x0, y0, x1, y1, false);
+ } else if (down1X < focusX && down1Y < focusY
+ && down0X > focusX && down0Y > focusY) {
+ // Top left + bottom right pinch to zoom.
+ mAngle = calculateRotationAngle(mLastResizeBounds.centerX(),
+ mLastResizeBounds.centerY(), x1, y1, x0, y0, false);
}
mLastResizeBounds.set(PipPinchResizingAlgorithm.pinchResize(x0, y0, x1, y1,
@@ -445,21 +453,26 @@ public class PipResizeGestureHandler {
}
}
- private float mAngle = 0;
-
- private float calculateRotationAngle(int focusX, int focusY, float x0, float y0,
- float x1, float y1, boolean positive) {
+ private float calculateRotationAngle(int pivotX, int pivotY, float topX, float topY,
+ float bottomX, float bottomY, boolean positive) {
// The base angle is the angle formed by taking the angle between the center horizontal
// and one of the corners.
- double baseAngle = Math.toDegrees(Math.atan2(Math.abs(mLastResizeBounds.top - focusY),
- Math.abs(mLastResizeBounds.right - focusX)));
+ double baseAngle = Math.toDegrees(Math.atan2(Math.abs(mLastResizeBounds.top - pivotY),
+ Math.abs(mLastResizeBounds.right - pivotX)));
+
double angle0 = mThresholdCrossed0
- ? Math.toDegrees(Math.atan2(Math.abs(y0 - focusY), Math.abs(x0 - focusX)))
- : baseAngle;
- double angle1 = mThresholdCrossed1
- ? Math.toDegrees(Math.atan2(Math.abs(y1 - focusY), Math.abs(x1 - focusX)))
- : baseAngle;
+ ? Math.toDegrees(Math.atan2(pivotY - topY, topX - pivotX)) : baseAngle;
+ double angle1 = mThresholdCrossed0
+ ? Math.toDegrees(Math.atan2(pivotY - bottomY, bottomX - pivotX)) : baseAngle;
+
+
+ if (positive) {
+ angle1 = angle1 < 0 ? 180 + angle1 : angle1 - 180;
+ } else {
+ angle0 = angle0 < 0 ? -angle0 - 180 : 180 - angle0;
+ angle1 = -angle1;
+ }
// Calculate the percentage difference of [0, 90] compare to the base angle.
double diff0 = (Math.max(0, Math.min(angle0, 90)) - baseAngle) / 90;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 2c6809259459..177646b22ea3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -33,6 +33,7 @@ import java.io.PrintWriter;
/**
* Interface to engage split-screen feature.
+ * TODO: Figure out which of these are actually needed outside of the Shell
*/
@ExternalThread
public interface SplitScreen extends DragAndDropPolicy.Starter {
@@ -102,18 +103,11 @@ public interface SplitScreen extends DragAndDropPolicy.Starter {
void setSideStagePosition(@StagePosition int sideStagePosition);
/** Hides the side-stage if it is currently visible. */
void setSideStageVisibility(boolean visible);
- default void enterSplitScreen(int taskId, boolean leftOrTop) {
- moveToSideStage(taskId,
- leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT);
- }
+
/** Removes the split-screen stages. */
void exitSplitScreen();
/** Gets the stage bounds. */
void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds);
- /** Dumps current status of split-screen. */
- void dump(@NonNull PrintWriter pw, String prefix);
- /** Called when the shell organizer has been registered. */
- void onOrganizerRegistered();
void registerSplitScreenListener(SplitScreenListener listener);
void unregisterSplitScreenListener(SplitScreenListener listener);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 18dd53b90ff4..bbad36dcc046 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -18,6 +18,13 @@ package com.android.wm.shell.splitscreen;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
+
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
@@ -35,7 +42,9 @@ import androidx.annotation.Nullable;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import java.io.PrintWriter;
@@ -44,25 +53,33 @@ import java.io.PrintWriter;
* {@link SplitScreen}.
* @see StageCoordinator
*/
-public class SplitScreenController implements SplitScreen {
+public class SplitScreenController implements DragAndDropPolicy.Starter {
private static final String TAG = SplitScreenController.class.getSimpleName();
private final ShellTaskOrganizer mTaskOrganizer;
private final SyncTransactionQueue mSyncQueue;
private final Context mContext;
private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
+ private final ShellExecutor mMainExecutor;
+ private final SplitScreenImpl mImpl = new SplitScreenImpl();
+
private StageCoordinator mStageCoordinator;
public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
- RootTaskDisplayAreaOrganizer rootTDAOrganizer) {
+ RootTaskDisplayAreaOrganizer rootTDAOrganizer,
+ ShellExecutor mainExecutor) {
mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue;
mContext = context;
mRootTDAOrganizer = rootTDAOrganizer;
+ mMainExecutor = mainExecutor;
+ }
+
+ public SplitScreen asSplitScreen() {
+ return mImpl;
}
- @Override
public void onOrganizerRegistered() {
if (mStageCoordinator == null) {
// TODO: Multi-display
@@ -71,13 +88,11 @@ public class SplitScreenController implements SplitScreen {
}
}
- @Override
public boolean isSplitScreenVisible() {
return mStageCoordinator.isSplitScreenVisible();
}
- @Override
- public boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition) {
+ public boolean moveToSideStage(int taskId, @SplitScreen.StagePosition int sideStagePosition) {
final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
if (task == null) {
throw new IllegalArgumentException("Unknown taskId" + taskId);
@@ -85,50 +100,46 @@ public class SplitScreenController implements SplitScreen {
return moveToSideStage(task, sideStagePosition);
}
- @Override
public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
- @StagePosition int sideStagePosition) {
+ @SplitScreen.StagePosition int sideStagePosition) {
return mStageCoordinator.moveToSideStage(task, sideStagePosition);
}
- @Override
public boolean removeFromSideStage(int taskId) {
return mStageCoordinator.removeFromSideStage(taskId);
}
- @Override
- public void setSideStagePosition(@StagePosition int sideStagePosition) {
+ public void setSideStagePosition(@SplitScreen.StagePosition int sideStagePosition) {
mStageCoordinator.setSideStagePosition(sideStagePosition);
}
- @Override
public void setSideStageVisibility(boolean visible) {
mStageCoordinator.setSideStageVisibility(visible);
}
- @Override
+ public void enterSplitScreen(int taskId, boolean leftOrTop) {
+ moveToSideStage(taskId,
+ leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT);
+ }
+
public void exitSplitScreen() {
mStageCoordinator.exitSplitScreen();
}
- @Override
public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
mStageCoordinator.getStageBounds(outTopOrLeftBounds, outBottomOrRightBounds);
}
- @Override
- public void registerSplitScreenListener(SplitScreenListener listener) {
+ public void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) {
mStageCoordinator.registerSplitScreenListener(listener);
}
- @Override
- public void unregisterSplitScreenListener(SplitScreenListener listener) {
+ public void unregisterSplitScreenListener(SplitScreen.SplitScreenListener listener) {
mStageCoordinator.unregisterSplitScreenListener(listener);
}
- @Override
- public void startTask(int taskId,
- @StageType int stage, @StagePosition int position, @Nullable Bundle options) {
+ public void startTask(int taskId, @SplitScreen.StageType int stage,
+ @SplitScreen.StagePosition int position, @Nullable Bundle options) {
options = resolveStartStage(stage, position, options);
try {
@@ -138,9 +149,9 @@ public class SplitScreenController implements SplitScreen {
}
}
- @Override
- public void startShortcut(String packageName, String shortcutId, @StageType int stage,
- @StagePosition int position, @Nullable Bundle options, UserHandle user) {
+ public void startShortcut(String packageName, String shortcutId,
+ @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
+ @Nullable Bundle options, UserHandle user) {
options = resolveStartStage(stage, position, options);
try {
@@ -153,9 +164,8 @@ public class SplitScreenController implements SplitScreen {
}
}
- @Override
- public void startIntent(PendingIntent intent,
- @StageType int stage, @StagePosition int position, @Nullable Bundle options) {
+ public void startIntent(PendingIntent intent, @SplitScreen.StageType int stage,
+ @SplitScreen.StagePosition int position, @Nullable Bundle options) {
options = resolveStartStage(stage, position, options);
try {
@@ -165,8 +175,8 @@ public class SplitScreenController implements SplitScreen {
}
}
- private Bundle resolveStartStage(@StageType int stage, @StagePosition int position,
- @Nullable Bundle options) {
+ private Bundle resolveStartStage(@SplitScreen.StageType int stage,
+ @SplitScreen.StagePosition int position, @Nullable Bundle options) {
switch (stage) {
case STAGE_TYPE_UNDEFINED: {
// Use the stage of the specified position is valid.
@@ -216,7 +226,6 @@ public class SplitScreenController implements SplitScreen {
return options;
}
- @Override
public void dump(@NonNull PrintWriter pw, String prefix) {
pw.println(prefix + TAG);
if (mStageCoordinator != null) {
@@ -224,4 +233,113 @@ public class SplitScreenController implements SplitScreen {
}
}
+ private class SplitScreenImpl implements SplitScreen {
+ @Override
+ public boolean isSplitScreenVisible() {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return SplitScreenController.this.isSplitScreenVisible();
+ }, Boolean.class);
+ }
+
+ @Override
+ public boolean moveToSideStage(int taskId, int sideStagePosition) {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return SplitScreenController.this.moveToSideStage(taskId, sideStagePosition);
+ }, Boolean.class);
+ }
+
+ @Override
+ public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
+ int sideStagePosition) {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return SplitScreenController.this.moveToSideStage(task, sideStagePosition);
+ }, Boolean.class);
+ }
+
+ @Override
+ public boolean removeFromSideStage(int taskId) {
+ return mMainExecutor.executeBlockingForResult(() -> {
+ return SplitScreenController.this.removeFromSideStage(taskId);
+ }, Boolean.class);
+ }
+
+ @Override
+ public void setSideStagePosition(int sideStagePosition) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.setSideStagePosition(sideStagePosition);
+ });
+ }
+
+ @Override
+ public void setSideStageVisibility(boolean visible) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.setSideStageVisibility(visible);
+ });
+ }
+
+ @Override
+ public void enterSplitScreen(int taskId, boolean leftOrTop) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.enterSplitScreen(taskId, leftOrTop);
+ });
+ }
+
+ @Override
+ public void exitSplitScreen() {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.exitSplitScreen();
+ });
+ }
+
+ @Override
+ public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
+ try {
+ mMainExecutor.executeBlocking(() -> {
+ SplitScreenController.this.getStageBounds(outTopOrLeftBounds,
+ outBottomOrRightBounds);
+ });
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Failed to get stage bounds in 2s");
+ }
+ }
+
+ @Override
+ public void registerSplitScreenListener(SplitScreenListener listener) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.registerSplitScreenListener(listener);
+ });
+ }
+
+ @Override
+ public void unregisterSplitScreenListener(SplitScreenListener listener) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.unregisterSplitScreenListener(listener);
+ });
+ }
+
+ @Override
+ public void startTask(int taskId, int stage, int position, @Nullable Bundle options) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.startTask(taskId, stage, position, options);
+ });
+ }
+
+ @Override
+ public void startShortcut(String packageName, String shortcutId, int stage, int position,
+ @Nullable Bundle options, UserHandle user) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.startShortcut(packageName, shortcutId, stage, position,
+ options, user);
+ });
+ }
+
+ @Override
+ public void startIntent(PendingIntent intent, int stage, int position,
+ @Nullable Bundle options) {
+ mMainExecutor.execute(() -> {
+ SplitScreenController.this.startIntent(intent, stage, position, options);
+ });
+ }
+ }
+
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 8e24e0b516cb..f3749220d4e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -377,12 +377,10 @@ public class StartingSurfaceDrawer {
final int taskId = startingWindowInfo.taskInfo.taskId;
final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */);
- mMainExecutor.execute(() -> {
- mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
- final StartingWindowRecord tView =
- new StartingWindowRecord(null/* decorView */, surface);
- mStartingWindowRecords.put(taskId, tView);
- });
+ mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+ final StartingWindowRecord tView =
+ new StartingWindowRecord(null/* decorView */, surface);
+ mStartingWindowRecords.put(taskId, tView);
}
/**
@@ -392,42 +390,40 @@ public class StartingSurfaceDrawer {
if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId);
}
- mMainExecutor.execute(() -> removeWindowSynced(taskId));
+ removeWindowSynced(taskId);
}
protected void postAddWindow(int taskId, IBinder appToken,
- View view, WindowManager wm, WindowManager.LayoutParams params) {
- mMainExecutor.execute(() -> {
- boolean shouldSaveView = true;
- try {
- wm.addView(view, params);
- } catch (WindowManager.BadTokenException e) {
- // ignore
- Slog.w(TAG, appToken + " already running, starting window not displayed. "
- + e.getMessage());
- shouldSaveView = false;
- } catch (RuntimeException e) {
- // don't crash if something else bad happens, for example a
- // failure loading resources because we are loading from an app
- // on external storage that has been unmounted.
- Slog.w(TAG, appToken + " failed creating starting window", e);
+ View view, WindowManager wm, WindowManager.LayoutParams params) {
+ boolean shouldSaveView = true;
+ try {
+ wm.addView(view, params);
+ } catch (WindowManager.BadTokenException e) {
+ // ignore
+ Slog.w(TAG, appToken + " already running, starting window not displayed. "
+ + e.getMessage());
+ shouldSaveView = false;
+ } catch (RuntimeException e) {
+ // don't crash if something else bad happens, for example a
+ // failure loading resources because we are loading from an app
+ // on external storage that has been unmounted.
+ Slog.w(TAG, appToken + " failed creating starting window", e);
+ shouldSaveView = false;
+ } finally {
+ if (view != null && view.getParent() == null) {
+ Slog.w(TAG, "view not successfully added to wm, removing view");
+ wm.removeViewImmediate(view);
shouldSaveView = false;
- } finally {
- if (view != null && view.getParent() == null) {
- Slog.w(TAG, "view not successfully added to wm, removing view");
- wm.removeViewImmediate(view);
- shouldSaveView = false;
- }
}
+ }
- if (shouldSaveView) {
- removeWindowSynced(taskId);
- mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
- final StartingWindowRecord tView =
- new StartingWindowRecord(view, null /* TaskSnapshotWindow */);
- mStartingWindowRecords.put(taskId, tView);
- }
- });
+ if (shouldSaveView) {
+ removeWindowSynced(taskId);
+ mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+ final StartingWindowRecord tView =
+ new StartingWindowRecord(view, null /* TaskSnapshotWindow */);
+ mStartingWindowRecords.put(taskId, tView);
+ }
}
protected void removeWindowSynced(int taskId) {
@@ -445,7 +441,7 @@ public class StartingSurfaceDrawer {
if (DEBUG_TASK_SNAPSHOT) {
Slog.v(TAG, "Removing task snapshot window for " + taskId);
}
- record.mTaskSnapshotWindow.remove(mMainExecutor);
+ record.mTaskSnapshotWindow.remove();
}
mStartingWindowRecords.remove(taskId);
}
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 b5e18960ff5c..a6f44efd7645 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
@@ -82,6 +82,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.DecorView;
import com.android.internal.view.BaseIWindow;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.annotations.ExternalThread;
/**
* This class represents a starting window that shows a snapshot.
@@ -121,6 +122,7 @@ public class TaskSnapshotWindow {
private final Window mWindow;
private final Surface mSurface;
private final Runnable mClearWindowHandler;
+ private final ShellExecutor mMainExecutor;
private SurfaceControl mSurfaceControl;
private SurfaceControl mChildSurfaceControl;
private final IWindowSession mSession;
@@ -213,7 +215,7 @@ public class TaskSnapshotWindow {
final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
windowFlags, windowPrivateFlags, taskBounds, orientation, activityType,
- topWindowInsetsState, clearWindowHandler);
+ topWindowInsetsState, clearWindowHandler, mainExecutor);
final Window window = snapshotSurface.mWindow;
final InsetsState mTmpInsetsState = new InsetsState();
@@ -229,7 +231,7 @@ public class TaskSnapshotWindow {
} catch (RemoteException e) {
snapshotSurface.clearWindowSynced();
}
- window.setOuter(snapshotSurface, mainExecutor);
+ window.setOuter(snapshotSurface);
try {
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
@@ -249,7 +251,8 @@ public class TaskSnapshotWindow {
TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
int currentOrientation, int activityType, InsetsState topWindowInsetsState,
- Runnable clearWindowHandler) {
+ Runnable clearWindowHandler, ShellExecutor mainExecutor) {
+ mMainExecutor = mainExecutor;
mSurface = new Surface();
mSession = WindowManagerGlobal.getWindowSession();
mWindow = new Window();
@@ -286,28 +289,26 @@ public class TaskSnapshotWindow {
mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
}
- void remove(ShellExecutor mainExecutor) {
+ void remove() {
final long now = SystemClock.uptimeMillis();
if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
// Show the latest content as soon as possible for unlocking to home.
&& mActivityType != ACTIVITY_TYPE_HOME) {
final long delayTime = mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS - now;
- mainExecutor.executeDelayed(() -> remove(mainExecutor), delayTime);
+ mMainExecutor.executeDelayed(() -> remove(), delayTime);
if (DEBUG) {
Slog.d(TAG, "Defer removing snapshot surface in " + delayTime);
}
return;
}
- mainExecutor.execute(() -> {
- try {
- if (DEBUG) {
- Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
- }
- mSession.remove(mWindow);
- } catch (RemoteException e) {
- // nothing
+ try {
+ if (DEBUG) {
+ Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
}
- });
+ mSession.remove(mWindow);
+ } catch (RemoteException e) {
+ // nothing
+ }
}
/**
@@ -497,13 +498,12 @@ public class TaskSnapshotWindow {
}
}
+ @ExternalThread
static class Window extends BaseIWindow {
private TaskSnapshotWindow mOuter;
- private ShellExecutor mMainExecutor;
- public void setOuter(TaskSnapshotWindow outer, ShellExecutor mainExecutor) {
+ public void setOuter(TaskSnapshotWindow outer) {
mOuter = outer;
- mMainExecutor = mainExecutor;
}
@Override
@@ -511,22 +511,20 @@ public class TaskSnapshotWindow {
MergedConfiguration mergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId) {
if (mOuter != null) {
- if (mergedConfiguration != null
- && mOuter.mOrientationOnCreation
- != mergedConfiguration.getMergedConfiguration().orientation) {
- // The orientation of the screen is changing. We better remove the snapshot ASAP
- // as we are going to wait on the new window in any case to unfreeze the screen,
- // and the starting window is not needed anymore.
- mMainExecutor.execute(() -> {
+ mOuter.mMainExecutor.execute(() -> {
+ if (mergedConfiguration != null
+ && mOuter.mOrientationOnCreation
+ != mergedConfiguration.getMergedConfiguration().orientation) {
+ // The orientation of the screen is changing. We better remove the snapshot
+ // ASAP as we are going to wait on the new window in any case to unfreeze
+ // the screen, and the starting window is not needed anymore.
mOuter.clearWindowSynced();
- });
- } else if (reportDraw) {
- mMainExecutor.execute(() -> {
+ } else if (reportDraw) {
if (mOuter.mHasDrawn) {
mOuter.reportDrawn();
}
- });
- }
+ }
+ });
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
new file mode 100644
index 000000000000..85bbf74d56b9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitions.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.transition;
+
+import android.annotation.NonNull;
+import android.window.IRemoteTransition;
+import android.window.TransitionFilter;
+
+import com.android.wm.shell.common.annotations.ExternalThread;
+
+/**
+ * Interface to manage remote transitions.
+ */
+@ExternalThread
+public interface RemoteTransitions {
+ /**
+ * Registers a remote transition.
+ */
+ void registerRemote(@NonNull TransitionFilter filter,
+ @NonNull IRemoteTransition remoteTransition);
+
+ /**
+ * Unregisters a remote transition.
+ */
+ void unregisterRemote(@NonNull IRemoteTransition remoteTransition);
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index d8687bd899de..10344892e766 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -67,6 +67,7 @@ public class Transitions {
private final ShellExecutor mAnimExecutor;
private final TransitionPlayerImpl mPlayerImpl;
private final RemoteTransitionHandler mRemoteTransitionHandler;
+ private final RemoteTransitionImpl mImpl = new RemoteTransitionImpl();
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
@@ -78,6 +79,10 @@ public class Transitions {
/** Keeps track of currently tracked transitions and all the animations associated with each */
private final ArrayMap<IBinder, ActiveTransition> mActiveTransitions = new ArrayMap<>();
+ public static RemoteTransitions asRemoteTransitions(Transitions transitions) {
+ return transitions.mImpl;
+ }
+
public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
@NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
mOrganizer = organizer;
@@ -101,8 +106,20 @@ public class Transitions {
/** Create an empty/non-registering transitions object for system-ui tests. */
@VisibleForTesting
- public static Transitions createEmptyForTesting() {
- return new Transitions();
+ public static RemoteTransitions createEmptyForTesting() {
+ return new RemoteTransitions() {
+ @Override
+ public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter,
+ @androidx.annotation.NonNull IRemoteTransition remoteTransition) {
+ // Do nothing
+ }
+
+ @Override
+ public void unregisterRemote(
+ @androidx.annotation.NonNull IRemoteTransition remoteTransition) {
+ // Do nothing
+ }
+ };
}
/** Register this transition handler with Core */
@@ -134,16 +151,14 @@ public class Transitions {
}
/** Register a remote transition to be used when `filter` matches an incoming transition */
- @ExternalThread
public void registerRemote(@NonNull TransitionFilter filter,
@NonNull IRemoteTransition remoteTransition) {
- mMainExecutor.execute(() -> mRemoteTransitionHandler.addFiltered(filter, remoteTransition));
+ mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
}
/** Unregisters a remote transition and all associated filters */
- @ExternalThread
public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
- mMainExecutor.execute(() -> mRemoteTransitionHandler.removeFiltered(remoteTransition));
+ mRemoteTransitionHandler.removeFiltered(remoteTransition);
}
/** @return true if the transition was triggered by opening something vs closing something */
@@ -371,4 +386,22 @@ public class Transitions {
mMainExecutor.execute(() -> Transitions.this.requestStartTransition(iBinder, request));
}
}
+
+ @ExternalThread
+ private class RemoteTransitionImpl implements RemoteTransitions {
+ @Override
+ public void registerRemote(@NonNull TransitionFilter filter,
+ @NonNull IRemoteTransition remoteTransition) {
+ mMainExecutor.execute(() -> {
+ Transitions.this.registerRemote(filter, remoteTransition);
+ });
+ }
+
+ @Override
+ public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
+ mMainExecutor.execute(() -> {
+ Transitions.this.unregisterRemote(remoteTransition);
+ });
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index 8258630a9502..f06d57c6c789 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -25,8 +25,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.wm.shell.flicker"/>
- <option name="include-annotation" value="androidx.test.filters.RequiresDevice" />
- <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6000s" />
<option name="hidden-api-checks" value="false" />
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index 7ad75532eced..3282ece999ac 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.flicker
import android.graphics.Region
import android.view.Surface
+import com.android.server.wm.flicker.dsl.LayersAssertionBuilder
import com.android.server.wm.flicker.dsl.LayersAssertionBuilderLegacy
import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
@@ -25,6 +26,109 @@ import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.traces.layers.getVisibleBounds
@JvmOverloads
+fun LayersAssertionBuilder.appPairsDividerIsVisible(bugId: Int = 0) {
+ end("appPairsDividerIsVisible", bugId) {
+ this.isVisible(APP_PAIR_SPLIT_DIVIDER)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.appPairsDividerIsInvisible(bugId: Int = 0) {
+ end("appPairsDividerIsInVisible", bugId) {
+ this.notExists(APP_PAIR_SPLIT_DIVIDER)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.appPairsDividerBecomesVisible(bugId: Int = 0) {
+ all("dividerLayerBecomesVisible", bugId) {
+ this.hidesLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .showsLayer(DOCKED_STACK_DIVIDER)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.dockedStackDividerIsVisible(bugId: Int = 0) {
+ end("dockedStackDividerIsVisible", bugId) {
+ this.isVisible(DOCKED_STACK_DIVIDER)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.dockedStackDividerBecomesVisible(bugId: Int = 0) {
+ all("dividerLayerBecomesVisible", bugId) {
+ this.hidesLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .showsLayer(DOCKED_STACK_DIVIDER)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.dockedStackDividerBecomesInvisible(bugId: Int = 0) {
+ all("dividerLayerBecomesInvisible", bugId) {
+ this.showsLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .hidesLayer(DOCKED_STACK_DIVIDER)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.dockedStackDividerIsInvisible(bugId: Int = 0) {
+ end("dockedStackDividerIsInvisible", bugId) {
+ this.notExists(DOCKED_STACK_DIVIDER)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.appPairsPrimaryBoundsIsVisible(
+ rotation: Int,
+ primaryLayerName: String,
+ bugId: Int = 0
+) {
+ end("PrimaryAppBounds", bugId) {
+ val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
+ this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.appPairsSecondaryBoundsIsVisible(
+ rotation: Int,
+ secondaryLayerName: String,
+ bugId: Int = 0
+) {
+ end("SecondaryAppBounds", bugId) {
+ val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
+ this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.dockedStackPrimaryBoundsIsVisible(
+ rotation: Int,
+ primaryLayerName: String,
+ bugId: Int = 0
+) {
+ end("PrimaryAppBounds", bugId) {
+ val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
+ this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.dockedStackSecondaryBoundsIsVisible(
+ rotation: Int,
+ secondaryLayerName: String,
+ bugId: Int = 0
+) {
+ end("SecondaryAppBounds", bugId) {
+ val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
+ this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
+ }
+}
+
+@JvmOverloads
fun LayersAssertionBuilderLegacy.appPairsDividerIsVisible(
bugId: Int = 0,
enabled: Boolean = bugId == 0
@@ -51,8 +155,8 @@ fun LayersAssertionBuilderLegacy.appPairsDividerBecomesVisible(
) {
all("dividerLayerBecomesVisible", bugId, enabled) {
this.hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .showsLayer(DOCKED_STACK_DIVIDER)
}
}
@@ -73,8 +177,8 @@ fun LayersAssertionBuilderLegacy.dockedStackDividerBecomesVisible(
) {
all("dividerLayerBecomesVisible", bugId, enabled) {
this.hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .showsLayer(DOCKED_STACK_DIVIDER)
}
}
@@ -85,8 +189,8 @@ fun LayersAssertionBuilderLegacy.dockedStackDividerBecomesInvisible(
) {
all("dividerLayerBecomesInvisible", bugId, enabled) {
this.showsLayer(DOCKED_STACK_DIVIDER)
- .then()
- .hidesLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .hidesLayer(DOCKED_STACK_DIVIDER)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index d25774935e86..c3fd66395366 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.apppairs
import android.os.Bundle
-import android.platform.test.annotations.Presubmit
import android.os.SystemClock
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -40,7 +39,6 @@ import org.junit.runners.Parameterized
* Test cold launch app from launcher.
* To run this test: `atest WMShellFlickerTests:AppPairsTestCannotPairNonResizeableApps`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -51,10 +49,9 @@ class AppPairsTestCannotPairNonResizeableApps(
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): List<Array<Any>> {
- val testTag = "testAppPairs_cannotPairNonResizeableApps"
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
withTestName {
- buildTestTag(testTag, configuration)
+ buildTestTag(configuration)
}
transitions {
nonResizeableApp?.launchViaIntent(wmHelper)
@@ -64,17 +61,20 @@ class AppPairsTestCannotPairNonResizeableApps(
SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
}
assertions {
- layersTrace {
- appPairsDividerIsInvisible()
- }
- windowManagerTrace {
- end("onlyResizeableAppWindowVisible") {
+ presubmit {
+ layersTrace {
+ appPairsDividerIsInvisible()
+ }
+ windowManagerTrace {
val nonResizeableApp = nonResizeableApp
require(nonResizeableApp != null) {
"Non resizeable app not initialized"
}
- isVisible(nonResizeableApp.defaultWindowName)
- isInvisible(primaryApp.defaultWindowName)
+
+ end("onlyResizeableAppWindowVisible") {
+ isVisible(nonResizeableApp.defaultWindowName)
+ isInvisible(primaryApp.defaultWindowName)
+ }
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index 257350b6950b..7a2a5e482d98 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -18,7 +18,6 @@ package com.android.wm.shell.flicker.apppairs
import android.os.Bundle
import android.os.SystemClock
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
@@ -38,7 +37,6 @@ import org.junit.runners.Parameterized
* Test cold launch app from launcher.
* To run this test: `atest WMShellFlickerTests:AppPairsTestPairPrimaryAndSecondaryApps`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -49,10 +47,9 @@ class AppPairsTestPairPrimaryAndSecondaryApps(
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): List<Array<Any>> {
- val testTag = "testAppPairs_pairPrimaryAndSecondaryApps"
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
withTestName {
- buildTestTag(testTag, configuration)
+ buildTestTag(configuration)
}
transitions {
// TODO pair apps through normal UX flow
@@ -61,20 +58,27 @@ class AppPairsTestPairPrimaryAndSecondaryApps(
SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
}
assertions {
- layersTrace {
- appPairsDividerIsVisible()
- end("appsEndingBounds", enabled = false) {
- val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
- this.hasVisibleRegion(primaryApp.defaultWindowName,
- appPairsHelper.getPrimaryBounds(dividerRegion))
- .hasVisibleRegion(secondaryApp.defaultWindowName,
- appPairsHelper.getSecondaryBounds(dividerRegion))
+ presubmit {
+ layersTrace {
+ appPairsDividerIsVisible()
+ }
+ windowManagerTrace {
+ end("bothAppWindowsVisible") {
+ isVisible(primaryApp.defaultWindowName)
+ isVisible(secondaryApp.defaultWindowName)
+ }
}
}
- windowManagerTrace {
- end("bothAppWindowsVisible") {
- isVisible(primaryApp.defaultWindowName)
- isVisible(secondaryApp.defaultWindowName)
+
+ flaky {
+ layersTrace {
+ end("appsEndingBounds") {
+ val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
+ this.hasVisibleRegion(primaryApp.defaultWindowName,
+ appPairsHelper.getPrimaryBounds(dividerRegion))
+ .hasVisibleRegion(secondaryApp.defaultWindowName,
+ appPairsHelper.getSecondaryBounds(dividerRegion))
+ }
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index 0b001f5ac1b6..d8dc4c2b56f6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -18,7 +18,6 @@ package com.android.wm.shell.flicker.apppairs
import android.os.Bundle
import android.os.SystemClock
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
@@ -38,7 +37,6 @@ import org.junit.runners.Parameterized
* Test cold launch app from launcher.
* To run this test: `atest WMShellFlickerTests:AppPairsTestUnpairPrimaryAndSecondaryApps`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -49,10 +47,9 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): List<Array<Any>> {
- val testTag = "testAppPairs_unpairPrimaryAndSecondaryApps"
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
withTestName {
- buildTestTag(testTag, configuration)
+ buildTestTag(configuration)
}
setup {
executeShellCommand(
@@ -66,24 +63,31 @@ class AppPairsTestUnpairPrimaryAndSecondaryApps(
SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
}
assertions {
- layersTrace {
- appPairsDividerIsInvisible()
- start("appsStartingBounds", enabled = false) {
- val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
- this.hasVisibleRegion(primaryApp.defaultWindowName,
- appPairsHelper.getPrimaryBounds(dividerRegion))
- .hasVisibleRegion(secondaryApp.defaultWindowName,
- appPairsHelper.getSecondaryBounds(dividerRegion))
+ presubmit {
+ layersTrace {
+ appPairsDividerIsInvisible()
}
- end("appsEndingBounds", enabled = false) {
- this.notExists(primaryApp.defaultWindowName)
- .notExists(secondaryApp.defaultWindowName)
+ windowManagerTrace {
+ end("bothAppWindowsInvisible") {
+ isInvisible(primaryApp.defaultWindowName)
+ isInvisible(secondaryApp.defaultWindowName)
+ }
}
}
- windowManagerTrace {
- end("bothAppWindowsInvisible") {
- isInvisible(primaryApp.defaultWindowName)
- isInvisible(secondaryApp.defaultWindowName)
+
+ flaky {
+ layersTrace {
+ start("appsStartingBounds") {
+ val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
+ this.hasVisibleRegion(primaryApp.defaultWindowName,
+ appPairsHelper.getPrimaryBounds(dividerRegion))
+ .hasVisibleRegion(secondaryApp.defaultWindowName,
+ appPairsHelper.getSecondaryBounds(dividerRegion))
+ }
+ end("appsEndingBounds") {
+ this.notExists(primaryApp.defaultWindowName)
+ .notExists(secondaryApp.defaultWindowName)
+ }
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index aafa9bfbd676..8aee005b7513 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -18,7 +18,6 @@ package com.android.wm.shell.flicker.apppairs
import android.os.Bundle
import android.os.SystemClock
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -46,7 +45,6 @@ import org.junit.runners.Parameterized
* Test open apps to app pairs and rotate.
* To run this test: `atest WMShellFlickerTests:RotateTwoLaunchedAppsInAppPairsMode`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -60,7 +58,7 @@ class RotateTwoLaunchedAppsInAppPairsMode(
fun getParams(): Collection<Array<Any>> {
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
withTestName {
- buildTestTag("testRotateTwoLaunchedAppsInAppPairsMode", configuration)
+ buildTestTag(configuration)
}
transitions {
executeShellCommand(composePairsCommand(
@@ -69,23 +67,28 @@ class RotateTwoLaunchedAppsInAppPairsMode(
setRotation(configuration.endRotation)
}
assertions {
- layersTrace {
- navBarLayerRotatesAndScales(Surface.ROTATION_0, configuration.endRotation,
- enabled = false)
- statusBarLayerRotatesScales(Surface.ROTATION_0, configuration.endRotation,
- enabled = false)
- appPairsDividerIsVisible(enabled = false)
- appPairsPrimaryBoundsIsVisible(configuration.endRotation,
- primaryApp.defaultWindowName, bugId = 172776659)
- appPairsSecondaryBoundsIsVisible(configuration.endRotation,
- secondaryApp.defaultWindowName, bugId = 172776659)
+ presubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ end("bothAppWindowsVisible") {
+ isVisible(primaryApp.defaultWindowName)
+ .isVisible(secondaryApp.defaultWindowName)
+ }
+ }
}
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- end("bothAppWindowsVisible") {
- isVisible(primaryApp.defaultWindowName)
- .isVisible(secondaryApp.defaultWindowName)
+
+ flaky {
+ layersTrace {
+ appPairsDividerIsVisible()
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ appPairsPrimaryBoundsIsVisible(configuration.endRotation,
+ primaryApp.defaultWindowName, bugId = 172776659)
+ appPairsSecondaryBoundsIsVisible(configuration.endRotation,
+ secondaryApp.defaultWindowName, bugId = 172776659)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index 19ca31fbee4a..bc99c9430f13 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -62,7 +62,7 @@ class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
fun getParams(): Collection<Array<Any>> {
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
withTestName {
- buildTestTag("testRotateAndEnterAppPairsMode", configuration)
+ buildTestTag(configuration)
}
transitions {
this.setRotation(configuration.endRotation)
@@ -71,22 +71,37 @@ class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
}
assertions {
- layersTrace {
- navBarLayerRotatesAndScales(Surface.ROTATION_0, configuration.endRotation,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerRotatesScales(Surface.ROTATION_0, configuration.endRotation)
- appPairsDividerIsVisible()
- appPairsPrimaryBoundsIsVisible(configuration.endRotation,
- primaryApp.defaultWindowName, 172776659)
- appPairsSecondaryBoundsIsVisible(configuration.endRotation,
- secondaryApp.defaultWindowName, 172776659)
+ val isRotated = configuration.startRotation.isRotated()
+ presubmit {
+ layersTrace {
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ appPairsDividerIsVisible()
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ }
+ }
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ end("bothAppWindowsVisible") {
+ isVisible(primaryApp.defaultWindowName)
+ isVisible(secondaryApp.defaultWindowName)
+ }
+ }
}
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- end("bothAppWindowsVisible") {
- isVisible(primaryApp.defaultWindowName)
- isVisible(secondaryApp.defaultWindowName)
+ flaky {
+ layersTrace {
+ appPairsPrimaryBoundsIsVisible(configuration.endRotation,
+ primaryApp.defaultWindowName, 172776659)
+ appPairsSecondaryBoundsIsVisible(configuration.endRotation,
+ secondaryApp.defaultWindowName, 172776659)
+
+ if (isRotated) {
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ }
}
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 25721066b713..19ecc49513e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -44,6 +44,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
@@ -65,7 +66,7 @@ import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
-import com.android.wm.shell.splitscreen.SplitScreen;
+import com.android.wm.shell.splitscreen.SplitScreenController;
import org.junit.Before;
import org.junit.Test;
@@ -92,7 +93,7 @@ public class DragAndDropPolicyTest {
// Both the split-screen and start interface.
@Mock
- private SplitScreen mSplitScreenStarter;
+ private SplitScreenController mSplitScreenStarter;
private DisplayLayout mLandscapeDisplayLayout;
private DisplayLayout mPortraitDisplayLayout;
@@ -127,8 +128,8 @@ public class DragAndDropPolicyTest {
mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
mInsets = Insets.of(0, 0, 0, 0);
- mPolicy = new DragAndDropPolicy(
- mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter);
+ mPolicy = spy(new DragAndDropPolicy(
+ mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter));
mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
setClipDataResizeable(mNonResizeableActivityClipData, false);
@@ -204,8 +205,8 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@Test
@@ -216,13 +217,13 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
@@ -233,13 +234,13 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
@@ -250,8 +251,8 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@Test
@@ -262,8 +263,8 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@Test
@@ -275,14 +276,14 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
@@ -294,14 +295,14 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
- verify(mSplitScreenStarter).startClipDescription(any(), any(),
- eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT));
+ verify(mSplitScreenStarter).startIntent(any(),
+ eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 0087d917f007..3147dab1a0f8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -16,6 +16,9 @@
package com.android.wm.shell.pip;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_90;
+
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
@@ -34,6 +37,7 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayLayout;
import org.junit.Before;
import org.junit.Test;
@@ -84,7 +88,7 @@ public class PipAnimationControllerTest extends ShellTestCase {
public void getAnimator_withBounds_returnBoundsAnimator() {
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, new Rect(), new Rect(), new Rect(), null,
- TRANSITION_DIRECTION_TO_PIP, 0);
+ TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0);
assertEquals("Expect ANIM_TYPE_BOUNDS animation",
animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS);
@@ -98,13 +102,13 @@ public class PipAnimationControllerTest extends ShellTestCase {
final Rect endValue2 = new Rect(200, 200, 300, 300);
final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue1, null,
- TRANSITION_DIRECTION_TO_PIP, 0);
+ TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0);
oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
oldAnimator.start();
final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue2, null,
- TRANSITION_DIRECTION_TO_PIP, 0);
+ TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0);
assertEquals("getAnimator with same type returns same animator",
oldAnimator, newAnimator);
@@ -128,6 +132,21 @@ public class PipAnimationControllerTest extends ShellTestCase {
}
@Test
+ public void pipTransitionAnimator_rotatedEndValue() {
+ final Rect startBounds = new Rect(200, 700, 400, 800);
+ final Rect endBounds = new Rect(0, 0, 500, 1000);
+ final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController
+ .getAnimator(mTaskInfo, mLeash, null, startBounds, endBounds, null,
+ TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_90);
+ // Apply fraction 1 to compute the end value.
+ animator.applySurfaceControlTransaction(mLeash, new DummySurfaceControlTx(), 1);
+ final Rect rotatedEndBounds = new Rect(endBounds);
+ DisplayLayout.rotateBounds(rotatedEndBounds, endBounds, ROTATION_90);
+
+ assertEquals("Expect 90 degree rotated bounds", rotatedEndBounds, animator.mCurrentValue);
+ }
+
+ @Test
@SuppressWarnings("unchecked")
public void pipTransitionAnimator_updateEndValue() {
final Rect baseValue = new Rect(0, 0, 100, 100);
@@ -136,7 +155,7 @@ public class PipAnimationControllerTest extends ShellTestCase {
final Rect endValue2 = new Rect(200, 200, 300, 300);
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue1, null,
- TRANSITION_DIRECTION_TO_PIP, 0);
+ TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0);
animator.updateEndValue(endValue2);
@@ -150,7 +169,7 @@ public class PipAnimationControllerTest extends ShellTestCase {
final Rect endValue = new Rect(100, 100, 200, 200);
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue, null,
- TRANSITION_DIRECTION_TO_PIP, 0);
+ TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0);
animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
animator.setPipAnimationCallback(mPipAnimationCallback);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
index 414a0a778d93..27e5f51d88b8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
@@ -47,6 +47,7 @@ import android.window.TaskSnapshot;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
import org.junit.Test;
@@ -83,7 +84,7 @@ public class TaskSnapshotWindowTest {
createTaskDescription(Color.WHITE, Color.RED, Color.BLUE),
0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */,
taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState(),
- null /* clearWindow */);
+ null /* clearWindow */, new TestShellExecutor());
}
private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index ce1d96c167d7..f48122858267 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -335,7 +335,6 @@ cc_defaults {
"jni/YuvToJpegEncoder.cpp",
"jni/fonts/Font.cpp",
"jni/fonts/FontFamily.cpp",
- "jni/fonts/NativeFont.cpp",
"jni/text/LineBreaker.cpp",
"jni/text/MeasuredText.cpp",
"jni/text/TextShaper.cpp",
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index 0fad2d58cc8a..e1f5abd786bf 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -69,7 +69,6 @@ extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env
extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
extern int register_android_graphics_fonts_Font(JNIEnv* env);
extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
-extern int register_android_graphics_fonts_NativeFont(JNIEnv* env);
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
@@ -136,7 +135,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_drawable_VectorDrawable),
REG_JNI(register_android_graphics_fonts_Font),
REG_JNI(register_android_graphics_fonts_FontFamily),
- REG_JNI(register_android_graphics_fonts_NativeFont),
REG_JNI(register_android_graphics_pdf_PdfDocument),
REG_JNI(register_android_graphics_pdf_PdfEditor),
REG_JNI(register_android_graphics_pdf_PdfRenderer),
diff --git a/libs/hwui/jni/RenderEffect.cpp b/libs/hwui/jni/RenderEffect.cpp
index 97c40d695f97..fa1752cc47d6 100644
--- a/libs/hwui/jni/RenderEffect.cpp
+++ b/libs/hwui/jni/RenderEffect.cpp
@@ -115,6 +115,18 @@ static jlong createChainEffect(
return reinterpret_cast<jlong>(composeFilter.release());
}
+static jlong createShaderEffect(
+ JNIEnv* env,
+ jobject,
+ jlong shaderHandle
+) {
+ auto* shader = reinterpret_cast<const SkShader*>(shaderHandle);
+ sk_sp<SkImageFilter> shaderFilter = SkImageFilters::Shader(
+ sk_ref_sp(shader), nullptr
+ );
+ return reinterpret_cast<jlong>(shaderFilter.release());
+}
+
static void RenderEffect_safeUnref(SkImageFilter* filter) {
SkSafeUnref(filter);
}
@@ -130,7 +142,8 @@ static const JNINativeMethod gRenderEffectMethods[] = {
{"nativeCreateBitmapEffect", "(JFFFFFFFF)J", (void*)createBitmapEffect},
{"nativeCreateColorFilterEffect", "(JJ)J", (void*)createColorFilterEffect},
{"nativeCreateBlendModeEffect", "(JJI)J", (void*)createBlendModeEffect},
- {"nativeCreateChainEffect", "(JJ)J", (void*)createChainEffect}
+ {"nativeCreateChainEffect", "(JJ)J", (void*)createChainEffect},
+ {"nativeCreateShaderEffect", "(J)J", (void*)createShaderEffect}
};
int register_android_graphics_RenderEffect(JNIEnv* env) {
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index b769d40238a4..3392dac02493 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -34,6 +34,7 @@
#include <hwui/Typeface.h>
#include <minikin/FontFamily.h>
#include <minikin/FontFileParser.h>
+#include <minikin/LocaleList.h>
#include <ui/FatVector.h>
#include <memory>
@@ -149,12 +150,8 @@ static jlong Font_Builder_clone(JNIEnv* env, jobject clazz, jlong fontPtr, jlong
return reinterpret_cast<jlong>(new FontWrapper(std::move(newFont)));
}
-// Critical Native
-static jlong Font_Builder_getReleaseNativeFont(CRITICAL_JNI_PARAMS) {
- return reinterpret_cast<jlong>(releaseFont);
-}
-
///////////////////////////////////////////////////////////////////////////////
+// Font JNI functions
// Fast Native
static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint glyphId,
@@ -195,51 +192,92 @@ static jfloat Font_getFontMetrics(JNIEnv* env, jobject, jlong fontHandle, jlong
}
// Critical Native
-static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
- FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- return reinterpret_cast<jlong>(font->font.get());
+static jlong Font_getMinikinFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ return reinterpret_cast<jlong>(font->font->typeface().get());
}
// Critical Native
-static jlong Font_GetBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
- FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
- const void* bufferPtr = font->font->typeface()->GetFontData();
- return reinterpret_cast<jlong>(bufferPtr);
+static jlong Font_cloneFont(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ std::shared_ptr<minikin::Font> ref = font->font;
+ return reinterpret_cast<jlong>(new FontWrapper(std::move(ref)));
}
-///////////////////////////////////////////////////////////////////////////////
-
-struct FontBufferWrapper {
- FontBufferWrapper(const std::shared_ptr<minikin::MinikinFont>& font) : minikinFont(font) {}
- // MinikinFont holds a shared pointer of SkTypeface which has reference to font data.
- std::shared_ptr<minikin::MinikinFont> minikinFont;
-};
+// Fast Native
+static jobject Font_newByteBuffer(JNIEnv* env, jobject, jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ return env->NewDirectByteBuffer(const_cast<void*>(minikinFont->GetFontData()),
+ minikinFont->GetFontSize());
+}
-static void unrefBuffer(jlong nativePtr) {
- FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
- delete wrapper;
+// Critical Native
+static jlong Font_getBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ return reinterpret_cast<jlong>(font->font->typeface()->GetFontData());
}
// Critical Native
-static jlong FontBufferHelper_refFontBuffer(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
- const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
- return reinterpret_cast<jlong>(new FontBufferWrapper(font->typeface()));
+static jlong Font_getReleaseNativeFontFunc() {
+ return reinterpret_cast<jlong>(releaseFont);
}
// Fast Native
-static jobject FontBufferHelper_wrapByteBuffer(JNIEnv* env, jobject, jlong nativePtr) {
- FontBufferWrapper* wrapper = reinterpret_cast<FontBufferWrapper*>(nativePtr);
- return env->NewDirectByteBuffer(
- const_cast<void*>(wrapper->minikinFont->GetFontData()),
- wrapper->minikinFont->GetFontSize());
+static jstring Font_getFontPath(JNIEnv* env, jobject, jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ const std::string& path = minikinFont->GetFontPath();
+ if (path.empty()) {
+ return nullptr;
+ }
+ return env->NewStringUTF(path.c_str());
+}
+
+// Fast Native
+static jstring Font_getLocaleList(JNIEnv* env, jobject, jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ uint32_t localeListId = font->font->getLocaleListId();
+ if (localeListId == 0) {
+ return nullptr;
+ }
+ std::string langTags = minikin::getLocaleString(localeListId);
+ if (langTags.empty()) {
+ return nullptr;
+ }
+ return env->NewStringUTF(langTags.c_str());
}
// Critical Native
-static jlong FontBufferHelper_getReleaseFunc(CRITICAL_JNI_PARAMS) {
- return reinterpret_cast<jlong>(unrefBuffer);
+static jint Font_getPackedStyle(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ uint32_t weight = font->font->style().weight();
+ uint32_t isItalic = font->font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 1 : 0;
+ return (isItalic << 16) | weight;
}
-///////////////////////////////////////////////////////////////////////////////
+// Critical Native
+static jint Font_getIndex(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ return minikinFont->GetFontIndex();
+}
+
+// Critical Native
+static jint Font_getAxisCount(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ return minikinFont->GetAxes().size();
+}
+
+// Critical Native
+static jlong Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontPtr, jint index) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+ const std::shared_ptr<minikin::MinikinFont>& minikinFont = font->font->typeface();
+ minikin::FontVariation var = minikinFont->GetAxes().at(index);
+ uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
+ return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
+}
// Fast Native
static jlong FontFileUtil_getFontRevision(JNIEnv* env, jobject, jobject buffer, jint index) {
@@ -314,20 +352,23 @@ static const JNINativeMethod gFontBuilderMethods[] = {
{"nBuild", "(JLjava/nio/ByteBuffer;Ljava/lang/String;Ljava/lang/String;IZI)J",
(void*)Font_Builder_build},
{"nClone", "(JJIZI)J", (void*)Font_Builder_clone},
- {"nGetReleaseNativeFont", "()J", (void*)Font_Builder_getReleaseNativeFont},
};
static const JNINativeMethod gFontMethods[] = {
- { "nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*) Font_getGlyphBounds },
- { "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
- { "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr },
- { "nGetFontBufferAddress", "(J)J", (void*) Font_GetBufferAddress },
-};
-
-static const JNINativeMethod gFontBufferHelperMethods[] = {
- { "nRefFontBuffer", "(J)J", (void*) FontBufferHelper_refFontBuffer },
- { "nWrapByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*) FontBufferHelper_wrapByteBuffer },
- { "nGetReleaseFunc", "()J", (void*) FontBufferHelper_getReleaseFunc },
+ {"nGetMinikinFontPtr", "(J)J", (void*)Font_getMinikinFontPtr},
+ {"nCloneFont", "(J)J", (void*)Font_cloneFont},
+ {"nNewByteBuffer", "(J)Ljava/nio/ByteBuffer;", (void*)Font_newByteBuffer},
+ {"nGetBufferAddress", "(J)J", (void*)Font_getBufferAddress},
+ {"nGetReleaseNativeFont", "()J", (void*)Font_getReleaseNativeFontFunc},
+ {"nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*)Font_getGlyphBounds},
+ {"nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F",
+ (void*)Font_getFontMetrics},
+ {"nGetFontPath", "(J)Ljava/lang/String;", (void*)Font_getFontPath},
+ {"nGetLocaleList", "(J)Ljava/lang/String;", (void*)Font_getLocaleList},
+ {"nGetPackedStyle", "(J)I", (void*)Font_getPackedStyle},
+ {"nGetIndex", "(J)I", (void*)Font_getIndex},
+ {"nGetAxisCount", "(J)I", (void*)Font_getAxisCount},
+ {"nGetAxisInfo", "(JI)J", (void*)Font_getAxisInfo},
};
static const JNINativeMethod gFontFileUtilMethods[] = {
@@ -343,8 +384,6 @@ int register_android_graphics_fonts_Font(JNIEnv* env) {
NELEM(gFontBuilderMethods)) +
RegisterMethodsOrDie(env, "android/graphics/fonts/Font", gFontMethods,
NELEM(gFontMethods)) +
- RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFontBufferHelper",
- gFontBufferHelperMethods, NELEM(gFontBufferHelperMethods)) +
RegisterMethodsOrDie(env, "android/graphics/fonts/FontFileUtil", gFontFileUtilMethods,
NELEM(gFontFileUtilMethods));
}
diff --git a/libs/hwui/jni/fonts/FontFamily.cpp b/libs/hwui/jni/fonts/FontFamily.cpp
index 8fe6da3183f4..80964794efb2 100644
--- a/libs/hwui/jni/fonts/FontFamily.cpp
+++ b/libs/hwui/jni/fonts/FontFamily.cpp
@@ -100,17 +100,31 @@ static jint FontFamily_getVariant(CRITICAL_JNI_PARAMS_COMMA jlong familyPtr) {
return static_cast<jint>(family->family->variant());
}
+// CriticalNative
+static jint FontFamily_getFontSize(jlong familyPtr) {
+ FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
+ return family->family->getNumFonts();
+}
+
+// CriticalNative
+static jlong FontFamily_getFont(jlong familyPtr, jint index) {
+ FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
+ std::shared_ptr<minikin::Font> font = family->family->getFontRef(index);
+ return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
+}
+
///////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gFontFamilyBuilderMethods[] = {
{ "nInitBuilder", "()J", (void*) FontFamily_Builder_initBuilder },
{ "nAddFont", "(JJ)V", (void*) FontFamily_Builder_addFont },
{ "nBuild", "(JLjava/lang/String;IZ)J", (void*) FontFamily_Builder_build },
-
{ "nGetReleaseNativeFamily", "()J", (void*) FontFamily_Builder_GetReleaseFunc },
};
static const JNINativeMethod gFontFamilyMethods[] = {
+ {"nGetFontSize", "(J)I", (void*)FontFamily_getFontSize},
+ {"nGetFont", "(JI)J", (void*)FontFamily_getFont},
{"nGetLangTags", "(J)Ljava/lang/String;", (void*)FontFamily_getLangTags},
{"nGetVariant", "(J)I", (void*)FontFamily_getVariant},
};
diff --git a/libs/hwui/jni/fonts/NativeFont.cpp b/libs/hwui/jni/fonts/NativeFont.cpp
deleted file mode 100644
index c5c5d464ccac..000000000000
--- a/libs/hwui/jni/fonts/NativeFont.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "Minikin"
-
-#include "Font.h"
-#include "SkData.h"
-#include "SkFont.h"
-#include "SkFontMetrics.h"
-#include "SkFontMgr.h"
-#include "SkRefCnt.h"
-#include "SkTypeface.h"
-#include "GraphicsJNI.h"
-#include <nativehelper/ScopedUtfChars.h>
-#include "Utils.h"
-#include "FontUtils.h"
-
-#include <hwui/MinikinSkia.h>
-#include <hwui/Paint.h>
-#include <hwui/Typeface.h>
-#include <minikin/FontFamily.h>
-#include <minikin/LocaleList.h>
-#include <ui/FatVector.h>
-
-#include <memory>
-
-namespace android {
-
-// Critical Native
-static jint NativeFont_getFamilyCount(CRITICAL_JNI_PARAMS_COMMA jlong typefaceHandle) {
- Typeface* tf = reinterpret_cast<Typeface*>(typefaceHandle);
- return tf->fFontCollection->getFamilies().size();
-}
-
-// Critical Native
-static jlong NativeFont_getFamily(CRITICAL_JNI_PARAMS_COMMA jlong typefaceHandle, jint index) {
- Typeface* tf = reinterpret_cast<Typeface*>(typefaceHandle);
- return reinterpret_cast<jlong>(tf->fFontCollection->getFamilies()[index].get());
-
-}
-
-// Fast Native
-static jstring NativeFont_getLocaleList(JNIEnv* env, jobject, jlong familyHandle) {
- minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
- uint32_t localeListId = family->localeListId();
- return env->NewStringUTF(minikin::getLocaleString(localeListId).c_str());
-}
-
-// Critical Native
-static jint NativeFont_getFontCount(CRITICAL_JNI_PARAMS_COMMA jlong familyHandle) {
- minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
- return family->getNumFonts();
-}
-
-// Critical Native
-static jlong NativeFont_getFont(CRITICAL_JNI_PARAMS_COMMA jlong familyHandle, jint index) {
- minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
- return reinterpret_cast<jlong>(family->getFont(index));
-}
-
-// Critical Native
-static jlong NativeFont_getFontInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
- const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
-
- uint64_t result = font->style().weight();
- result |= font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 0x10000 : 0x00000;
- result |= ((static_cast<uint64_t>(minikinSkia->GetFontIndex())) << 32);
- result |= ((static_cast<uint64_t>(minikinSkia->GetAxes().size())) << 48);
- return result;
-}
-
-// Critical Native
-static jlong NativeFont_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle, jint index) {
- const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
- const minikin::FontVariation& var = minikinSkia->GetAxes().at(index);
- uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
- return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
-}
-
-// FastNative
-static jstring NativeFont_getFontPath(JNIEnv* env, jobject, jlong fontHandle) {
- const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
- MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
- const std::string& filePath = minikinSkia->getFilePath();
- if (filePath.empty()) {
- return nullptr;
- }
- return env->NewStringUTF(filePath.c_str());
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static const JNINativeMethod gNativeFontMethods[] = {
- { "nGetFamilyCount", "(J)I", (void*) NativeFont_getFamilyCount },
- { "nGetFamily", "(JI)J", (void*) NativeFont_getFamily },
- { "nGetLocaleList", "(J)Ljava/lang/String;", (void*) NativeFont_getLocaleList },
- { "nGetFontCount", "(J)I", (void*) NativeFont_getFontCount },
- { "nGetFont", "(JI)J", (void*) NativeFont_getFont },
- { "nGetFontInfo", "(J)J", (void*) NativeFont_getFontInfo },
- { "nGetAxisInfo", "(JI)J", (void*) NativeFont_getAxisInfo },
- { "nGetFontPath", "(J)Ljava/lang/String;", (void*) NativeFont_getFontPath },
-};
-
-int register_android_graphics_fonts_NativeFont(JNIEnv* env) {
- return RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFont", gNativeFontMethods,
- NELEM(gNativeFontMethods));
-}
-
-} // namespace android
diff --git a/libs/hwui/jni/text/TextShaper.cpp b/libs/hwui/jni/text/TextShaper.cpp
index 9785aa537f65..a6fb95832c03 100644
--- a/libs/hwui/jni/text/TextShaper.cpp
+++ b/libs/hwui/jni/text/TextShaper.cpp
@@ -23,13 +23,14 @@
#include <set>
#include <algorithm>
-#include "SkPaint.h"
-#include "SkTypeface.h"
#include <hwui/MinikinSkia.h>
#include <hwui/MinikinUtils.h>
#include <hwui/Paint.h>
-#include <minikin/MinikinPaint.h>
#include <minikin/MinikinFont.h>
+#include <minikin/MinikinPaint.h>
+#include "FontUtils.h"
+#include "SkPaint.h"
+#include "SkTypeface.h"
namespace android {
@@ -149,7 +150,8 @@ static jfloat TextShaper_Result_getY(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i
// CriticalNative
static jlong TextShaper_Result_getFont(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) {
const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr);
- return reinterpret_cast<jlong>(layout->layout.getFont(i));
+ std::shared_ptr<minikin::Font> fontRef = layout->layout.getFontRef(i);
+ return reinterpret_cast<jlong>(new FontWrapper(std::move(fontRef)));
}
// CriticalNative
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 85924c5e8939..d998e5031984 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -101,7 +101,8 @@ void CacheManager::trimMemory(TrimMemoryMode mode) {
return;
}
- mGrContext->flushAndSubmit();
+ // flush and submit all work to the gpu and wait for it to finish
+ mGrContext->flushAndSubmit(/*syncCpu=*/true);
switch (mode) {
case TrimMemoryMode::Complete:
@@ -119,11 +120,6 @@ void CacheManager::trimMemory(TrimMemoryMode mode) {
SkGraphics::SetFontCacheLimit(mMaxCpuFontCacheBytes);
break;
}
-
- // We must sync the cpu to make sure deletions of resources still queued up on the GPU actually
- // happen.
- mGrContext->flush({});
- mGrContext->submit(true);
}
void CacheManager::trimStaleResources() {
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index 06f158f25fc5..6a9a98d6743b 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -40,9 +40,9 @@ const DisplayInfo& getDisplayInfo() {
return info;
}
-const DisplayConfig& getActiveDisplayConfig() {
- static DisplayConfig config = [] {
- DisplayConfig config;
+const ui::DisplayMode& getActiveDisplayMode() {
+ static ui::DisplayMode config = [] {
+ ui::DisplayMode config;
#if HWUI_NULL_GPU
config.resolution = ui::Size(1080, 1920);
config.xDpi = config.yDpi = 320.f;
@@ -51,7 +51,7 @@ const DisplayConfig& getActiveDisplayConfig() {
const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
LOG_ALWAYS_FATAL_IF(!token, "%s: No internal display", __FUNCTION__);
- const status_t status = SurfaceComposerClient::getActiveDisplayConfig(token, &config);
+ const status_t status = SurfaceComposerClient::getActiveDisplayMode(token, &config);
LOG_ALWAYS_FATAL_IF(status, "%s: Failed to get active display config", __FUNCTION__);
#endif
return config;
diff --git a/libs/hwui/tests/common/TestContext.h b/libs/hwui/tests/common/TestContext.h
index a012ecb1a1d3..7d2f6d8ea731 100644
--- a/libs/hwui/tests/common/TestContext.h
+++ b/libs/hwui/tests/common/TestContext.h
@@ -23,8 +23,8 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
-#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
+#include <ui/DisplayMode.h>
#include <utils/Looper.h>
#include <atomic>
@@ -37,10 +37,10 @@ namespace uirenderer {
namespace test {
const DisplayInfo& getDisplayInfo();
-const DisplayConfig& getActiveDisplayConfig();
+const ui::DisplayMode& getActiveDisplayMode();
inline const ui::Size& getActiveDisplayResolution() {
- return getActiveDisplayConfig().resolution;
+ return getActiveDisplayMode().resolution;
}
class TestContext {
diff --git a/libs/tracingproxy/Android.bp b/libs/tracingproxy/Android.bp
new file mode 100644
index 000000000000..67f407ff7599
--- /dev/null
+++ b/libs/tracingproxy/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Provides C++ wrappers for system services.
+
+cc_library_shared {
+ name: "libtracingproxy",
+
+ aidl: {
+ export_aidl_headers: true,
+ include_dirs: [
+ "frameworks/base/core/java",
+ ],
+ },
+
+ srcs: [
+ ":ITracingServiceProxy.aidl",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 65721cc33aed..adf58da6a072 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -36,6 +36,7 @@ import android.location.LastLocationRequest;
import android.location.Location;
import android.location.LocationRequest;
import android.location.LocationTime;
+import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
import android.os.Bundle;
import android.os.ICancellationSignal;
@@ -91,6 +92,9 @@ interface ILocationManager
void addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener, String packageName, @nullable String attributionTag);
void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);
+ void addProviderRequestListener(in IProviderRequestListener listener);
+ void removeProviderRequestListener(in IProviderRequestListener listener);
+
int getGnssBatchSize();
void startGnssBatch(long periodNanos, in ILocationListener listener, String packageName, @nullable String attributionTag, @nullable String listenerId);
void flushGnssBatch();
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index d56948222797..088b789ea690 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -49,7 +49,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
+import android.location.provider.ProviderRequest;
+import android.location.provider.ProviderRequest.Listener;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -436,6 +439,9 @@ public class LocationManager {
new GnssNavigationTransportManager();
}
+ private static final ProviderRequestTransportManager sProviderRequestListeners =
+ new ProviderRequestTransportManager();
+
private final Context mContext;
private final ILocationManager mService;
@@ -2772,6 +2778,37 @@ public class LocationManager {
}
/**
+ * Registers a {@link ProviderRequest.Listener} to all providers.
+ *
+ * @param executor the executor that the callback runs on
+ * @param listener the listener to register
+ * @return {@code true} always
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public boolean registerProviderRequestListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Listener listener) {
+ sProviderRequestListeners.addListener(listener,
+ new ProviderRequestTransport(executor, listener));
+ return true;
+ }
+
+ /**
+ * Unregisters a {@link ProviderRequest.Listener}.
+ *
+ * @param listener the listener to remove.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ public void unregisterProviderRequestListener(
+ @NonNull Listener listener) {
+ sProviderRequestListeners.removeListener(listener);
+ }
+
+ /**
* Returns the batch size (in number of Location objects) that are supported by the batching
* interface.
*
@@ -2960,6 +2997,22 @@ public class LocationManager {
}
}
+ private static class ProviderRequestTransportManager extends
+ ListenerTransportManager<ProviderRequestTransport> {
+
+ @Override
+ protected void registerTransport(ProviderRequestTransport transport)
+ throws RemoteException {
+ getService().addProviderRequestListener(transport);
+ }
+
+ @Override
+ protected void unregisterTransport(ProviderRequestTransport transport)
+ throws RemoteException {
+ getService().removeProviderRequestListener(transport);
+ }
+ }
+
private static class GetCurrentLocationTransport extends ILocationCallback.Stub implements
ListenerExecutor, CancellationSignal.OnCancelListener {
@@ -3359,6 +3412,36 @@ public class LocationManager {
}
}
+ private static class ProviderRequestTransport extends IProviderRequestListener.Stub
+ implements ListenerTransport<ProviderRequest.Listener> {
+
+ private final Executor mExecutor;
+
+ private volatile @Nullable ProviderRequest.Listener mListener;
+
+ ProviderRequestTransport(Executor executor, ProviderRequest.Listener listener) {
+ Preconditions.checkArgument(executor != null, "invalid null executor");
+ Preconditions.checkArgument(listener != null, "invalid null callback");
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void unregister() {
+ mListener = null;
+ }
+
+ @Override
+ public @Nullable ProviderRequest.Listener getListener() {
+ return mListener;
+ }
+
+ @Override
+ public void onProviderRequestChanged(String provider, ProviderRequest request) {
+ execute(mExecutor, listener -> listener.onProviderRequestChanged(provider, request));
+ }
+ }
+
private static class BatchedLocationCallbackWrapper implements LocationListener {
private final BatchedLocationCallback mCallback;
diff --git a/location/java/android/location/provider/IProviderRequestListener.aidl b/location/java/android/location/provider/IProviderRequestListener.aidl
new file mode 100644
index 000000000000..89d454aafe2c
--- /dev/null
+++ b/location/java/android/location/provider/IProviderRequestListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location.provider;
+
+import android.location.provider.ProviderRequest;
+
+/**
+ * {@hide}
+ */
+oneway interface IProviderRequestListener {
+ void onProviderRequestChanged(String provider, in ProviderRequest request);
+}
diff --git a/location/java/android/location/provider/ProviderRequest.java b/location/java/android/location/provider/ProviderRequest.java
index e543b040a2d4..b6ec32309b08 100644
--- a/location/java/android/location/provider/ProviderRequest.java
+++ b/location/java/android/location/provider/ProviderRequest.java
@@ -53,6 +53,17 @@ public final class ProviderRequest implements Parcelable {
private final boolean mLocationSettingsIgnored;
private final WorkSource mWorkSource;
+ /**
+ * Listener to be invoked when a new request is set to the provider.
+ */
+ public interface Listener {
+
+ /**
+ * Invoked when a new request is set.
+ */
+ void onProviderRequestChanged(@NonNull String provider, @NonNull ProviderRequest request);
+ }
+
private ProviderRequest(
long intervalMillis,
@Quality int quality,
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 06bf5f70d9ec..9c6b276e7b20 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -119,9 +119,14 @@ public class CamcorderProfile
*/
public static final int QUALITY_2K = 12;
+ /**
+ * Quality level corresponding to 8K UHD (7680 x 4320) resolution
+ */
+ public static final int QUALITY_8KUHD = 13;
+
// Start and end of quality list
private static final int QUALITY_LIST_START = QUALITY_LOW;
- private static final int QUALITY_LIST_END = QUALITY_2K;
+ private static final int QUALITY_LIST_END = QUALITY_8KUHD;
/**
* Time lapse quality level corresponding to the lowest available resolution.
@@ -188,10 +193,14 @@ public class CamcorderProfile
*/
public static final int QUALITY_TIME_LAPSE_2K = 1012;
+ /**
+ * Time lapse quality level corresponding to the 8K UHD (7680 x 4320) resolution.
+ */
+ public static final int QUALITY_TIME_LAPSE_8KUHD = 1013;
// Start and end of timelapse quality list
private static final int QUALITY_TIME_LAPSE_LIST_START = QUALITY_TIME_LAPSE_LOW;
- private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_2K;
+ private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_8KUHD;
/**
* High speed ( >= 100fps) quality level corresponding to the lowest available resolution.
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 31fb8d03c4a0..9bf126b7a875 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -35,7 +35,7 @@ interface ISession {
ISessionController getController();
void setFlags(int flags);
void setActive(boolean active);
- void setMediaButtonReceiver(in PendingIntent mbr);
+ void setMediaButtonReceiver(in PendingIntent mbr, String sessionPackageName);
void setMediaButtonBroadcastReceiver(in ComponentName broadcastReceiver);
void setLaunchPendingIntent(in PendingIntent pi);
void destroySession();
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 24118b086c24..20fa53d3ec32 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -286,7 +286,7 @@ public final class MediaSession {
@Deprecated
public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
try {
- mBinder.setMediaButtonReceiver(mbr);
+ mBinder.setMediaButtonReceiver(mbr, mContext.getPackageName());
} catch (RemoteException e) {
Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
}
diff --git a/media/jni/tuner/DemuxClient.h b/media/jni/tuner/DemuxClient.h
index 31eb35a1a56d..c38a8fa34690 100644
--- a/media/jni/tuner/DemuxClient.h
+++ b/media/jni/tuner/DemuxClient.h
@@ -100,6 +100,11 @@ public:
*/
Result close();
+ /**
+ * Get the Aidl demux to set as source.
+ */
+ shared_ptr<ITunerDemux> getAidlDemux() { return mTunerDemux; }
+
void setId(int id) { mId = id; }
int getId() { return mId; }
diff --git a/media/jni/tuner/DescramblerClient.cpp b/media/jni/tuner/DescramblerClient.cpp
index 979beeac6b3a..c9bacda0fa70 100644
--- a/media/jni/tuner/DescramblerClient.cpp
+++ b/media/jni/tuner/DescramblerClient.cpp
@@ -27,13 +27,12 @@ namespace android {
/////////////// DescramblerClient ///////////////////////
-// TODO: pending aidl interface
-DescramblerClient::DescramblerClient() {
- //mTunerDescrambler = tunerDescrambler;
+DescramblerClient::DescramblerClient(shared_ptr<ITunerDescrambler> tunerDescrambler) {
+ mTunerDescrambler = tunerDescrambler;
}
DescramblerClient::~DescramblerClient() {
- //mTunerDescrambler = NULL;
+ mTunerDescrambler = NULL;
mDescrambler = NULL;
}
@@ -47,7 +46,10 @@ Result DescramblerClient::setDemuxSource(sp<DemuxClient> demuxClient) {
return Result::INVALID_ARGUMENT;
}
- // TODO: pending aidl interface
+ if (mTunerDescrambler != NULL) {
+ Status s = mTunerDescrambler->setDemuxSource(demuxClient->getAidlDemux());
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mDescrambler != NULL) {
return mDescrambler->setDemuxSource(demuxClient->getId());
@@ -57,7 +59,10 @@ Result DescramblerClient::setDemuxSource(sp<DemuxClient> demuxClient) {
}
Result DescramblerClient::setKeyToken(vector<uint8_t> keyToken) {
- // TODO: pending aidl interface
+ if (mTunerDescrambler != NULL) {
+ Status s = mTunerDescrambler->setKeyToken(keyToken);
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mDescrambler != NULL) {
return mDescrambler->setKeyToken(keyToken);
@@ -67,7 +72,11 @@ Result DescramblerClient::setKeyToken(vector<uint8_t> keyToken) {
}
Result DescramblerClient::addPid(DemuxPid pid, sp<FilterClient> optionalSourceFilter) {
- // TODO: pending aidl interface
+ if (mTunerDescrambler != NULL) {
+ Status s = mTunerDescrambler->addPid(
+ getAidlDemuxPid(pid), optionalSourceFilter->getAidlFilter());
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mDescrambler != NULL) {
return mDescrambler->addPid(pid, optionalSourceFilter->getHalFilter());
@@ -76,16 +85,24 @@ Result DescramblerClient::addPid(DemuxPid pid, sp<FilterClient> optionalSourceFi
return Result::INVALID_STATE;}
Result DescramblerClient::removePid(DemuxPid pid, sp<FilterClient> optionalSourceFilter) {
- // TODO: pending aidl interface
+ if (mTunerDescrambler != NULL) {
+ Status s = mTunerDescrambler->removePid(
+ getAidlDemuxPid(pid), optionalSourceFilter->getAidlFilter());
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mDescrambler != NULL) {
- return mDescrambler->addPid(pid, optionalSourceFilter->getHalFilter());
+ return mDescrambler->removePid(pid, optionalSourceFilter->getHalFilter());
}
- return Result::INVALID_STATE;}
+ return Result::INVALID_STATE;
+}
Result DescramblerClient::close() {
- // TODO: pending aidl interface
+ if (mTunerDescrambler != NULL) {
+ Status s = mTunerDescrambler->close();
+ return ClientHelper::getServiceSpecificErrorCode(s);
+ }
if (mDescrambler != NULL) {
return mDescrambler->close();
@@ -95,4 +112,16 @@ Result DescramblerClient::close() {
/////////////// DescramblerClient Helper Methods ///////////////////////
+TunerDemuxPid DescramblerClient::getAidlDemuxPid(DemuxPid& pid) {
+ TunerDemuxPid aidlPid;
+ switch (pid.getDiscriminator()) {
+ case DemuxPid::hidl_discriminator::tPid:
+ aidlPid.set<TunerDemuxPid::tPid>((int)pid.tPid());
+ break;
+ case DemuxPid::hidl_discriminator::mmtpPid:
+ aidlPid.set<TunerDemuxPid::mmtpPid>((int)pid.mmtpPid());
+ break;
+ }
+ return aidlPid;
+}
} // namespace android
diff --git a/media/jni/tuner/DescramblerClient.h b/media/jni/tuner/DescramblerClient.h
index 8af688314db1..a8fa1e2e0497 100644
--- a/media/jni/tuner/DescramblerClient.h
+++ b/media/jni/tuner/DescramblerClient.h
@@ -17,14 +17,15 @@
#ifndef _ANDROID_MEDIA_TV_DESCRAMBLER_CLIENT_H_
#define _ANDROID_MEDIA_TV_DESCRAMBLER_CLIENT_H_
-//#include <aidl/android/media/tv/tuner/ITunerDescrambler.h>
+#include <aidl/android/media/tv/tuner/ITunerDescrambler.h>
#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
#include <android/hardware/tv/tuner/1.1/types.h>
#include "DemuxClient.h"
#include "FilterClient.h"
-//using ::aidl::android::media::tv::tuner::ITunerDescrambler;
+using ::aidl::android::media::tv::tuner::ITunerDescrambler;
+using ::aidl::android::media::tv::tuner::TunerDemuxPid;
using ::android::hardware::tv::tuner::V1_0::IDescrambler;
using ::android::hardware::tv::tuner::V1_0::Result;
@@ -37,8 +38,7 @@ namespace android {
struct DescramblerClient : public RefBase {
public:
- // TODO: pending hidl interface
- DescramblerClient();
+ DescramblerClient(shared_ptr<ITunerDescrambler> tunerDescrambler);
~DescramblerClient();
// TODO: remove after migration to Tuner Service is done.
@@ -70,12 +70,13 @@ public:
Result close();
private:
+ TunerDemuxPid getAidlDemuxPid(DemuxPid& pid);
+
/**
* An AIDL Tuner Descrambler Singleton assigned at the first time the Tuner Client
* opens a descrambler. Default null when descrambler is not opened.
*/
- // TODO: pending on aidl interface
- //shared_ptr<ITunerDescrambler> mTunerDescrambler;
+ shared_ptr<ITunerDescrambler> mTunerDescrambler;
/**
* A Descrambler HAL interface that is ready before migrating to the TunerDescrambler.
diff --git a/media/jni/tuner/FrontendClient.cpp b/media/jni/tuner/FrontendClient.cpp
index f454907851a4..3a00133c69e2 100644
--- a/media/jni/tuner/FrontendClient.cpp
+++ b/media/jni/tuner/FrontendClient.cpp
@@ -91,8 +91,8 @@ Result FrontendClient::setCallback(sp<FrontendClientCallback> frontendClientCall
if (mTunerFrontend != NULL) {
mAidlCallback = ::ndk::SharedRefBase::make<TunerFrontendCallback>(frontendClientCallback);
mAidlCallback->setFrontendType(mType);
- mTunerFrontend->setCallback(mAidlCallback);
- return Result::SUCCESS;
+ Status s = mTunerFrontend->setCallback(mAidlCallback);
+ return ClientHelper::getServiceSpecificErrorCode(s);
}
mHidlCallback = new HidlFrontendCallback(frontendClientCallback);
@@ -243,9 +243,8 @@ vector<FrontendStatusExt1_1> FrontendClient::getStatusExtended_1_1(
Result FrontendClient::setLnb(sp<LnbClient> lnbClient) {
if (mTunerFrontend != NULL) {
- // TODO: handle error message.
- /*mTunerFrontend->setLnb(lnbClient->getAidlLnb());
- return Result::SUCCESS;*/
+ Status s = mTunerFrontend->setLnb(lnbClient->getAidlLnb());
+ return ClientHelper::getServiceSpecificErrorCode(s);
}
if (mFrontend != NULL) {
@@ -258,9 +257,8 @@ Result FrontendClient::setLnb(sp<LnbClient> lnbClient) {
Result FrontendClient::setLna(bool bEnable) {
if (mTunerFrontend != NULL) {
- // TODO: handle error message.
- /*mTunerFrontend->setLna(bEnable);
- return Result::SUCCESS;*/
+ Status s = mTunerFrontend->setLna(bEnable);
+ return ClientHelper::getServiceSpecificErrorCode(s);
}
if (mFrontend != NULL) {
@@ -275,9 +273,11 @@ int FrontendClient::linkCiCamToFrontend(int ciCamId) {
int ltsId = (int)Constant::INVALID_LTS_ID;
if (mTunerFrontend != NULL) {
- // TODO: handle error message.
- /*mTunerFrontend->linkCiCamToFrontend(ciCamId, ltsId);
- return ltsId;*/
+ Status s = mTunerFrontend->linkCiCamToFrontend(ciCamId, &ltsId);
+ if (ClientHelper::getServiceSpecificErrorCode(s) == Result::SUCCESS) {
+ return ltsId;
+ }
+ return (int)Constant::INVALID_LTS_ID;
}
if (mFrontend_1_1 != NULL) {
@@ -297,9 +297,8 @@ int FrontendClient::linkCiCamToFrontend(int ciCamId) {
Result FrontendClient::unlinkCiCamToFrontend(int ciCamId) {
if (mTunerFrontend != NULL) {
- // TODO: handle error message.
- /*mTunerFrontend->unlinkCiCamToFrontend(ciCamId);
- return Result::SUCCESS;*/
+ Status s = mTunerFrontend->unlinkCiCamToFrontend(ciCamId);
+ return ClientHelper::getServiceSpecificErrorCode(s);
}
if (mFrontend_1_1 != NULL) {
diff --git a/media/jni/tuner/LnbClient.h b/media/jni/tuner/LnbClient.h
index e7869e890e8f..465dc2331ecf 100644
--- a/media/jni/tuner/LnbClient.h
+++ b/media/jni/tuner/LnbClient.h
@@ -108,7 +108,7 @@ public:
*/
Result close();
- //shared_ptr<ITunerLnb> getAidlLnb() { return mTunerLnb; }
+ shared_ptr<ITunerLnb> getAidlLnb() { return mTunerLnb; }
void setId(LnbId id) { mId = id; }
LnbId getId() { return mId; }
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index a604490daf58..7f954b561567 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -22,7 +22,10 @@
#include "TunerClient.h"
+using ::aidl::android::media::tv::tuner::TunerFrontendCapabilities;
+using ::aidl::android::media::tv::tuner::TunerFrontendDtmbCapabilities;
using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::FrontendStatusType;
using ::android::hardware::tv::tuner::V1_0::FrontendType;
namespace android {
@@ -136,12 +139,11 @@ sp<FrontendClient> TunerClient::openFrontend(int frontendHandle) {
shared_ptr<FrontendInfo> TunerClient::getFrontendInfo(int id) {
if (mTunerService != NULL) {
TunerFrontendInfo aidlFrontendInfo;
- // TODO: handle error code
Status s = mTunerService->getFrontendInfo(id, &aidlFrontendInfo);
if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
return NULL;
}
- return make_shared<FrontendInfo>(FrontendInfoAidlToHidl(aidlFrontendInfo));
+ return make_shared<FrontendInfo>(frontendInfoAidlToHidl(aidlFrontendInfo));
}
if (mTuner != NULL) {
@@ -157,7 +159,22 @@ shared_ptr<FrontendInfo> TunerClient::getFrontendInfo(int id) {
}
shared_ptr<FrontendDtmbCapabilities> TunerClient::getFrontendDtmbCapabilities(int id) {
- // pending aidl interface
+ if (mTunerService != NULL) {
+ TunerFrontendDtmbCapabilities dtmbCaps;
+ Status s = mTunerService->getFrontendDtmbCapabilities(id, &dtmbCaps);
+ if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
+ return NULL;
+ }
+ FrontendDtmbCapabilities hidlCaps{
+ .transmissionModeCap = static_cast<uint32_t>(dtmbCaps.transmissionModeCap),
+ .bandwidthCap = static_cast<uint32_t>(dtmbCaps.bandwidthCap),
+ .modulationCap = static_cast<uint32_t>(dtmbCaps.modulationCap),
+ .codeRateCap = static_cast<uint32_t>(dtmbCaps.codeRateCap),
+ .guardIntervalCap = static_cast<uint32_t>(dtmbCaps.guardIntervalCap),
+ .interleaveModeCap = static_cast<uint32_t>(dtmbCaps.interleaveModeCap),
+ };
+ return make_shared<FrontendDtmbCapabilities>(hidlCaps);
+ }
if (mTuner_1_1 != NULL) {
Result result;
@@ -224,17 +241,18 @@ shared_ptr<DemuxCapabilities> TunerClient::getDemuxCaps() {
return NULL;
}
-sp<DescramblerClient> TunerClient::openDescrambler(int /*descramblerHandle*/) {
+sp<DescramblerClient> TunerClient::openDescrambler(int descramblerHandle) {
if (mTunerService != NULL) {
- // TODO: handle error code
- /*shared_ptr<ITunerDescrambler> tunerDescrambler;
- mTunerService->openDescrambler(demuxHandle, &tunerDescrambler);
- return new DescramblerClient(tunerDescrambler);*/
+ shared_ptr<ITunerDescrambler> tunerDescrambler;
+ Status s = mTunerService->openDescrambler(descramblerHandle, &tunerDescrambler);
+ if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) {
+ return NULL;
+ }
+ return new DescramblerClient(tunerDescrambler);
}
if (mTuner != NULL) {
- // TODO: pending aidl interface
- sp<DescramblerClient> descramblerClient = new DescramblerClient();
+ sp<DescramblerClient> descramblerClient = new DescramblerClient(NULL);
sp<IDescrambler> hidlDescrambler = openHidlDescrambler();
if (hidlDescrambler != NULL) {
descramblerClient->setHidlDescrambler(hidlDescrambler);
@@ -486,7 +504,7 @@ DemuxCapabilities TunerClient::getHidlDemuxCaps(TunerDemuxCapabilities& aidlCaps
return caps;
}
-FrontendInfo TunerClient::FrontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendInfo) {
+FrontendInfo TunerClient::frontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendInfo) {
FrontendInfo hidlFrontendInfo {
.type = static_cast<FrontendType>(aidlFrontendInfo.type),
.minFrequency = static_cast<uint32_t>(aidlFrontendInfo.minFrequency),
@@ -496,8 +514,102 @@ FrontendInfo TunerClient::FrontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendI
.acquireRange = static_cast<uint32_t>(aidlFrontendInfo.acquireRange),
.exclusiveGroupId = static_cast<uint32_t>(aidlFrontendInfo.exclusiveGroupId),
};
- // TODO: handle Frontend caps
+ int size = aidlFrontendInfo.statusCaps.size();
+ hidlFrontendInfo.statusCaps.resize(size);
+ for (int i = 0; i < size; i++) {
+ hidlFrontendInfo.statusCaps[i] =
+ static_cast<FrontendStatusType>(aidlFrontendInfo.statusCaps[i]);
+ }
+
+ switch (aidlFrontendInfo.caps.getTag()) {
+ case TunerFrontendCapabilities::analogCaps: {
+ auto analog = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::analogCaps>();
+ hidlFrontendInfo.frontendCaps.analogCaps({
+ .typeCap = static_cast<uint32_t>(analog.typeCap),
+ .sifStandardCap = static_cast<uint32_t>(analog.sifStandardCap),
+ });
+ break;
+ }
+ case TunerFrontendCapabilities::atscCaps: {
+ auto atsc = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::atscCaps>();
+ hidlFrontendInfo.frontendCaps.atscCaps({
+ .modulationCap = static_cast<uint32_t>(atsc.modulationCap),
+ });
+ break;
+ }
+ case TunerFrontendCapabilities::atsc3Caps: {
+ auto atsc3 = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::atsc3Caps>();
+ hidlFrontendInfo.frontendCaps.atsc3Caps({
+ .bandwidthCap = static_cast<uint32_t>(atsc3.bandwidthCap),
+ .modulationCap = static_cast<uint32_t>(atsc3.modulationCap),
+ .timeInterleaveModeCap = static_cast<uint32_t>(atsc3.timeInterleaveModeCap),
+ .codeRateCap = static_cast<uint32_t>(atsc3.codeRateCap),
+ .fecCap = static_cast<uint32_t>(atsc3.fecCap),
+ .demodOutputFormatCap = static_cast<uint8_t>(atsc3.demodOutputFormatCap),
+ });
+ break;
+ }
+ case TunerFrontendCapabilities::cableCaps: {
+ auto cable = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::cableCaps>();
+ hidlFrontendInfo.frontendCaps.dvbcCaps({
+ .modulationCap = static_cast<uint32_t>(cable.modulationCap),
+ .fecCap = static_cast<uint64_t>(cable.codeRateCap),
+ .annexCap = static_cast<uint8_t>(cable.annexCap),
+ });
+ break;
+ }
+ case TunerFrontendCapabilities::dvbsCaps: {
+ auto dvbs = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::dvbsCaps>();
+ hidlFrontendInfo.frontendCaps.dvbsCaps({
+ .modulationCap = static_cast<int32_t>(dvbs.modulationCap),
+ .innerfecCap = static_cast<uint64_t>(dvbs.codeRateCap),
+ .standard = static_cast<uint8_t>(dvbs.standard),
+ });
+ break;
+ }
+ case TunerFrontendCapabilities::dvbtCaps: {
+ auto dvbt = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::dvbtCaps>();
+ hidlFrontendInfo.frontendCaps.dvbtCaps({
+ .transmissionModeCap = static_cast<uint32_t>(dvbt.transmissionModeCap),
+ .bandwidthCap = static_cast<uint32_t>(dvbt.bandwidthCap),
+ .constellationCap = static_cast<uint32_t>(dvbt.constellationCap),
+ .coderateCap = static_cast<uint32_t>(dvbt.codeRateCap),
+ .hierarchyCap = static_cast<uint32_t>(dvbt.hierarchyCap),
+ .guardIntervalCap = static_cast<uint32_t>(dvbt.guardIntervalCap),
+ .isT2Supported = dvbt.isT2Supported,
+ .isMisoSupported = dvbt.isMisoSupported,
+ });
+ break;
+ }
+ case TunerFrontendCapabilities::isdbsCaps: {
+ auto isdbs = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::isdbsCaps>();
+ hidlFrontendInfo.frontendCaps.isdbsCaps({
+ .modulationCap = static_cast<uint32_t>(isdbs.modulationCap),
+ .coderateCap = static_cast<uint32_t>(isdbs.codeRateCap),
+ });
+ break;
+ }
+ case TunerFrontendCapabilities::isdbs3Caps: {
+ auto isdbs3 = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::isdbs3Caps>();
+ hidlFrontendInfo.frontendCaps.isdbs3Caps({
+ .modulationCap = static_cast<uint32_t>(isdbs3.modulationCap),
+ .coderateCap = static_cast<uint32_t>(isdbs3.codeRateCap),
+ });
+ break;
+ }
+ case TunerFrontendCapabilities::isdbtCaps: {
+ auto isdbt = aidlFrontendInfo.caps.get<TunerFrontendCapabilities::isdbtCaps>();
+ hidlFrontendInfo.frontendCaps.isdbtCaps({
+ .modeCap = static_cast<uint32_t>(isdbt.modeCap),
+ .bandwidthCap = static_cast<uint32_t>(isdbt.bandwidthCap),
+ .modulationCap = static_cast<uint32_t>(isdbt.modulationCap),
+ .coderateCap = static_cast<uint32_t>(isdbt.codeRateCap),
+ .guardIntervalCap = static_cast<uint32_t>(isdbt.guardIntervalCap),
+ });
+ break;
+ }
+ }
return hidlFrontendInfo;
}
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index acd018eb1e44..744bf2058766 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -147,7 +147,7 @@ private:
sp<IDescrambler> openHidlDescrambler();
vector<int> getLnbHandles();
DemuxCapabilities getHidlDemuxCaps(TunerDemuxCapabilities& aidlCaps);
- FrontendInfo FrontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendInfo);
+ FrontendInfo frontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendInfo);
void updateTunerResources();
void updateFrontendResources();
void updateLnbResources();
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 3b054e942178..a74613970ce7 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -1368,7 +1368,7 @@ public class ConnectivityManager {
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
try {
return mService.getDefaultNetworkCapabilitiesForUser(
- userId, mContext.getOpPackageName());
+ userId, mContext.getOpPackageName(), getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1450,7 +1450,8 @@ public class ConnectivityManager {
@Nullable
public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
try {
- return mService.getNetworkCapabilities(network, mContext.getOpPackageName());
+ return mService.getNetworkCapabilities(
+ network, mContext.getOpPackageName(), getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3735,7 +3736,8 @@ public class ConnectivityManager {
Binder binder = new Binder();
if (reqType == LISTEN) {
request = mService.listenForNetwork(
- need, messenger, binder, callingPackageName);
+ need, messenger, binder, callingPackageName,
+ getAttributionTag());
} else {
request = mService.requestNetwork(
need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
@@ -4180,7 +4182,8 @@ public class ConnectivityManager {
checkPendingIntentNotNull(operation);
try {
mService.pendingListenForNetwork(
- request.networkCapabilities, operation, mContext.getOpPackageName());
+ request.networkCapabilities, operation, mContext.getOpPackageName(),
+ getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index e2672c480c10..f909d1362550 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -66,7 +66,7 @@ interface IConnectivityManager
Network getNetworkForType(int networkType);
Network[] getAllNetworks();
NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
- int userId, String callingPackageName);
+ int userId, String callingPackageName, String callingAttributionTag);
boolean isNetworkSupported(int networkType);
@@ -75,7 +75,8 @@ interface IConnectivityManager
LinkProperties getLinkPropertiesForType(int networkType);
LinkProperties getLinkProperties(in Network network);
- NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName);
+ NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName,
+ String callingAttributionTag);
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
NetworkState[] getAllNetworkState();
@@ -176,10 +177,12 @@ interface IConnectivityManager
void releasePendingNetworkRequest(in PendingIntent operation);
NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
- in Messenger messenger, in IBinder binder, String callingPackageName);
+ in Messenger messenger, in IBinder binder, String callingPackageName,
+ String callingAttributionTag);
void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
- in PendingIntent operation, String callingPackageName);
+ in PendingIntent operation, String callingPackageName,
+ String callingAttributionTag);
void releaseNetworkRequest(in NetworkRequest networkRequest);
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index b9ef4c21ef6f..6540397d6200 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -16,6 +16,22 @@
package android.net;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -30,6 +46,8 @@ import android.os.Process;
import android.text.TextUtils;
import android.util.proto.ProtoOutputStream;
+import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -156,8 +174,30 @@ public class NetworkRequest implements Parcelable {
* needed in terms of {@link NetworkCapabilities} features
*/
public static class Builder {
+ /**
+ * Capabilities that are currently compatible with VCN networks.
+ */
+ private static final List<Integer> VCN_SUPPORTED_CAPABILITIES = Arrays.asList(
+ NET_CAPABILITY_CAPTIVE_PORTAL,
+ NET_CAPABILITY_DUN,
+ NET_CAPABILITY_FOREGROUND,
+ NET_CAPABILITY_INTERNET,
+ NET_CAPABILITY_NOT_CONGESTED,
+ NET_CAPABILITY_NOT_METERED,
+ NET_CAPABILITY_NOT_RESTRICTED,
+ NET_CAPABILITY_NOT_ROAMING,
+ NET_CAPABILITY_NOT_SUSPENDED,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_PARTIAL_CONNECTIVITY,
+ NET_CAPABILITY_TEMPORARILY_NOT_METERED,
+ NET_CAPABILITY_TRUSTED,
+ NET_CAPABILITY_VALIDATED);
+
private final NetworkCapabilities mNetworkCapabilities;
+ // A boolean that represents the user modified NOT_VCN_MANAGED capability.
+ private boolean mModifiedNotVcnManaged = false;
+
/**
* Default constructor for Builder.
*/
@@ -179,6 +219,7 @@ public class NetworkRequest implements Parcelable {
// maybeMarkCapabilitiesRestricted() doesn't add back.
final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
nc.maybeMarkCapabilitiesRestricted();
+ deduceNotVcnManagedCapability(nc);
return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
ConnectivityManager.REQUEST_ID_UNSET, Type.NONE);
}
@@ -195,6 +236,9 @@ public class NetworkRequest implements Parcelable {
*/
public Builder addCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addCapability(capability);
+ if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
+ mModifiedNotVcnManaged = true;
+ }
return this;
}
@@ -206,6 +250,9 @@ public class NetworkRequest implements Parcelable {
*/
public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.removeCapability(capability);
+ if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
+ mModifiedNotVcnManaged = true;
+ }
return this;
}
@@ -263,6 +310,9 @@ public class NetworkRequest implements Parcelable {
@NonNull
public Builder clearCapabilities() {
mNetworkCapabilities.clearAll();
+ // If the caller explicitly clear all capabilities, the NOT_VCN_MANAGED capabilities
+ // should not be add back later.
+ mModifiedNotVcnManaged = true;
return this;
}
@@ -382,6 +432,25 @@ public class NetworkRequest implements Parcelable {
mNetworkCapabilities.setSignalStrength(signalStrength);
return this;
}
+
+ /**
+ * Deduce the NET_CAPABILITY_NOT_VCN_MANAGED capability from other capabilities
+ * and user intention, which includes:
+ * 1. For the requests that don't have anything besides
+ * {@link #VCN_SUPPORTED_CAPABILITIES}, add the NET_CAPABILITY_NOT_VCN_MANAGED to
+ * allow the callers automatically utilize VCN networks if available.
+ * 2. For the requests that explicitly add or remove NET_CAPABILITY_NOT_VCN_MANAGED,
+ * do not alter them to allow user fire request that suits their need.
+ *
+ * @hide
+ */
+ private void deduceNotVcnManagedCapability(final NetworkCapabilities nc) {
+ if (mModifiedNotVcnManaged) return;
+ for (final int cap : nc.getCapabilities()) {
+ if (!VCN_SUPPORTED_CAPABILITIES.contains(cap)) return;
+ }
+ nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+ }
}
// implement the Parcelable interface
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
index b8030f166436..4c7b898a4fb5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
@@ -259,7 +259,12 @@ public class MobileStatusTracker {
.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode).append(',')
.append("dataState=").append(dataState).append(',')
.append("serviceState=").append(serviceState == null ? ""
- : serviceState.toString()).append(',')
+ : "mVoiceRegState=" + serviceState.getState() + "("
+ + ServiceState.rilServiceStateToString(serviceState.getState())
+ + ")" + ", mDataRegState=" + serviceState.getDataRegState() + "("
+ + ServiceState.rilServiceStateToString(
+ serviceState.getDataRegState()) + ")")
+ .append(',')
.append("signalStrength=").append(signalStrength == null ? ""
: signalStrength.toString()).append(',')
.append("telephonyDisplayInfo=").append(telephonyDisplayInfo == null ? ""
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index ad6a5312f156..66165b6d1ff2 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -147,10 +147,5 @@ public class GlobalSettingsValidators {
VALIDATORS.put(Global.DEVELOPMENT_SETTINGS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.NOTIFICATION_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.RESTRICTED_NETWORKING_MODE, BOOLEAN_VALIDATOR);
- VALIDATORS.put(
- Global.ONE_HANDED_KEYGUARD_SIDE,
- new InclusiveIntegerRangeValidator(
- /* first= */Global.ONE_HANDED_KEYGUARD_SIDE_LEFT,
- /* last= */Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT));
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index c11877a8a963..438cec8ef68f 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -283,7 +283,6 @@ public class SettingsBackupTest {
Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS,
Settings.Global.EUICC_SWITCH_SLOT_TIMEOUT_MILLIS,
Settings.Global.FANCY_IME_ANIMATIONS,
- Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
Settings.Global.FORCED_APP_STANDBY_ENABLED,
Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 9021864a5a86..7bfb42b7cfad 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -76,8 +76,8 @@ android_library {
"androidx.dynamicanimation_dynamicanimation",
"androidx-constraintlayout_constraintlayout",
"androidx.exifinterface_exifinterface",
- "kotlinx-coroutines-android",
- "kotlinx-coroutines-core",
+ "kotlinx_coroutines_android",
+ "kotlinx_coroutines",
"iconloader_base",
"SystemUI-tags",
"SystemUI-proto",
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
index b5f55af50bff..79868093fb12 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer.xml
@@ -24,7 +24,7 @@
<include
style="@style/BouncerSecurityContainer"
layout="@layout/keyguard_host_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
index c75ee51517d1..04e645bd0a32 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_host_view.xml
@@ -41,14 +41,13 @@
android:layout_gravity="center">
<com.android.keyguard.KeyguardSecurityViewFlipper
android:id="@+id/view_flipper"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingTop="@dimen/keyguard_security_view_top_margin"
android:paddingStart="@dimen/keyguard_security_view_lateral_margin"
android:paddingEnd="@dimen/keyguard_security_view_lateral_margin"
- android:layout_gravity="center"
android:gravity="center">
</com.android.keyguard.KeyguardSecurityViewFlipper>
</com.android.keyguard.KeyguardSecurityContainer>
diff --git a/packages/SystemUI/res-keyguard/values/config.xml b/packages/SystemUI/res-keyguard/values/config.xml
index 6176f7c1dd0a..8d9d6ee68c67 100644
--- a/packages/SystemUI/res-keyguard/values/config.xml
+++ b/packages/SystemUI/res-keyguard/values/config.xml
@@ -22,5 +22,4 @@
<!-- Allow the menu hard key to be disabled in LockScreen on some devices [DO NOT TRANSLATE] -->
<bool name="config_disableMenuKeyInLockScreen">false</bool>
- <bool name="can_use_one_handed_bouncer">false</bool>
</resources>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 862076b650b9..187ae58c2f2c 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -43,14 +43,17 @@
android:accessibilityLiveRegion="polite"/>
<com.android.systemui.statusbar.phone.KeyguardIndicationTextView
- android:id="@+id/keyguard_indication_enterprise_disclosure"
- android:layout_width="match_parent"
+ android:id="@+id/keyguard_indication_text_bottom"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
+ android:minHeight="48dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_centerHorizontal="true"
android:paddingStart="@dimen/keyguard_indication_text_padding"
android:paddingEnd="@dimen/keyguard_indication_text_padding"
android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
- android:alpha=".54"
+ android:alpha=".8"
android:visibility="gone"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index afa98b56a13c..5bb46a83f259 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -199,6 +199,9 @@
<!-- The amount the content shifts upwards when transforming into the shelf -->
<dimen name="shelf_transform_content_shift">32dp</dimen>
+ <!-- The y translation for keyguard indication text animation for rotating text in/out -->
+ <dimen name="keyguard_indication_y_translation">24dp</dimen>
+
<!-- The padding on the bottom of the notifications on the keyguard -->
<dimen name="keyguard_indication_bottom_padding">12sp</dimen>
@@ -1157,7 +1160,7 @@
<dimen name="logout_button_layout_height">32dp</dimen>
<dimen name="logout_button_padding_horizontal">16dp</dimen>
<dimen name="logout_button_margin_bottom">12dp</dimen>
- <dimen name="logout_button_corner_radius">2dp</dimen>
+ <dimen name="logout_button_corner_radius">4dp</dimen>
<!-- Blur radius on status bar window and power menu -->
<dimen name="min_window_blur_radius">1px</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 01e54ff60582..ded8a2e66aea 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -34,6 +34,9 @@
<bool name="flag_brightness_slider">false</bool>
+ <!-- The new animations to/from lockscreen and AOD! -->
+ <bool name="flag_lockscreen_animations">false</bool>
+
<!-- People Tile flag -->
<bool name="flag_conversations">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d93239531038..abcf4e802ab9 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -954,11 +954,8 @@
<string name="quick_settings_dark_mode_secondary_label_on_at">On at <xliff:g id="time" example="10 pm">%s</xliff:g></string>
<!-- QuickSettings: Secondary text for when the Dark theme or some other tile will be on until some user-selected time. [CHAR LIMIT=20] -->
<string name="quick_settings_dark_mode_secondary_label_until">Until <xliff:g id="time" example="7 am">%s</xliff:g></string>
- <!-- TODO(b/170970602): remove translatable=false when RBC has official name and strings -->
- <!-- QuickSettings: Label for the toggle that controls whether Reduce Bright Colors is enabled. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_reduce_bright_colors_label" translatable="false">Reduce Bright Colors</string>
- <!-- QuickSettings: Secondary text for intensity level of Reduce Bright Colors. [CHAR LIMIT=NONE] -->
- <string name="quick_settings_reduce_bright_colors_secondary_label" translatable="false"> <xliff:g id="intensity" example="50">%d</xliff:g>%% reduction</string>
+ <!-- QuickSettings: Label for the toggle that controls whether Reduce Brightness is enabled. [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_reduce_bright_colors_label">Reduce Brightness</string>
<!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
<string name="quick_settings_nfc_label">NFC</string>
@@ -2256,6 +2253,12 @@
<!-- Accessibility description indicating the currently selected tile's position. Only used for tiles that are currently in use [CHAR LIMIT=NONE] -->
<string name="accessibility_qs_edit_position">Position <xliff:g id="position" example="5">%1$d</xliff:g></string>
+ <!-- Accessibility announcement after a tile has been added [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_tile_added">Tile added</string>
+
+ <!-- Accessibility announcement after a tile has been added [CHAR LIMIT=NONE] -->
+ <string name="accessibility_qs_edit_tile_removed">Tile removed</string>
+
<!-- Accessibility label for window when QS editing is happening [CHAR LIMIT=NONE] -->
<string name="accessibility_desc_quick_settings_edit">Quick settings editor.</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
index 19e7d7ea4e6e..bec9220028b1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
@@ -17,7 +17,6 @@
package com.android.systemui.shared.system;
import android.annotation.IntDef;
-import android.annotation.NonNull;
import android.view.View;
import com.android.internal.jank.InteractionJankMonitor;
@@ -37,6 +36,10 @@ public final class InteractionJankMonitorWrapper {
InteractionJankMonitor.CUJ_LAUNCHER_APP_CLOSE_TO_PIP;
public static final int CUJ_QUICK_SWITCH =
InteractionJankMonitor.CUJ_LAUNCHER_QUICK_SWITCH;
+ public static final int CUJ_OPEN_ALL_APPS =
+ InteractionJankMonitor.CUJ_LAUNCHER_OPEN_ALL_APPS;
+ public static final int CUJ_ALL_APPS_SCROLL =
+ InteractionJankMonitor.CUJ_LAUNCHER_ALL_APPS_SCROLL;
@IntDef({
CUJ_APP_LAUNCH_FROM_RECENTS,
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index 70021b6f3d45..fbabaa489d74 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -114,10 +114,13 @@ public class SyncRtSurfaceTransactionApplierCompat {
for (int i = params.length - 1; i >= 0; i--) {
SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams =
params[i];
- t.deferTransactionUntil(surfaceParams.surface, mBarrierSurfaceControl, frame);
surfaceParams.applyTo(t);
}
- t.apply();
+ if (mTargetViewRootImpl != null) {
+ mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
+ } else {
+ t.apply();
+ }
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
.sendToTarget();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
index 4a28d56a41e1..89c60f1d3f06 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -56,4 +56,12 @@ public class ViewRootImplCompat {
});
}
}
+
+ public void mergeWithNextTransaction(SurfaceControl.Transaction t, long frame) {
+ if (mViewRoot != null) {
+ mViewRoot.mergeWithNextTransaction(t, frame);
+ } else {
+ t.apply();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index c182fd178202..5f6fd30ffa1b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -29,17 +29,12 @@ import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.provider.Settings;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.util.TypedValue;
-import android.view.Gravity;
import android.view.MotionEvent;
-import android.view.OrientationEventListener;
import android.view.VelocityTracker;
-import android.view.View;
import android.view.ViewConfiguration;
-import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimationControlListener;
@@ -60,7 +55,6 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import java.util.List;
@@ -105,12 +99,6 @@ public class KeyguardSecurityContainer extends FrameLayout {
private boolean mDisappearAnimRunning;
private SwipeListener mSwipeListener;
- private boolean mIsSecurityViewLeftAligned = true;
- private boolean mOneHandedMode = false;
- private SecurityMode mSecurityMode = SecurityMode.Invalid;
- private ViewPropertyAnimator mRunningOneHandedAnimator;
- private final OrientationEventListener mOrientationEventListener;
-
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -169,20 +157,16 @@ public class KeyguardSecurityContainer extends FrameLayout {
// Used to notify the container when something interesting happens.
public interface SecurityCallback {
boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen);
-
void userActivity();
-
void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
/**
- * @param strongAuth wheher the user has authenticated with strong authentication like
- * pattern, password or PIN but not by trust agents or fingerprint
+ * @param strongAuth wheher the user has authenticated with strong authentication like
+ * pattern, password or PIN but not by trust agents or fingerprint
* @param targetUserId a user that needs to be the foreground user at the finish completion.
*/
void finish(boolean strongAuth, int targetUserId);
-
void reset();
-
void onCancelClicked();
}
@@ -240,136 +224,12 @@ public class KeyguardSecurityContainer extends FrameLayout {
super(context, attrs, defStyle);
mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
mViewConfiguration = ViewConfiguration.get(context);
-
- mOrientationEventListener = new OrientationEventListener(context) {
- @Override
- public void onOrientationChanged(int orientation) {
- updateLayoutForSecurityMode(mSecurityMode);
- }
- };
}
void onResume(SecurityMode securityMode, boolean faceAuthEnabled) {
- mSecurityMode = securityMode;
mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
updateBiometricRetry(securityMode, faceAuthEnabled);
- updateLayoutForSecurityMode(securityMode);
- mOrientationEventListener.enable();
- }
-
- void updateLayoutForSecurityMode(SecurityMode securityMode) {
- mSecurityMode = securityMode;
- mOneHandedMode = canUseOneHandedBouncer();
-
- if (mOneHandedMode) {
- mIsSecurityViewLeftAligned = isOneHandedKeyguardLeftAligned(mContext);
- }
-
- updateSecurityViewGravity();
- updateSecurityViewLocation(false);
- }
-
- /** Return whether the one-handed keyguard should be enabled. */
- private boolean canUseOneHandedBouncer() {
- // Is it enabled?
- if (!getResources().getBoolean(
- com.android.internal.R.bool.config_enableOneHandedKeyguard)) {
- return false;
- }
-
- if (!KeyguardSecurityModel.isSecurityViewOneHanded(mSecurityMode)) {
- return false;
- }
-
- return getResources().getBoolean(R.bool.can_use_one_handed_bouncer);
- }
-
- /** Read whether the one-handed keyguard should be on the left/right from settings. */
- private boolean isOneHandedKeyguardLeftAligned(Context context) {
- try {
- return Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.ONE_HANDED_KEYGUARD_SIDE)
- == Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT;
- } catch (Settings.SettingNotFoundException ex) {
- return true;
- }
- }
-
- private void updateSecurityViewGravity() {
- View securityView = findKeyguardSecurityView();
-
- if (securityView == null) {
- return;
- }
-
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) securityView.getLayoutParams();
-
- if (mOneHandedMode) {
- lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
- } else {
- lp.gravity = Gravity.CENTER;
- }
-
- securityView.setLayoutParams(lp);
- }
-
- /**
- * Moves the inner security view to the correct location (in one handed mode) with animation.
- * This is triggered when the user taps on the side of the screen that is not currently occupied
- * by the security view .
- */
- private void updateSecurityViewLocation(boolean animate) {
- View securityView = findKeyguardSecurityView();
-
- if (securityView == null) {
- return;
- }
-
- if (!mOneHandedMode) {
- securityView.setTranslationX(0);
- return;
- }
-
- if (mRunningOneHandedAnimator != null) {
- mRunningOneHandedAnimator.cancel();
- mRunningOneHandedAnimator = null;
- }
-
- int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f);
-
- if (animate) {
- mRunningOneHandedAnimator = securityView.animate().translationX(targetTranslation);
- mRunningOneHandedAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mRunningOneHandedAnimator.setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mRunningOneHandedAnimator = null;
- }
- });
-
- mRunningOneHandedAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- mRunningOneHandedAnimator.start();
- } else {
- securityView.setTranslationX(targetTranslation);
- }
- }
-
- @Nullable
- private KeyguardSecurityViewFlipper findKeyguardSecurityView() {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
-
- if (isKeyguardSecurityView(child)) {
- return (KeyguardSecurityViewFlipper) child;
- }
- }
-
- return null;
- }
-
- private boolean isKeyguardSecurityView(View view) {
- return view instanceof KeyguardSecurityViewFlipper;
}
public void onPause() {
@@ -378,7 +238,6 @@ public class KeyguardSecurityContainer extends FrameLayout {
mAlertDialog = null;
}
mSecurityViewFlipper.setWindowInsetsAnimationCallback(null);
- mOrientationEventListener.disable();
}
@Override
@@ -460,44 +319,19 @@ public class KeyguardSecurityContainer extends FrameLayout {
if (mSwipeListener != null) {
mSwipeListener.onSwipeUp();
}
- } else {
- if (!mIsDragging) {
- handleTap(event);
- }
}
}
return true;
}
- private void handleTap(MotionEvent event) {
- // If we're using a fullscreen security mode, skip
- if (!mOneHandedMode) {
- return;
- }
-
- // Did the tap hit the "other" side of the bouncer?
- if ((mIsSecurityViewLeftAligned && (event.getX() > getWidth() / 2f))
- || (!mIsSecurityViewLeftAligned && (event.getX() < getWidth() / 2f))) {
- mIsSecurityViewLeftAligned = !mIsSecurityViewLeftAligned;
-
- Settings.Global.putInt(
- mContext.getContentResolver(),
- Settings.Global.ONE_HANDED_KEYGUARD_SIDE,
- mIsSecurityViewLeftAligned ? Settings.Global.ONE_HANDED_KEYGUARD_SIDE_LEFT
- : Settings.Global.ONE_HANDED_KEYGUARD_SIDE_RIGHT);
-
- updateSecurityViewLocation(true);
- }
- }
-
void setSwipeListener(SwipeListener swipeListener) {
mSwipeListener = swipeListener;
}
private void startSpringAnimation(float startVelocity) {
mSpringAnimation
- .setStartVelocity(startVelocity)
- .animateToFinalPosition(0);
+ .setStartVelocity(startVelocity)
+ .animateToFinalPosition(0);
}
public void startDisappearAnimation(SecurityMode securitySelection) {
@@ -607,17 +441,18 @@ public class KeyguardSecurityContainer extends FrameLayout {
return insets.inset(0, 0, 0, inset);
}
+
private void showDialog(String title, String message) {
if (mAlertDialog != null) {
mAlertDialog.dismiss();
}
mAlertDialog = new AlertDialog.Builder(mContext)
- .setTitle(title)
- .setMessage(message)
- .setCancelable(false)
- .setNeutralButton(R.string.ok, null)
- .create();
+ .setTitle(title)
+ .setMessage(message)
+ .setCancelable(false)
+ .setNeutralButton(R.string.ok, null)
+ .create();
if (!(mContext instanceof Activity)) {
mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
}
@@ -655,44 +490,6 @@ public class KeyguardSecurityContainer extends FrameLayout {
}
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int maxHeight = 0;
- int maxWidth = 0;
- int childState = 0;
-
- int halfWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
- MeasureSpec.getSize(widthMeasureSpec) / 2,
- MeasureSpec.getMode(widthMeasureSpec));
-
- for (int i = 0; i < getChildCount(); i++) {
- final View view = getChildAt(i);
- if (view.getVisibility() != GONE) {
- if (mOneHandedMode && isKeyguardSecurityView(view)) {
- measureChildWithMargins(view, halfWidthMeasureSpec, 0,
- heightMeasureSpec, 0);
- } else {
- measureChildWithMargins(view, widthMeasureSpec, 0,
- heightMeasureSpec, 0);
- }
- final LayoutParams lp = (LayoutParams) view.getLayoutParams();
- maxWidth = Math.max(maxWidth,
- view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
- maxHeight = Math.max(maxHeight,
- view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
- childState = combineMeasuredStates(childState, view.getMeasuredState());
- }
- }
-
- // Check against our minimum height and width
- maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
- maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
-
- setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
- resolveSizeAndState(maxHeight, heightMeasureSpec,
- childState << MEASURED_HEIGHT_STATE_SHIFT));
- }
-
void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
String message = null;
switch (userType) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index fdab8db67431..1a8d420fb394 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -404,7 +404,6 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
if (newView != null) {
newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
mSecurityViewFlipperController.show(newView);
- mView.updateLayoutForSecurityMode(securityMode);
}
mSecurityCallback.onSecurityModeChanged(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index 631c24844417..c77c86711abf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -92,13 +92,4 @@ public class KeyguardSecurityModel {
throw new IllegalStateException("Unknown security quality:" + security);
}
}
-
- /**
- * Returns whether the given security view should be used in a "one handed" way. This can be
- * used to change how the security view is drawn (e.g. take up less of the screen, and align to
- * one side).
- */
- public static boolean isSecurityViewOneHanded(SecurityMode securityMode) {
- return securityMode == SecurityMode.Pattern || securityMode == SecurityMode.PIN;
- }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 97aa26fb7f68..fea152abe36a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -56,8 +56,10 @@ public class KeyguardStatusView extends GridLayout {
private final IActivityManager mIActivityManager;
private TextView mLogoutView;
+ private boolean mCanShowLogout = true; // by default, try to show the logout button here
private KeyguardClockSwitch mClockView;
private TextView mOwnerInfo;
+ private boolean mCanShowOwnerInfo = true; // by default, try to show the owner information here
private KeyguardSliceView mKeyguardSlice;
private View mNotificationIcons;
private Runnable mPendingMarqueeStart;
@@ -114,6 +116,25 @@ public class KeyguardStatusView extends GridLayout {
if (mOwnerInfo != null) mOwnerInfo.setSelected(enabled);
}
+ void setCanShowOwnerInfo(boolean canShowOwnerInfo) {
+ mCanShowOwnerInfo = canShowOwnerInfo;
+ mOwnerInfo = findViewById(R.id.owner_info);
+ if (mOwnerInfo != null) {
+ if (mCanShowOwnerInfo) {
+ mOwnerInfo.setVisibility(VISIBLE);
+ updateOwnerInfo();
+ } else {
+ mOwnerInfo.setVisibility(GONE);
+ mOwnerInfo = null;
+ }
+ }
+ }
+
+ void setCanShowLogout(boolean canShowLogout) {
+ mCanShowLogout = canShowLogout;
+ updateLogoutView();
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -128,7 +149,10 @@ public class KeyguardStatusView extends GridLayout {
if (KeyguardClockAccessibilityDelegate.isNeeded(mContext)) {
mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
}
- mOwnerInfo = findViewById(R.id.owner_info);
+ if (mCanShowOwnerInfo) {
+ mOwnerInfo = findViewById(R.id.owner_info);
+ }
+
mKeyguardSlice = findViewById(R.id.keyguard_status_area);
mTextColor = mClockView.getCurrentTextColor();
@@ -189,7 +213,7 @@ public class KeyguardStatusView extends GridLayout {
if (mLogoutView == null) {
return;
}
- mLogoutView.setVisibility(shouldShowLogout() ? VISIBLE : GONE);
+ mLogoutView.setVisibility(mCanShowLogout && shouldShowLogout() ? VISIBLE : GONE);
// Logout button will stay in language of user 0 if we don't set that manually.
mLogoutView.setText(mContext.getResources().getString(
com.android.internal.R.string.global_action_logout));
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 973b49384c09..a5f364d30d7d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -134,7 +134,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
/**
- * Get the height of the logout button.
+ * Get the height of the owner information view.
*/
public int getOwnerInfoHeight() {
return mView.getOwnerInfoHeight();
@@ -335,9 +335,13 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
// of the top of the view
mKeyguardSliceViewController.updateTopMargin(
mKeyguardClockSwitchController.getClockTextTopPadding());
+ mView.setCanShowOwnerInfo(false);
+ mView.setCanShowLogout(false);
} else {
// reset margin
mKeyguardSliceViewController.updateTopMargin(0);
+ mView.setCanShowOwnerInfo(true);
+ mView.setCanShowLogout(false);
}
updateAodIcons();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 062410abb689..ffb8446f3e21 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -33,7 +33,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
-import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.transition.RemoteTransitions;
import java.util.Optional;
@@ -86,7 +86,7 @@ public interface SysUIComponent {
Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump);
@BindsInstance
- Builder setTransitions(Transitions t);
+ Builder setTransitions(RemoteTransitions t);
SysUIComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 60b665f0a51a..84dd25963a15 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -27,7 +27,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
-import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.transition.RemoteTransitions;
import java.util.Optional;
@@ -55,16 +55,12 @@ public interface WMComponent {
getShellInit().init();
}
- // Gets the Shell init instance
@WMSingleton
ShellInit getShellInit();
- // Gets the Shell dump instance
@WMSingleton
Optional<ShellCommandHandler> getShellCommandHandler();
- // TODO(b/162923491): We currently pass the instances through to SysUI, but that may change
- // depending on the threading mechanism we go with
@WMSingleton
Optional<OneHanded> getOneHanded();
@@ -89,7 +85,6 @@ public interface WMComponent {
@WMSingleton
Optional<TaskViewFactory> getTaskViewFactory();
- /** Gets transitions */
@WMSingleton
- Transitions getTransitions();
+ RemoteTransitions getTransitions();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java
new file mode 100644
index 000000000000..3a06f7aeb6bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+/**
+ * Data class containing display information (message, icon, styling) for indication to show at
+ * the bottom of the keyguard.
+ *
+ * See {@link com.android.systemui.statusbar.phone.KeyguardBottomAreaView}.
+ */
+public class KeyguardIndication {
+ @NonNull
+ private final CharSequence mMessage;
+ @NonNull
+ private final ColorStateList mTextColor;
+ @Nullable
+ private final Drawable mIcon;
+ @Nullable
+ private final View.OnClickListener mOnClickListener;
+ @Nullable
+ private final Drawable mBackground;
+
+ private KeyguardIndication(
+ CharSequence message,
+ ColorStateList textColor,
+ Drawable icon,
+ View.OnClickListener onClickListener,
+ Drawable background) {
+ mMessage = message;
+ mTextColor = textColor;
+ mIcon = icon;
+ mOnClickListener = onClickListener;
+ mBackground = background;
+ }
+
+ /**
+ * Message to display
+ */
+ public @NonNull CharSequence getMessage() {
+ return mMessage;
+ }
+
+ /**
+ * TextColor to display the message.
+ */
+ public @NonNull ColorStateList getTextColor() {
+ return mTextColor;
+ }
+
+ /**
+ * Icon to display.
+ */
+ public @Nullable Drawable getIcon() {
+ return mIcon;
+ }
+
+ /**
+ * Click listener for messsage.
+ */
+ public @Nullable View.OnClickListener getClickListener() {
+ return mOnClickListener;
+ }
+
+ /**
+ * Background for textView.
+ */
+ public @Nullable Drawable getBackground() {
+ return mBackground;
+ }
+
+ /**
+ * KeyguardIndication Builder
+ */
+ public static class Builder {
+ private CharSequence mMessage;
+ private Drawable mIcon;
+ private View.OnClickListener mOnClickListener;
+ private ColorStateList mTextColor;
+ private Drawable mBackground;
+
+ public Builder() { }
+
+ /**
+ * Required field. Message to display.
+ */
+ public Builder setMessage(@NonNull CharSequence message) {
+ this.mMessage = message;
+ return this;
+ }
+
+ /**
+ * Required field. Text color to use to display the message.
+ */
+ public Builder setTextColor(@NonNull ColorStateList textColor) {
+ this.mTextColor = textColor;
+ return this;
+ }
+
+ /**
+ * Optional. Icon to show next to the text. Icon location changes based on language
+ * display direction. For LTR, icon shows to the left of the message. For RTL, icon shows
+ * to the right of the message.
+ */
+ public Builder setIcon(Drawable icon) {
+ this.mIcon = icon;
+ return this;
+ }
+
+ /**
+ * Optional. Set a click listener on the message.
+ */
+ public Builder setClickListener(View.OnClickListener onClickListener) {
+ this.mOnClickListener = onClickListener;
+ return this;
+ }
+
+ /**
+ * Optional. Set a custom background on the TextView.
+ */
+ public Builder setBackground(Drawable background) {
+ this.mBackground = background;
+ return this;
+ }
+
+ /**
+ * Build the KeyguardIndication.
+ */
+ public KeyguardIndication build() {
+ if (mMessage == null) throw new IllegalStateException("message must be set");
+ if (mTextColor == null) throw new IllegalStateException("text color must be set");
+ return new KeyguardIndication(
+ mMessage, mTextColor, mIcon, mOnClickListener, mBackground);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
new file mode 100644
index 000000000000..d0070d8d9ae9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard;
+
+import android.annotation.Nullable;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.text.TextUtils;
+import android.view.View;
+
+import androidx.annotation.IntDef;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
+import com.android.systemui.util.ViewController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Rotates through messages to show on the keyguard bottom area on the lock screen
+ * NOTE: This controller should not be used on AoD to avoid waking up the AP too often.
+ */
+public class KeyguardIndicationRotateTextViewController extends
+ ViewController<KeyguardIndicationTextView> implements Dumpable {
+ public static String TAG = "KgIndicationRotatingCtrl";
+ private static final long DEFAULT_INDICATION_SHOW_LENGTH = 3500; // milliseconds
+
+ private final StatusBarStateController mStatusBarStateController;
+ private final float mMaxAlpha;
+ private final ColorStateList mInitialTextColorState;
+
+ // Stores @IndicationType => KeyguardIndication messages
+ private final Map<Integer, KeyguardIndication> mIndicationMessages = new HashMap<>();
+
+ // Executor that will show the next message after a delay
+ private final DelayableExecutor mExecutor;
+ @Nullable private ShowNextIndication mShowNextIndicationRunnable;
+
+ // List of indication types to show. The next indication to show is always at index 0
+ private final List<Integer> mIndicationQueue = new LinkedList<>();
+ private @IndicationType int mCurrIndicationType = INDICATION_TYPE_NONE;
+
+ private boolean mIsDozing;
+
+ public KeyguardIndicationRotateTextViewController(
+ KeyguardIndicationTextView view,
+ @Main DelayableExecutor executor,
+ StatusBarStateController statusBarStateController,
+ int lockScreenMode
+ ) {
+ super(view);
+ mMaxAlpha = view.getAlpha();
+ mExecutor = executor;
+ mInitialTextColorState = mView != null
+ ? mView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
+ mStatusBarStateController = statusBarStateController;
+ mView.setLockScreenMode(lockScreenMode);
+ init();
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ cancelScheduledIndication();
+ }
+
+ /**
+ * Update the indication type with the given String.
+ * @param type of indication
+ * @param newIndication message to associate with this indication type
+ * @param showImmediately if true: shows this indication message immediately. Else, the text
+ * associated with this type is updated and will show when its turn in
+ * the IndicationQueue comes around.
+ */
+ public void updateIndication(@IndicationType int type, KeyguardIndication newIndication,
+ boolean showImmediately) {
+ final boolean hasPreviousIndication = mIndicationMessages.get(type) != null;
+ final boolean hasNewIndication = newIndication != null
+ && !TextUtils.isEmpty(newIndication.getMessage());
+ if (!hasNewIndication) {
+ mIndicationMessages.remove(type);
+ mIndicationQueue.removeIf(x -> x == type);
+ } else {
+ if (!hasPreviousIndication) {
+ mIndicationQueue.add(type);
+ }
+
+ mIndicationMessages.put(type, newIndication);
+ }
+
+ if (mIsDozing) {
+ return;
+ }
+
+ final boolean showNow = showImmediately
+ || mCurrIndicationType == INDICATION_TYPE_NONE
+ || mCurrIndicationType == type;
+ if (hasNewIndication) {
+ if (showNow) {
+ showIndication(type);
+ } else if (!isNextIndicationScheduled()) {
+ scheduleShowNextIndication();
+ }
+ return;
+ }
+
+ if (mCurrIndicationType == type
+ && !hasNewIndication
+ && showImmediately) {
+ if (mShowNextIndicationRunnable != null) {
+ mShowNextIndicationRunnable.runImmediately();
+ } else {
+ showIndication(INDICATION_TYPE_NONE);
+ }
+ }
+ }
+
+ /**
+ * Stop showing the following indication type.
+ *
+ * If the current indication is of this type, immediately stops showing the message.
+ */
+ public void hideIndication(@IndicationType int type) {
+ updateIndication(type, null, true);
+ }
+
+ /**
+ * Show a transient message.
+ * Transient messages:
+ * - show immediately
+ * - will continue to be in the rotation of messages shown until hideTransient is called.
+ * - can be presented with an "error" color if isError is true
+ */
+ public void showTransient(CharSequence newIndication, boolean isError) {
+ updateIndication(INDICATION_TYPE_TRANSIENT,
+ new KeyguardIndication.Builder()
+ .setMessage(newIndication)
+ .setTextColor(isError
+ ? Utils.getColorError(getContext())
+ : mInitialTextColorState)
+ .build(),
+ /* showImmediately */true);
+ }
+
+ /**
+ * Hide a transient message immediately.
+ */
+ public void hideTransient() {
+ hideIndication(INDICATION_TYPE_TRANSIENT);
+ }
+
+ /**
+ * @return true if there are available indications to show
+ */
+ public boolean hasIndications() {
+ return mIndicationMessages.keySet().size() > 0;
+ }
+
+ /**
+ * Immediately show the passed indication type and schedule the next indication to show.
+ * Will re-add this indication to be re-shown after all other indications have been
+ * rotated through.
+ */
+ private void showIndication(@IndicationType int type) {
+ cancelScheduledIndication();
+
+ mCurrIndicationType = type;
+ mIndicationQueue.removeIf(x -> x == type);
+ if (mCurrIndicationType == INDICATION_TYPE_NONE) {
+ mView.setVisibility(View.GONE);
+ } else {
+ mView.setVisibility(View.VISIBLE);
+ mIndicationQueue.add(type); // re-add to show later
+ }
+
+ // pass the style update to be run right before our new indication is shown:
+ mView.switchIndication(mIndicationMessages.get(type));
+
+ // only schedule next indication if there's more than just this indication in the queue
+ if (mCurrIndicationType != INDICATION_TYPE_NONE && mIndicationQueue.size() > 1) {
+ scheduleShowNextIndication();
+ }
+ }
+
+ protected boolean isNextIndicationScheduled() {
+ return mShowNextIndicationRunnable != null;
+ }
+
+ private void scheduleShowNextIndication() {
+ cancelScheduledIndication();
+ mShowNextIndicationRunnable = new ShowNextIndication(DEFAULT_INDICATION_SHOW_LENGTH);
+ }
+
+ private void cancelScheduledIndication() {
+ if (mShowNextIndicationRunnable != null) {
+ mShowNextIndicationRunnable.cancelDelayedExecution();
+ mShowNextIndicationRunnable = null;
+ }
+ }
+
+ private StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onDozeAmountChanged(float linear, float eased) {
+ mView.setAlpha((1 - linear) * mMaxAlpha);
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ if (isDozing == mIsDozing) return;
+ mIsDozing = isDozing;
+ if (mIsDozing) {
+ showIndication(INDICATION_TYPE_NONE);
+ } else if (mIndicationQueue.size() > 0) {
+ showIndication(mIndicationQueue.remove(0));
+ }
+ }
+ };
+
+ /**
+ * Shows the next indication in the IndicationQueue after an optional delay.
+ * This wrapper has the ability to cancel itself (remove runnable from DelayableExecutor) or
+ * immediately run itself (which also removes itself from the DelayableExecutor).
+ */
+ class ShowNextIndication {
+ private final Runnable mShowIndicationRunnable;
+ private Runnable mCancelDelayedRunnable;
+
+ ShowNextIndication(long delay) {
+ mShowIndicationRunnable = () -> {
+ int type = mIndicationQueue.size() == 0
+ ? INDICATION_TYPE_NONE : mIndicationQueue.remove(0);
+ showIndication(type);
+ };
+ mCancelDelayedRunnable = mExecutor.executeDelayed(mShowIndicationRunnable, delay);
+ }
+
+ public void runImmediately() {
+ cancelDelayedExecution();
+ mShowIndicationRunnable.run();
+ }
+
+ public void cancelDelayedExecution() {
+ if (mCancelDelayedRunnable != null) {
+ mCancelDelayedRunnable.run();
+ mCancelDelayedRunnable = null;
+ }
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("KeyguardIndicationRotatingTextViewController:");
+ pw.println(" currentMessage=" + mView.getText());
+ pw.println(" dozing:" + mIsDozing);
+ pw.println(" queue:" + mIndicationQueue.toString());
+ pw.println(" showNextIndicationRunnable:" + mShowNextIndicationRunnable);
+
+ if (hasIndications()) {
+ pw.println(" All messages:");
+ for (int type : mIndicationMessages.keySet()) {
+ pw.println(" type=" + type + " message=" + mIndicationMessages.get(type));
+ }
+ }
+ }
+
+ private static final int INDICATION_TYPE_NONE = -1;
+ public static final int INDICATION_TYPE_OWNER_INFO = 0;
+ public static final int INDICATION_TYPE_DISCLOSURE = 1;
+ public static final int INDICATION_TYPE_LOGOUT = 2;
+ public static final int INDICATION_TYPE_BATTERY = 3;
+ public static final int INDICATION_TYPE_ALIGNMENT = 4;
+ public static final int INDICATION_TYPE_TRANSIENT = 5;
+ public static final int INDICATION_TYPE_TRUST = 6;
+ public static final int INDICATION_TYPE_RESTING = 7;
+ public static final int INDICATION_TYPE_USER_LOCKED = 8;
+ public static final int INDICATION_TYPE_NOW_PLAYING = 9;
+ public static final int INDICATION_TYPE_REVERSE_CHARGING = 10;
+
+ @IntDef({
+ INDICATION_TYPE_NONE,
+ INDICATION_TYPE_DISCLOSURE,
+ INDICATION_TYPE_OWNER_INFO,
+ INDICATION_TYPE_LOGOUT,
+ INDICATION_TYPE_BATTERY,
+ INDICATION_TYPE_ALIGNMENT,
+ INDICATION_TYPE_TRANSIENT,
+ INDICATION_TYPE_TRUST,
+ INDICATION_TYPE_RESTING,
+ INDICATION_TYPE_USER_LOCKED,
+ INDICATION_TYPE_NOW_PLAYING,
+ INDICATION_TYPE_REVERSE_CHARGING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IndicationType{}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 507048c62186..21464fd37c6c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -441,15 +441,17 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
return position > mEditIndex;
}
- private void addFromPosition(int position) {
- if (!canAddFromPosition(position)) return;
+ private boolean addFromPosition(int position) {
+ if (!canAddFromPosition(position)) return false;
move(position, mEditIndex);
+ return true;
}
- private void removeFromPosition(int position) {
- if (!canRemoveFromPosition(position)) return;
+ private boolean removeFromPosition(int position) {
+ if (!canRemoveFromPosition(position)) return false;
TileInfo info = mTiles.get(position);
move(position, info.isSystem ? mEditIndex : mTileDividerIndex);
+ return true;
}
public SpanSizeLookup getSizeLookup() {
@@ -578,11 +580,17 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
}
private void add() {
- addFromPosition(getLayoutPosition());
+ if (addFromPosition(getLayoutPosition())) {
+ itemView.announceForAccessibility(
+ itemView.getContext().getText(R.string.accessibility_qs_edit_tile_added));
+ }
}
private void remove() {
- removeFromPosition(getLayoutPosition());
+ if (removeFromPosition(getLayoutPosition())) {
+ itemView.announceForAccessibility(
+ itemView.getContext().getText(R.string.accessibility_qs_edit_tile_removed));
+ }
}
boolean isCurrentTile() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
index 9ab2d7370ed8..35a8257bd5a7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFlagsModule.java
@@ -16,6 +16,9 @@
package com.android.systemui.qs.dagger;
+import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
+
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.FeatureFlags;
@@ -27,6 +30,7 @@ import dagger.Provides;
@Module
public interface QSFlagsModule {
String QS_LABELS_FLAG = "qs_labels_flag";
+ String RBC_AVAILABLE = "rbc_available";
@Provides
@SysUISingleton
@@ -34,4 +38,12 @@ public interface QSFlagsModule {
static boolean provideQSFlag(FeatureFlags featureFlags) {
return featureFlags.isQSLabelsEnabled();
}
+
+ /** */
+ @Provides
+ @SysUISingleton
+ @Named(RBC_AVAILABLE)
+ static boolean isReduceBrightColorsAvailable(Context context) {
+ return ColorDisplayManager.isReduceBrightColorsAvailable(context);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
index 84c7611478cd..f94cabcee297 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -16,12 +16,13 @@
package com.android.systemui.qs.tiles;
+import static com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE;
+
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.service.quicksettings.Tile;
-import android.text.TextUtils;
import android.widget.Switch;
import com.android.internal.logging.MetricsLogger;
@@ -39,6 +40,7 @@ import com.android.systemui.settings.UserTracker;
import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
+import javax.inject.Named;
/** Quick settings tile: Reduce Bright Colors **/
public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> {
@@ -46,9 +48,11 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> {
//TODO(b/170973645): get icon drawable
private final Icon mIcon = null;
private final SecureSetting mActivatedSetting;
+ private final boolean mIsAvailable;
@Inject
public ReduceBrightColorsTile(
+ @Named(RBC_AVAILABLE) boolean isAvailable,
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
@@ -69,11 +73,12 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> {
refreshState();
}
};
+ mIsAvailable = isAvailable;
+
}
@Override
public boolean isAvailable() {
- // TODO(b/170970675): Call into ColorDisplayService to get availability/config status
- return true;
+ return mIsAvailable;
}
@Override
@@ -121,15 +126,6 @@ public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> {
state.label = mContext.getString(R.string.quick_settings_reduce_bright_colors_label);
state.expandedAccessibilityClassName = Switch.class.getName();
state.contentDescription = state.label;
-
- final int intensity = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mActivatedSetting.getCurrentUser());
- state.secondaryLabel = state.value ? mContext.getString(
- R.string.quick_settings_reduce_bright_colors_secondary_label, intensity) : "";
-
- state.contentDescription = TextUtils.isEmpty(state.secondaryLabel)
- ? state.label
- : TextUtils.concat(state.label, ", ", state.secondaryLabel);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a9f76f61c537..01a8c1c89f84 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -101,7 +101,7 @@ import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.splitscreen.SplitScreen;
-import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.transition.RemoteTransitions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -149,7 +149,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final ScreenshotHelper mScreenshotHelper;
private final Optional<OneHanded> mOneHandedOptional;
private final CommandQueue mCommandQueue;
- private final Transitions mShellTransitions;
+ private final RemoteTransitions mShellTransitions;
private Region mActiveNavBarRegion;
@@ -799,7 +799,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
Optional<Lazy<StatusBar>> statusBarOptionalLazy,
Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher,
- Transitions shellTransitions) {
+ RemoteTransitions shellTransitions) {
super(broadcastDispatcher);
mContext = context;
mPipOptional = pipOptional;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index a3b5f27933be..43bb34380f80 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -79,6 +79,7 @@ public class BrightnessController implements ToggleSlider.Listener {
private final float mMaximumBacklightForVr;
private final float mDefaultBacklightForVr;
+ private final int mDisplayId;
private final Context mContext;
private final ToggleSlider mControl;
private final boolean mAutomaticAvailable;
@@ -311,6 +312,7 @@ public class BrightnessController implements ToggleSlider.Listener {
};
mBrightnessObserver = new BrightnessObserver(mHandler);
+ mDisplayId = mContext.getDisplayId();
PowerManager pm = context.getSystemService(PowerManager.class);
mMinimumBacklight = pm.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM);
@@ -420,7 +422,7 @@ public class BrightnessController implements ToggleSlider.Listener {
}
private void setBrightness(float brightness) {
- mDisplayManager.setTemporaryBrightness(brightness);
+ mDisplayManager.setTemporaryBrightness(mDisplayId, brightness);
}
private void updateVrMode(boolean isEnabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index e7b60c3a0d67..2dd85e9bb98d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -67,6 +67,10 @@ public class FeatureFlags {
return mFlagReader.isEnabled(R.bool.flag_brightness_slider);
}
+ public boolean useNewLockscreenAnimations() {
+ return mFlagReader.isEnabled(R.bool.flag_lockscreen_animations);
+ }
+
public boolean isPeopleTileEnabled() {
return mFlagReader.isEnabled(R.bool.flag_conversations);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index c816784a22f2..c70a93b5c894 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -16,10 +16,24 @@
package com.android.systemui.statusbar;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import static com.android.keyguard.KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_LOGOUT;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_RESTING;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_USER_LOCKED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -47,6 +61,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.ViewClippingUtil;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -56,13 +71,16 @@ import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.keyguard.KeyguardIndication;
+import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.LockscreenLockIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.wakelock.SettableWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
@@ -76,8 +94,7 @@ import javax.inject.Inject;
* Controls the indications and error messages shown on the Keyguard
*/
@SysUISingleton
-public class KeyguardIndicationController implements StateListener,
- KeyguardStateController.Callback {
+public class KeyguardIndicationController implements KeyguardStateController.Callback {
private static final String TAG = "KeyguardIndication";
private static final boolean DEBUG_CHARGING_SPEED = false;
@@ -94,14 +111,17 @@ public class KeyguardIndicationController implements StateListener,
private final StatusBarStateController mStatusBarStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private ViewGroup mIndicationArea;
- private KeyguardIndicationTextView mTextView;
- private KeyguardIndicationTextView mDisclosure;
+ private KeyguardIndicationTextView mTopIndicationView;
private final IBatteryStats mBatteryInfo;
private final SettableWakeLock mWakeLock;
private final DockManager mDockManager;
private final DevicePolicyManager mDevicePolicyManager;
private final UserManager mUserManager;
+ private final @Main DelayableExecutor mExecutor;
+ private final LockPatternUtils mLockPatternUtils;
+ private final IActivityManager mIActivityManager;
+ protected KeyguardIndicationRotateTextViewController mRotateTextViewController;
private BroadcastReceiver mBroadcastReceiver;
private LockscreenLockIconController mLockIconController;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -110,7 +130,7 @@ public class KeyguardIndicationController implements StateListener,
private String mAlignmentIndication;
private CharSequence mTransientIndication;
private boolean mTransientTextIsError;
- private ColorStateList mInitialTextColorState;
+ protected ColorStateList mInitialTextColorState;
private boolean mVisible;
private boolean mHideTransientMessageOnScreenOff;
@@ -124,8 +144,8 @@ public class KeyguardIndicationController implements StateListener,
private int mBatteryLevel;
private boolean mBatteryPresent = true;
private long mChargingTimeRemaining;
- private float mDisclosureMaxAlpha;
private String mMessageToShowOnScreenOn;
+ protected int mLockScreenMode;
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -151,7 +171,8 @@ public class KeyguardIndicationController implements StateListener,
BroadcastDispatcher broadcastDispatcher,
DevicePolicyManager devicePolicyManager,
IBatteryStats iBatteryStats,
- UserManager userManager) {
+ UserManager userManager,
+ @Main DelayableExecutor executor) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mDevicePolicyManager = devicePolicyManager;
@@ -165,23 +186,29 @@ public class KeyguardIndicationController implements StateListener,
wakeLockBuilder.setTag("Doze:KeyguardIndication").build(), TAG);
mBatteryInfo = iBatteryStats;
mUserManager = userManager;
+ mExecutor = executor;
+ mLockPatternUtils = new LockPatternUtils(context);
+ mIActivityManager = ActivityManager.getService();
mKeyguardUpdateMonitor.registerCallback(getKeyguardCallback());
mKeyguardUpdateMonitor.registerCallback(mTickReceiver);
- mStatusBarStateController.addCallback(this);
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
mKeyguardStateController.addCallback(this);
}
public void setIndicationArea(ViewGroup indicationArea) {
mIndicationArea = indicationArea;
- mTextView = indicationArea.findViewById(R.id.keyguard_indication_text);
- mInitialTextColorState = mTextView != null ?
- mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
- mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
- mDisclosureMaxAlpha = mDisclosure.getAlpha();
+ mTopIndicationView = indicationArea.findViewById(R.id.keyguard_indication_text);
+ mInitialTextColorState = mTopIndicationView != null
+ ? mTopIndicationView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
+ mRotateTextViewController = new KeyguardIndicationRotateTextViewController(
+ indicationArea.findViewById(R.id.keyguard_indication_text_bottom),
+ mExecutor,
+ mStatusBarStateController,
+ mLockScreenMode);
updateIndication(false /* animate */);
updateDisclosure();
-
+ updateOwnerInfo();
if (mBroadcastReceiver == null) {
// Update the disclosure proactively to avoid IPC on the critical path.
mBroadcastReceiver = new BroadcastReceiver() {
@@ -233,19 +260,196 @@ public class KeyguardIndicationController implements StateListener,
return mUpdateMonitorCallback;
}
+ /**
+ * Doesn't include owner information or disclosure which get triggered separately.
+ */
+ private void updateIndications(boolean animate, int userId) {
+ updateBattery(animate);
+ updateUserLocked(userId);
+ updateTransient();
+ updateTrust(userId, getTrustGrantedIndication(), getTrustManagedIndication());
+ updateAlignment();
+ updateResting();
+ }
+
private void updateDisclosure() {
- // NOTE: Because this uses IPC, avoid calling updateDisclosure() on a critical path.
if (whitelistIpcs(this::isOrganizationOwnedDevice)) {
- CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
- if (organizationName != null) {
- mDisclosure.switchIndication(mContext.getResources().getString(
- R.string.do_disclosure_with_name, organizationName));
- } else {
- mDisclosure.switchIndication(R.string.do_disclosure_generic);
+ final CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
+ final CharSequence disclosure = organizationName != null
+ ? mContext.getResources().getString(R.string.do_disclosure_with_name,
+ organizationName)
+ : mContext.getResources().getText(R.string.do_disclosure_generic);
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE,
+ new KeyguardIndication.Builder()
+ .setMessage(disclosure)
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ /* updateImmediately */ false);
+ } else {
+ mRotateTextViewController.hideIndication(INDICATION_TYPE_DISCLOSURE);
+ }
+
+ if (isKeyguardLayoutEnabled()) {
+ updateIndication(false); // resting indication may need to update
+ }
+ }
+
+ private void updateBattery(boolean animate) {
+ if (mPowerPluggedIn || mEnableBatteryDefender) {
+ String powerIndication = computePowerIndication();
+ if (DEBUG_CHARGING_SPEED) {
+ powerIndication += ", " + (mChargingWattage / 1000) + " mW";
}
- mDisclosure.setVisibility(View.VISIBLE);
+
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_BATTERY,
+ new KeyguardIndication.Builder()
+ .setMessage(powerIndication)
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ animate);
} else {
- mDisclosure.setVisibility(View.GONE);
+ // don't show the charging information if device isn't plugged in
+ mRotateTextViewController.hideIndication(INDICATION_TYPE_BATTERY);
+ }
+ }
+
+ private void updateUserLocked(int userId) {
+ if (!mKeyguardUpdateMonitor.isUserUnlocked(userId)) {
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_USER_LOCKED,
+ new KeyguardIndication.Builder()
+ .setMessage(mContext.getResources().getText(
+ com.android.internal.R.string.lockscreen_storage_locked))
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ false);
+ } else {
+ mRotateTextViewController.hideIndication(INDICATION_TYPE_USER_LOCKED);
+ }
+ }
+
+ private void updateTransient() {
+ if (!TextUtils.isEmpty(mTransientIndication)) {
+ mRotateTextViewController.showTransient(mTransientIndication,
+ mTransientTextIsError);
+ } else {
+ mRotateTextViewController.hideTransient();
+ }
+ }
+
+ private void updateTrust(int userId, CharSequence trustGrantedIndication,
+ CharSequence trustManagedIndication) {
+ if (!TextUtils.isEmpty(trustGrantedIndication)
+ && mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_TRUST,
+ new KeyguardIndication.Builder()
+ .setMessage(trustGrantedIndication)
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ false);
+ } else if (!TextUtils.isEmpty(trustManagedIndication)
+ && mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
+ && !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_TRUST,
+ new KeyguardIndication.Builder()
+ .setMessage(trustManagedIndication)
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ false);
+ } else {
+ mRotateTextViewController.hideIndication(INDICATION_TYPE_TRUST);
+ }
+ }
+
+ private void updateAlignment() {
+ if (!TextUtils.isEmpty(mAlignmentIndication)) {
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_ALIGNMENT,
+ new KeyguardIndication.Builder()
+ .setMessage(mAlignmentIndication)
+ .setTextColor(Utils.getColorError(mContext))
+ .build(),
+ true);
+ } else {
+ mRotateTextViewController.hideIndication(INDICATION_TYPE_ALIGNMENT);
+ }
+ }
+
+ private void updateResting() {
+ if (mRestingIndication != null
+ && !mRotateTextViewController.hasIndications()) {
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_RESTING,
+ new KeyguardIndication.Builder()
+ .setMessage(mRestingIndication)
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ false);
+ } else {
+ mRotateTextViewController.hideIndication(INDICATION_TYPE_RESTING);
+ }
+ }
+
+ protected boolean isKeyguardLayoutEnabled() {
+ return mLockScreenMode == LOCK_SCREEN_MODE_LAYOUT_1;
+ }
+
+ private void updateLogoutView() {
+ if (!isKeyguardLayoutEnabled()) {
+ return;
+ }
+ final boolean shouldShowLogout = mKeyguardUpdateMonitor.isLogoutEnabled()
+ && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM;
+ String logoutString = shouldShowLogout ? mContext.getResources().getString(
+ com.android.internal.R.string.global_action_logout) : null;
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_LOGOUT,
+ new KeyguardIndication.Builder()
+ .setMessage(logoutString)
+ .setTextColor(mInitialTextColorState)
+ .setBackground(mContext.getDrawable(
+ com.android.systemui.R.drawable.logout_button_background))
+ .setClickListener((view) -> {
+ int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
+ try {
+ mIActivityManager.switchUser(UserHandle.USER_SYSTEM);
+ mIActivityManager.stopUser(currentUserId, true /* force */, null);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Failed to logout user", re);
+ }
+ })
+ .build(),
+ false);
+ updateIndication(false); // resting indication may need to update
+ }
+
+ private void updateOwnerInfo() {
+ if (!isKeyguardLayoutEnabled()) {
+ return;
+ }
+ String info = mLockPatternUtils.getDeviceOwnerInfo();
+ if (info == null) {
+ // Use the current user owner information if enabled.
+ final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
+ KeyguardUpdateMonitor.getCurrentUser());
+ if (ownerInfoEnabled) {
+ info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
+ }
+ }
+ if (info != null) {
+ mRotateTextViewController.updateIndication(
+ INDICATION_TYPE_OWNER_INFO,
+ new KeyguardIndication.Builder()
+ .setMessage(info)
+ .setTextColor(mInitialTextColorState)
+ .build(),
+ false);
+ } else {
+ updateIndication(false); // resting indication may need to update
}
}
@@ -281,9 +485,10 @@ public class KeyguardIndicationController implements StateListener,
return UserHandle.USER_NULL;
}
- public void setVisible(boolean visible) {
+ @VisibleForTesting
+ protected void setVisible(boolean visible) {
mVisible = visible;
- mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
+ mIndicationArea.setVisibility(visible ? VISIBLE : GONE);
if (visible) {
// If this is called after an error message was already shown, we should not clear it.
// Otherwise the error message won't be shown
@@ -382,6 +587,7 @@ public class KeyguardIndicationController implements StateListener,
mTransientIndication = null;
mHideTransientMessageOnScreenOff = false;
mHandler.removeMessages(MSG_HIDE_TRANSIENT);
+ mRotateTextViewController.hideTransient();
updateIndication(false);
}
}
@@ -396,98 +602,109 @@ public class KeyguardIndicationController implements StateListener,
}
// A few places might need to hide the indication, so always start by making it visible
- mIndicationArea.setVisibility(View.VISIBLE);
+ mIndicationArea.setVisibility(VISIBLE);
// Walk down a precedence-ordered list of what indication
// should be shown based on user or device state
+ // AoD
if (mDozing) {
+ mTopIndicationView.setVisibility(VISIBLE);
// When dozing we ignore any text color and use white instead, because
// colors can be hard to read in low brightness.
- mTextView.setTextColor(Color.WHITE);
+ mTopIndicationView.setTextColor(Color.WHITE);
if (!TextUtils.isEmpty(mTransientIndication)) {
- mTextView.switchIndication(mTransientIndication);
+ mTopIndicationView.switchIndication(mTransientIndication, null);
} else if (!mBatteryPresent) {
// If there is no battery detected, hide the indication and bail
- mIndicationArea.setVisibility(View.GONE);
+ mIndicationArea.setVisibility(GONE);
} else if (!TextUtils.isEmpty(mAlignmentIndication)) {
- mTextView.switchIndication(mAlignmentIndication);
- mTextView.setTextColor(mContext.getColor(R.color.misalignment_text_color));
+ mTopIndicationView.switchIndication(mAlignmentIndication, null);
+ mTopIndicationView.setTextColor(mContext.getColor(R.color.misalignment_text_color));
} else if (mPowerPluggedIn || mEnableBatteryDefender) {
String indication = computePowerIndication();
if (animate) {
- animateText(mTextView, indication);
+ animateText(mTopIndicationView, indication);
} else {
- mTextView.switchIndication(indication);
+ mTopIndicationView.switchIndication(indication, null);
}
} else {
String percentage = NumberFormat.getPercentInstance()
.format(mBatteryLevel / 100f);
- mTextView.switchIndication(percentage);
+ mTopIndicationView.switchIndication(percentage, null);
}
return;
}
+ // LOCK SCREEN
+ // Some cases here might need to hide the indication (if the battery is not present)
int userId = KeyguardUpdateMonitor.getCurrentUser();
- String trustGrantedIndication = getTrustGrantedIndication();
- String trustManagedIndication = getTrustManagedIndication();
-
- String powerIndication = null;
- if (mPowerPluggedIn || mEnableBatteryDefender) {
- powerIndication = computePowerIndication();
- }
- // Some cases here might need to hide the indication (if the battery is not present)
- boolean hideIndication = false;
- boolean isError = false;
- if (!mKeyguardUpdateMonitor.isUserUnlocked(userId)) {
- mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
- } else if (!TextUtils.isEmpty(mTransientIndication)) {
- if (powerIndication != null && !mTransientIndication.equals(powerIndication)) {
- String indication = mContext.getResources().getString(
- R.string.keyguard_indication_trust_unlocked_plugged_in,
- mTransientIndication, powerIndication);
- mTextView.switchIndication(indication);
- hideIndication = !mBatteryPresent;
- } else {
- mTextView.switchIndication(mTransientIndication);
+ if (mLockScreenMode == LOCK_SCREEN_MODE_LAYOUT_1) {
+ mTopIndicationView.setVisibility(GONE);
+ updateIndications(animate, userId);
+ } else {
+ boolean hideIndication = false;
+ boolean isError = false;
+ String trustGrantedIndication = getTrustGrantedIndication();
+ String trustManagedIndication = getTrustManagedIndication();
+ String powerIndication = null;
+
+ if (mPowerPluggedIn || mEnableBatteryDefender) {
+ powerIndication = computePowerIndication();
}
- isError = mTransientTextIsError;
- } else if (!TextUtils.isEmpty(trustGrantedIndication)
- && mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
- if (powerIndication != null) {
- String indication = mContext.getResources().getString(
- R.string.keyguard_indication_trust_unlocked_plugged_in,
- trustGrantedIndication, powerIndication);
- mTextView.switchIndication(indication);
+ if (!mKeyguardUpdateMonitor.isUserUnlocked(userId)) {
+ mTopIndicationView.switchIndication(
+ com.android.internal.R.string.lockscreen_storage_locked);
+ } else if (!TextUtils.isEmpty(mTransientIndication)) {
+ if (powerIndication != null && !mTransientIndication.equals(powerIndication)) {
+ String indication = mContext.getResources().getString(
+ R.string.keyguard_indication_trust_unlocked_plugged_in,
+ mTransientIndication, powerIndication);
+ mTopIndicationView.switchIndication(indication, null);
+ hideIndication = !mBatteryPresent;
+ } else {
+ mTopIndicationView.switchIndication(mTransientIndication, null);
+ }
+ isError = mTransientTextIsError;
+ } else if (!TextUtils.isEmpty(trustGrantedIndication)
+ && mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
+ if (powerIndication != null) {
+ String indication = mContext.getResources().getString(
+ R.string.keyguard_indication_trust_unlocked_plugged_in,
+ trustGrantedIndication, powerIndication);
+ mTopIndicationView.switchIndication(indication, null);
+ hideIndication = !mBatteryPresent;
+ } else {
+ mTopIndicationView.switchIndication(trustGrantedIndication, null);
+ }
+ } else if (!TextUtils.isEmpty(mAlignmentIndication)) {
+ mTopIndicationView.switchIndication(mAlignmentIndication, null);
+ isError = true;
+ hideIndication = !mBatteryPresent;
+ } else if (mPowerPluggedIn || mEnableBatteryDefender) {
+ if (DEBUG_CHARGING_SPEED) {
+ powerIndication += ", " + (mChargingWattage / 1000) + " mW";
+ }
+ if (animate) {
+ animateText(mTopIndicationView, powerIndication);
+ } else {
+ mTopIndicationView.switchIndication(powerIndication, null);
+ }
hideIndication = !mBatteryPresent;
+ } else if (!TextUtils.isEmpty(trustManagedIndication)
+ && mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
+ && !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
+ mTopIndicationView.switchIndication(trustManagedIndication, null);
} else {
- mTextView.switchIndication(trustGrantedIndication);
- }
- } else if (!TextUtils.isEmpty(mAlignmentIndication)) {
- mTextView.switchIndication(mAlignmentIndication);
- isError = true;
- hideIndication = !mBatteryPresent;
- } else if (mPowerPluggedIn || mEnableBatteryDefender) {
- if (DEBUG_CHARGING_SPEED) {
- powerIndication += ", " + (mChargingWattage / 1000) + " mW";
+ mTopIndicationView.switchIndication(mRestingIndication, null);
}
- if (animate) {
- animateText(mTextView, powerIndication);
- } else {
- mTextView.switchIndication(powerIndication);
+
+ mTopIndicationView.setTextColor(
+ isError ? Utils.getColorError(mContext) : mInitialTextColorState);
+
+ if (hideIndication) {
+ mIndicationArea.setVisibility(GONE);
}
- hideIndication = !mBatteryPresent;
- } else if (!TextUtils.isEmpty(trustManagedIndication)
- && mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
- && !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
- mTextView.switchIndication(trustManagedIndication);
- } else {
- mTextView.switchIndication(mRestingIndication);
- }
- mTextView.setTextColor(isError ? Utils.getColorError(mContext)
- : mInitialTextColorState);
- if (hideIndication) {
- mIndicationArea.setVisibility(View.GONE);
}
}
@@ -510,7 +727,7 @@ public class KeyguardIndicationController implements StateListener,
@Override
public void onAnimationStart(Animator animation) {
- textView.switchIndication(indication);
+ textView.switchIndication(indication, null);
}
@Override
@@ -634,18 +851,6 @@ public class KeyguardIndicationController implements StateListener,
}
}
- public void setDozing(boolean dozing) {
- if (mDozing == dozing) {
- return;
- }
- mDozing = dozing;
- if (mHideTransientMessageOnScreenOff && mDozing) {
- hideTransientIndication();
- } else {
- updateIndication(false);
- }
- }
-
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardIndicationController:");
pw.println(" mTransientTextIsError: " + mTransientTextIsError);
@@ -659,23 +864,10 @@ public class KeyguardIndicationController implements StateListener,
pw.println(" mDozing: " + mDozing);
pw.println(" mBatteryLevel: " + mBatteryLevel);
pw.println(" mBatteryPresent: " + mBatteryPresent);
- pw.println(" mTextView.getText(): " + (mTextView == null ? null : mTextView.getText()));
+ pw.println(" mTextView.getText(): " + (
+ mTopIndicationView == null ? null : mTopIndicationView.getText()));
pw.println(" computePowerIndication(): " + computePowerIndication());
- }
-
- @Override
- public void onStateChanged(int newState) {
- // don't care
- }
-
- @Override
- public void onDozingChanged(boolean isDozing) {
- setDozing(isDozing);
- }
-
- @Override
- public void onDozeAmountChanged(float linear, float eased) {
- mDisclosure.setAlpha((1 - linear) * mDisclosureMaxAlpha);
+ mRotateTextViewController.dump(fd, pw, args);
}
@Override
@@ -687,6 +879,11 @@ public class KeyguardIndicationController implements StateListener,
public static final int HIDE_DELAY_MS = 5000;
@Override
+ public void onLockScreenModeChanged(int mode) {
+ mLockScreenMode = mode;
+ }
+
+ @Override
public void onRefreshBatteryInfo(BatteryStatus status) {
boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
|| status.status == BatteryManager.BATTERY_STATUS_FULL;
@@ -845,6 +1042,7 @@ public class KeyguardIndicationController implements StateListener,
@Override
public void onUserSwitchComplete(int userId) {
if (mVisible) {
+ updateOwnerInfo();
updateIndication(false);
}
}
@@ -857,11 +1055,39 @@ public class KeyguardIndicationController implements StateListener,
}
@Override
+ public void onLogoutEnabledChanged() {
+ if (mVisible) {
+ updateLogoutView();
+ }
+ }
+
+ @Override
public void onRequireUnlockForNfc() {
showTransientIndication(mContext.getString(R.string.require_unlock_for_nfc),
false /* isError */, false /* hideOnScreenOff */);
hideTransientIndicationDelayed(HIDE_DELAY_MS);
}
-
}
+
+ private StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ setVisible(newState == StatusBarState.KEYGUARD);
+ }
+
+ @Override
+ public void onDozingChanged(boolean dozing) {
+ if (mDozing == dozing) {
+ return;
+ }
+ mDozing = dozing;
+
+ if (mHideTransientMessageOnScreenOff && mDozing) {
+ hideTransientIndication();
+ } else {
+ updateIndication(false);
+ }
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 2f0f90d318eb..c1feacaba440 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -11,14 +11,10 @@ import android.graphics.PorterDuffColorFilter
import android.graphics.PorterDuffXfermode
import android.graphics.RadialGradient
import android.graphics.Shader
-import android.os.SystemProperties
import android.util.AttributeSet
import android.view.View
import com.android.systemui.Interpolators
-val enableLightReveal =
- SystemProperties.getBoolean("persist.sysui.show_new_screen_on_transitions", false)
-
/**
* Provides methods to modify the various properties of a [LightRevealScrim] to reveal between 0% to
* 100% of the view(s) underneath the scrim.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index a816eccebe33..cfadcd7f01ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -388,7 +388,28 @@ public class NotificationRemoteInputManager implements Dumpable {
*/
public boolean activateRemoteInput(View view, RemoteInput[] inputs, RemoteInput input,
PendingIntent pendingIntent, @Nullable EditedSuggestionInfo editedSuggestionInfo) {
+ return activateRemoteInput(view, inputs, input, pendingIntent, editedSuggestionInfo,
+ null /* userMessageContent */, null /* authBypassCheck */);
+ }
+ /**
+ * Activates a given {@link RemoteInput}
+ *
+ * @param view The view of the action button or suggestion chip that was tapped.
+ * @param inputs The remote inputs that need to be sent to the app.
+ * @param input The remote input that needs to be activated.
+ * @param pendingIntent The pending intent to be sent to the app.
+ * @param editedSuggestionInfo The smart reply that should be inserted in the remote input, or
+ * {@code null} if the user is not editing a smart reply.
+ * @param userMessageContent User-entered text with which to initialize the remote input view.
+ * @param authBypassCheck Optional auth bypass check associated with this remote input
+ * activation. If {@code null}, we never bypass.
+ * @return Whether the {@link RemoteInput} was activated.
+ */
+ public boolean activateRemoteInput(View view, RemoteInput[] inputs, RemoteInput input,
+ PendingIntent pendingIntent, @Nullable EditedSuggestionInfo editedSuggestionInfo,
+ @Nullable String userMessageContent,
+ @Nullable AuthBypassPredicate authBypassCheck) {
ViewParent p = view.getParent();
RemoteInputView riv = null;
ExpandableNotificationRow row = null;
@@ -410,40 +431,9 @@ public class NotificationRemoteInputManager implements Dumpable {
row.setUserExpanded(true);
- if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
- final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
-
- final boolean isLockedManagedProfile =
- mUserManager.getUserInfo(userId).isManagedProfile()
- && mKeyguardManager.isDeviceLocked(userId);
-
- final boolean isParentUserLocked;
- if (isLockedManagedProfile) {
- final UserInfo profileParent = mUserManager.getProfileParent(userId);
- isParentUserLocked = (profileParent != null)
- && mKeyguardManager.isDeviceLocked(profileParent.id);
- } else {
- isParentUserLocked = false;
- }
-
- if (mLockscreenUserManager.isLockscreenPublicMode(userId)
- || mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
- // If the parent user is no longer locked, and the user to which the remote input
- // is destined is a locked, managed profile, then onLockedWorkRemoteInput should be
- // called to unlock it.
- if (isLockedManagedProfile && !isParentUserLocked) {
- mCallback.onLockedWorkRemoteInput(userId, row, view);
- } else {
- // Even if we don't have security we should go through this flow, otherwise
- // we won't go to the shade.
- mCallback.onLockedRemoteInput(row, view);
- }
- return true;
- }
- if (isLockedManagedProfile) {
- mCallback.onLockedWorkRemoteInput(userId, row, view);
- return true;
- }
+ final boolean deferBouncer = authBypassCheck != null;
+ if (!deferBouncer && showBouncerForRemoteInput(view, pendingIntent, row)) {
+ return true;
}
if (riv != null && !riv.isAttachedToWindow()) {
@@ -461,7 +451,10 @@ public class NotificationRemoteInputManager implements Dumpable {
&& !row.getPrivateLayout().getExpandedChild().isShown()) {
// The expanded layout is selected, but it's not shown yet, let's wait on it to
// show before we do the animation.
- mCallback.onMakeExpandedVisibleForRemoteInput(row, view);
+ mCallback.onMakeExpandedVisibleForRemoteInput(row, view, deferBouncer, () -> {
+ activateRemoteInput(view, inputs, input, pendingIntent, editedSuggestionInfo,
+ userMessageContent, authBypassCheck);
+ });
return true;
}
@@ -491,10 +484,62 @@ public class NotificationRemoteInputManager implements Dumpable {
riv.setPendingIntent(pendingIntent);
riv.setRemoteInput(inputs, input, editedSuggestionInfo);
riv.focusAnimated();
+ if (userMessageContent != null) {
+ riv.setEditTextContent(userMessageContent);
+ }
+ if (deferBouncer) {
+ final ExpandableNotificationRow finalRow = row;
+ riv.setBouncerChecker(() -> !authBypassCheck.canSendRemoteInputWithoutBouncer()
+ && showBouncerForRemoteInput(view, pendingIntent, finalRow));
+ }
return true;
}
+ private boolean showBouncerForRemoteInput(View view, PendingIntent pendingIntent,
+ ExpandableNotificationRow row) {
+ if (mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
+ return false;
+ }
+
+ final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
+
+ final boolean isLockedManagedProfile =
+ mUserManager.getUserInfo(userId).isManagedProfile()
+ && mKeyguardManager.isDeviceLocked(userId);
+
+ final boolean isParentUserLocked;
+ if (isLockedManagedProfile) {
+ final UserInfo profileParent = mUserManager.getProfileParent(userId);
+ isParentUserLocked = (profileParent != null)
+ && mKeyguardManager.isDeviceLocked(profileParent.id);
+ } else {
+ isParentUserLocked = false;
+ }
+
+ if ((mLockscreenUserManager.isLockscreenPublicMode(userId)
+ || mStatusBarStateController.getState() == StatusBarState.KEYGUARD)) {
+ // If the parent user is no longer locked, and the user to which the remote
+ // input
+ // is destined is a locked, managed profile, then onLockedWorkRemoteInput
+ // should be
+ // called to unlock it.
+ if (isLockedManagedProfile && !isParentUserLocked) {
+ mCallback.onLockedWorkRemoteInput(userId, row, view);
+ } else {
+ // Even if we don't have security we should go through this flow, otherwise
+ // we won't go to the shade.
+ mCallback.onLockedRemoteInput(row, view);
+ }
+ return true;
+ }
+ if (isLockedManagedProfile) {
+ mCallback.onLockedWorkRemoteInput(userId, row, view);
+ return true;
+ }
+ return false;
+ }
+
private RemoteInputView findRemoteInputView(View v) {
if (v == null) {
return null;
@@ -807,8 +852,11 @@ public class NotificationRemoteInputManager implements Dumpable {
*
* @param row
* @param clickedView
+ * @param deferBouncer
+ * @param runnable
*/
- void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row, View clickedView);
+ void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row, View clickedView,
+ boolean deferBouncer, Runnable runnable);
/**
* Return whether or not remote input should be handled for this view.
@@ -845,4 +893,28 @@ public class NotificationRemoteInputManager implements Dumpable {
*/
boolean handleClick();
}
+
+ /**
+ * Predicate that is associated with a specific {@link #activateRemoteInput(View, RemoteInput[],
+ * RemoteInput, PendingIntent, EditedSuggestionInfo, String, AuthBypassPredicate)}
+ * invocation that determines whether or not the bouncer can be bypassed when sending the
+ * RemoteInput.
+ */
+ public interface AuthBypassPredicate {
+ /**
+ * Determines if the RemoteInput can be sent without the bouncer. Should be checked the
+ * same frame that the RemoteInput is to be sent.
+ */
+ boolean canSendRemoteInputWithoutBouncer();
+ }
+
+ /** Shows the bouncer if necessary */
+ public interface BouncerChecker {
+ /**
+ * Shows the bouncer if necessary in order to send a RemoteInput.
+ *
+ * @return {@code true} if the bouncer was shown, {@code false} otherwise
+ */
+ boolean showBouncerIfNecessary();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
index 79648457c521..301c3726793a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
@@ -29,6 +29,30 @@ public class NotificationDecoratedCustomViewWrapper extends NotificationTemplate
private View mWrappedView = null;
+ /**
+ * Determines if the standard template contains a custom view, injected by Notification.Builder
+ */
+ public static boolean hasCustomView(View v) {
+ return getWrappedCustomView(v) != null;
+ }
+
+ private static View getWrappedCustomView(View view) {
+ if (view == null) {
+ return null;
+ }
+ ViewGroup container = view.findViewById(
+ com.android.internal.R.id.notification_main_column);
+ if (container == null) {
+ return null;
+ }
+ Integer childIndex = (Integer) container.getTag(
+ com.android.internal.R.id.notification_custom_view_index_tag);
+ if (childIndex == null || childIndex == -1) {
+ return null;
+ }
+ return container.getChildAt(childIndex);
+ }
+
protected NotificationDecoratedCustomViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
super(ctx, view, row);
@@ -36,13 +60,7 @@ public class NotificationDecoratedCustomViewWrapper extends NotificationTemplate
@Override
public void onContentUpdated(ExpandableNotificationRow row) {
- ViewGroup container = mView.findViewById(
- com.android.internal.R.id.notification_main_column);
- Integer childIndex = (Integer) container.getTag(
- com.android.internal.R.id.notification_custom_view_index_tag);
- if (childIndex != null && childIndex != -1) {
- mWrappedView = container.getChildAt(childIndex);
- }
+ mWrappedView = getWrappedCustomView(mView);
// Custom views will most likely use just white or black as their text color.
// We need to scan through and replace these colors by Material NEXT colors.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 7b5c5f6dcf8f..b3d1a94beaa9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -80,6 +80,9 @@ public abstract class NotificationViewWrapper implements TransformableView {
if (Notification.DecoratedCustomViewStyle.class.equals(style)) {
return new NotificationDecoratedCustomViewWrapper(ctx, v, row);
}
+ if (NotificationDecoratedCustomViewWrapper.hasCustomView(v)) {
+ return new NotificationDecoratedCustomViewWrapper(ctx, v, row);
+ }
return new NotificationTemplateViewWrapper(ctx, v, row);
} else if (v instanceof NotificationHeaderView) {
return new NotificationHeaderViewWrapper(ctx, v, row);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 8c2fa3349e4a..85d8df8e6057 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -29,6 +29,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.tuner.TunerService;
@@ -54,6 +55,7 @@ public class DozeParameters implements TunerService.Tunable,
private final AlwaysOnDisplayPolicy mAlwaysOnPolicy;
private final Resources mResources;
private final BatteryController mBatteryController;
+ private final FeatureFlags mFeatureFlags;
private boolean mDozeAlwaysOn;
private boolean mControlScreenOffAnimation;
@@ -65,7 +67,8 @@ public class DozeParameters implements TunerService.Tunable,
AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
PowerManager powerManager,
BatteryController batteryController,
- TunerService tunerService) {
+ TunerService tunerService,
+ FeatureFlags featureFlags) {
mResources = resources;
mAmbientDisplayConfiguration = ambientDisplayConfiguration;
mAlwaysOnPolicy = alwaysOnDisplayPolicy;
@@ -74,6 +77,7 @@ public class DozeParameters implements TunerService.Tunable,
mControlScreenOffAnimation = !getDisplayNeedsBlanking();
mPowerManager = powerManager;
mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
+ mFeatureFlags = featureFlags;
tunerService.addTunable(
this,
@@ -200,8 +204,7 @@ public class DozeParameters implements TunerService.Tunable,
* then abruptly showing AOD.
*/
public boolean shouldControlUnlockedScreenOff() {
- return getAlwaysOn() && SystemProperties.getBoolean(
- "persist.sysui.show_new_screen_on_transitions", false);
+ return getAlwaysOn() && mFeatureFlags.useNewLockscreenAnimations();
}
private boolean getBoolean(String propName, int resId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index dd1419f4ff42..2ce0a8776266 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -131,8 +131,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private KeyguardAffordanceView mLeftAffordanceView;
private ImageView mAltLeftButton;
private ViewGroup mIndicationArea;
- private TextView mEnterpriseDisclosure;
private TextView mIndicationText;
+ private TextView mIndicationTextBottom;
private ViewGroup mPreviewContainer;
private ViewGroup mOverlayContainer;
@@ -251,9 +251,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mLeftAffordanceView = findViewById(R.id.left_button);
mAltLeftButton = findViewById(R.id.alt_left_button);
mIndicationArea = findViewById(R.id.keyguard_indication_area);
- mEnterpriseDisclosure = findViewById(
- R.id.keyguard_indication_enterprise_disclosure);
mIndicationText = findViewById(R.id.keyguard_indication_text);
+ mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
mIndicationBottomMargin = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_margin_bottom);
mBurnInYOffset = getResources().getDimensionPixelSize(
@@ -330,7 +329,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
// Respect font size setting.
- mEnterpriseDisclosure.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ mIndicationTextBottom.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(
com.android.internal.R.dimen.text_size_small_material));
mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index 30c951ac518c..8970a9a20931 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -16,11 +16,15 @@
package com.android.systemui.statusbar.phone;
+import static com.android.keyguard.KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
@@ -28,6 +32,7 @@ import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Interpolators;
+import com.android.systemui.keyguard.KeyguardIndication;
import java.util.LinkedList;
@@ -35,13 +40,15 @@ import java.util.LinkedList;
* A view to show hints on Keyguard ("Swipe up to unlock", "Tap again to open").
*/
public class KeyguardIndicationTextView extends TextView {
-
private static final int FADE_OUT_MILLIS = 200;
private static final int FADE_IN_MILLIS = 250;
private static final long MSG_DURATION_MILLIS = 600;
private long mNextAnimationTime = 0;
private boolean mAnimationsEnabled = true;
private LinkedList<CharSequence> mMessages = new LinkedList<>();
+ private LinkedList<KeyguardIndication> mKeyguardIndicationInfo = new LinkedList<>();
+
+ private boolean mUseNewAnimations = false;
public KeyguardIndicationTextView(Context context) {
super(context);
@@ -60,12 +67,33 @@ public class KeyguardIndicationTextView extends TextView {
super(context, attrs, defStyleAttr, defStyleRes);
}
+ public void setLockScreenMode(int lockScreenMode) {
+ mUseNewAnimations = lockScreenMode == LOCK_SCREEN_MODE_LAYOUT_1;
+ }
+
+ /**
+ * Changes the text with an animation and makes sure a single indication is shown long enough.
+ */
+ public void switchIndication(int textResId) {
+ switchIndication(getResources().getText(textResId), null);
+ }
+
+ /**
+ * Changes the text with an animation and makes sure a single indication is shown long enough.
+ *
+ * @param indication The text to show.
+ */
+ public void switchIndication(KeyguardIndication indication) {
+ switchIndication(indication == null ? null : indication.getMessage(), indication);
+ }
+
/**
* Changes the text with an animation and makes sure a single indication is shown long enough.
*
* @param text The text to show.
+ * @param indication optional display information for the text
*/
- public void switchIndication(CharSequence text) {
+ public void switchIndication(CharSequence text, KeyguardIndication indication) {
if (text == null) text = "";
CharSequence lastPendingMessage = mMessages.peekLast();
@@ -74,55 +102,119 @@ public class KeyguardIndicationTextView extends TextView {
return;
}
mMessages.add(text);
+ mKeyguardIndicationInfo.add(indication);
- Animator fadeOut = ObjectAnimator.ofFloat(this, View.ALPHA, 0f);
- fadeOut.setDuration(getFadeOutMillis());
- fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
-
- final CharSequence nextText = text;
- fadeOut.addListener(new AnimatorListenerAdapter() {
- public void onAnimationEnd(Animator animator) {
- setText(mMessages.poll());
- }
- });
-
+ final boolean hasIcon = indication != null && indication.getIcon() != null;
final AnimatorSet animSet = new AnimatorSet();
- final AnimatorSet.Builder animSetBuilder = animSet.play(fadeOut);
+ final AnimatorSet.Builder animSetBuilder = animSet.play(getOutAnimator());
// Make sure each animation is visible for a minimum amount of time, while not worrying
// about fading in blank text
long timeInMillis = System.currentTimeMillis();
long delay = Math.max(0, mNextAnimationTime - timeInMillis);
- setNextAnimationTime(timeInMillis + delay + getFadeOutMillis());
+ setNextAnimationTime(timeInMillis + delay + getFadeOutDuration());
- if (!text.equals("")) {
+ if (!text.equals("") || hasIcon) {
setNextAnimationTime(mNextAnimationTime + MSG_DURATION_MILLIS);
-
- ObjectAnimator fadeIn = ObjectAnimator.ofFloat(this, View.ALPHA, 1f);
- fadeIn.setDuration(getFadeInMillis());
- fadeIn.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- animSetBuilder.before(fadeIn);
+ animSetBuilder.before(getInAnimator());
}
animSet.setStartDelay(delay);
animSet.start();
}
+ private AnimatorSet getOutAnimator() {
+ AnimatorSet animatorSet = new AnimatorSet();
+ Animator fadeOut = ObjectAnimator.ofFloat(this, View.ALPHA, 0f);
+ fadeOut.setDuration(getFadeOutDuration());
+ fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+ fadeOut.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ KeyguardIndication info = mKeyguardIndicationInfo.poll();
+ if (info != null) {
+ setTextColor(info.getTextColor());
+ setOnClickListener(info.getClickListener());
+ final Drawable icon = info.getIcon();
+ if (icon != null) {
+ icon.setTint(getCurrentTextColor());
+ if (icon instanceof AnimatedVectorDrawable) {
+ ((AnimatedVectorDrawable) icon).start();
+ }
+ }
+ setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null);
+ }
+ setText(mMessages.poll());
+ }
+ });
+
+ if (mUseNewAnimations) {
+ Animator yTranslate =
+ ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, 0, -getYTranslationPixels());
+ yTranslate.setDuration(getFadeOutDuration());
+ fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+ animatorSet.playTogether(fadeOut, yTranslate);
+ } else {
+ animatorSet.play(fadeOut);
+ }
+
+ return animatorSet;
+ }
+
+ private AnimatorSet getInAnimator() {
+ AnimatorSet animatorSet = new AnimatorSet();
+ ObjectAnimator fadeIn = ObjectAnimator.ofFloat(this, View.ALPHA, 1f);
+ fadeIn.setStartDelay(getFadeInDelay());
+ fadeIn.setDuration(getFadeInDuration());
+ fadeIn.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+
+ if (mUseNewAnimations) {
+ Animator yTranslate =
+ ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, getYTranslationPixels(), 0);
+ yTranslate.setDuration(getYInDuration());
+ yTranslate.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ setTranslationY(0);
+ }
+ });
+ animatorSet.playTogether(yTranslate, fadeIn);
+ } else {
+ animatorSet.play(fadeIn);
+ }
+
+ return animatorSet;
+ }
+
@VisibleForTesting
public void setAnimationsEnabled(boolean enabled) {
mAnimationsEnabled = enabled;
}
- private long getFadeInMillis() {
- if (mAnimationsEnabled) return FADE_IN_MILLIS;
+ private long getFadeInDelay() {
+ if (!mAnimationsEnabled) return 0L;
+ if (mUseNewAnimations) return 150L;
return 0L;
}
- private long getFadeOutMillis() {
- if (mAnimationsEnabled) return FADE_OUT_MILLIS;
+ private long getFadeInDuration() {
+ if (!mAnimationsEnabled) return 0L;
+ if (mUseNewAnimations) return 317L;
+ return FADE_IN_MILLIS;
+ }
+
+ private long getYInDuration() {
+ if (!mAnimationsEnabled) return 0L;
+ if (mUseNewAnimations) return 600L;
return 0L;
}
+ private long getFadeOutDuration() {
+ if (!mAnimationsEnabled) return 0L;
+ if (mUseNewAnimations) return 167L;
+ return FADE_OUT_MILLIS;
+ }
+
private void setNextAnimationTime(long time) {
if (mAnimationsEnabled) {
mNextAnimationTime = time;
@@ -131,10 +223,8 @@ public class KeyguardIndicationTextView extends TextView {
}
}
- /**
- * See {@link #switchIndication}.
- */
- public void switchIndication(int textResId) {
- switchIndication(getResources().getText(textResId));
+ private int getYTranslationPixels() {
+ return mContext.getResources().getDimensionPixelSize(
+ com.android.systemui.R.dimen.keyguard_indication_y_translation);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 7095afd45959..1e19beeff730 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -35,7 +35,6 @@ import static com.android.systemui.charging.WirelessChargingLayout.UNKNOWN_BATTE
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
-import static com.android.systemui.statusbar.LightRevealScrimKt.getEnableLightReveal;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
@@ -181,6 +180,7 @@ import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -442,6 +442,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final KeyguardViewMediator mKeyguardViewMediator;
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final BrightnessSlider.Factory mBrightnessSliderFactory;
+ private final FeatureFlags mFeatureFlags;
private final List<ExpansionChangedListener> mExpansionChangedListeners;
@@ -765,7 +766,8 @@ public class StatusBar extends SystemUI implements DemoMode,
Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
NotificationIconAreaController notificationIconAreaController,
- BrightnessSlider.Factory brightnessSliderFactory) {
+ BrightnessSlider.Factory brightnessSliderFactory,
+ FeatureFlags featureFlags) {
super(context);
mNotificationsController = notificationsController;
mLightBarController = lightBarController;
@@ -843,6 +845,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mDemoModeController = demoModeController;
mNotificationIconAreaController = notificationIconAreaController;
mBrightnessSliderFactory = brightnessSliderFactory;
+ mFeatureFlags = featureFlags;
mExpansionChangedListeners = new ArrayList<>();
@@ -1143,8 +1146,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mLockscreenWallpaper = mLockscreenWallpaperLazy.get();
}
- mKeyguardIndicationController.setIndicationArea(
- mNotificationShadeWindowView.findViewById(R.id.keyguard_indication_area));
mNotificationPanelViewController.setKeyguardIndicationController(
mKeyguardIndicationController);
@@ -1186,9 +1187,11 @@ public class StatusBar extends SystemUI implements DemoMode,
mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
- if (getEnableLightReveal()) {
+ if (mFeatureFlags.useNewLockscreenAnimations() && mDozeParameters.getAlwaysOn()) {
mLightRevealScrim.setVisibility(View.VISIBLE);
mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
+ } else {
+ mLightRevealScrim.setVisibility(View.GONE);
}
mNotificationPanelViewController.initDependencies(
@@ -3620,26 +3623,19 @@ public class StatusBar extends SystemUI implements DemoMode,
mNavigationBarController.touchAutoDim(mDisplayId);
Trace.beginSection("StatusBar#updateKeyguardState");
if (mState == StatusBarState.KEYGUARD) {
- mKeyguardIndicationController.setVisible(true);
if (mKeyguardUserSwitcher != null) {
mKeyguardUserSwitcher.setKeyguard(true,
mStatusBarStateController.fromShadeLocked());
}
if (mStatusBarView != null) mStatusBarView.removePendingHideExpandedRunnables();
- if (mAmbientIndicationContainer != null) {
- mAmbientIndicationContainer.setVisibility(View.VISIBLE);
- }
} else {
- mKeyguardIndicationController.setVisible(false);
if (mKeyguardUserSwitcher != null) {
mKeyguardUserSwitcher.setKeyguard(false,
mStatusBarStateController.goingToFullShade() ||
mState == StatusBarState.SHADE_LOCKED ||
mStatusBarStateController.fromShadeLocked());
}
- if (mAmbientIndicationContainer != null) {
- mAmbientIndicationContainer.setVisibility(View.INVISIBLE);
- }
+
}
updateDozingState();
checkBarModes();
@@ -3651,7 +3647,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onDozeAmountChanged(float linear, float eased) {
- if (getEnableLightReveal()) {
+ if (mFeatureFlags.useNewLockscreenAnimations()) {
mLightRevealScrim.setRevealAmount(1f - linear);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 36519ac0d808..983b296e006b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -180,8 +180,8 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
@Override
public void onMakeExpandedVisibleForRemoteInput(ExpandableNotificationRow row,
- View clickedView) {
- if (mKeyguardStateController.isShowing()) {
+ View clickedView, boolean deferBouncer, Runnable runnable) {
+ if (!deferBouncer && mKeyguardStateController.isShowing()) {
onLockedRemoteInput(row, clickedView);
} else {
if (row.isChildInGroup() && !row.areChildrenExpanded()) {
@@ -189,7 +189,7 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
mGroupExpansionManager.toggleGroupExpansion(row.getEntry());
}
row.setUserExpanded(true);
- row.getPrivateLayout().setOnExpandedVisibleListener(clickedView::performClick);
+ row.getPrivateLayout().setOnExpandedVisibleListener(runnable);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 9e9533d0e199..b572c57590ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -47,6 +47,7 @@ import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -200,7 +201,8 @@ public interface StatusBarPhoneModule {
DismissCallbackRegistry dismissCallbackRegistry,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
NotificationIconAreaController notificationIconAreaController,
- BrightnessSlider.Factory brightnessSliderFactory) {
+ BrightnessSlider.Factory brightnessSliderFactory,
+ FeatureFlags featureFlags) {
return new StatusBar(
context,
notificationsController,
@@ -279,6 +281,7 @@ public interface StatusBarPhoneModule {
notificationShadeDepthController,
statusBarTouchableRegionManager,
notificationIconAreaController,
- brightnessSliderFactory);
+ brightnessSliderFactory,
+ featureFlags);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index 08a4492fc15d..ccaa1f480683 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -25,6 +25,8 @@ import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
@@ -42,11 +44,18 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
private static final int MSG_MOBILE_DATA_ENABLED_CHANGED = 5;
private static final int MSG_ADD_REMOVE_EMERGENCY = 6;
private static final int MSG_ADD_REMOVE_SIGNAL = 7;
+ private static final int HISTORY_SIZE = 64;
+ private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
// All the callbacks.
private final ArrayList<EmergencyListener> mEmergencyListeners = new ArrayList<>();
private final ArrayList<SignalCallback> mSignalCallbacks = new ArrayList<>();
+ // Save the previous HISTORY_SIZE states for logging.
+ private final String[] mHistory = new String[HISTORY_SIZE];
+ // Where to copy the next state into.
+ private int mHistoryIndex;
+
public CallbackHandler() {
super(Looper.getMainLooper());
}
@@ -111,12 +120,27 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
public void setWifiIndicators(final boolean enabled, final IconState statusIcon,
final IconState qsIcon, final boolean activityIn, final boolean activityOut,
final String description, boolean isTransient, String secondaryLabel) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setWifiIndicators: ")
+ .append("enabled=").append(enabled).append(",")
+ .append("statusIcon=").append(statusIcon).append(",")
+ .append("qsIcon=").append(qsIcon).append(",")
+ .append("activityIn=").append(activityIn).append(",")
+ .append("activityOut=").append(activityOut).append(",")
+ .append("description=").append(description).append(",")
+ .append("isTransient=").append(isTransient).append(",")
+ .append("secondaryLabel=").append(secondaryLabel)
+ .toString();
+ recordLastCallback(log);
post(() -> {
for (SignalCallback callback : mSignalCallbacks) {
callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut,
description, isTransient, secondaryLabel);
}
});
+
+
}
@Override
@@ -125,6 +149,25 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
final boolean activityOut, final CharSequence typeContentDescription,
CharSequence typeContentDescriptionHtml, final CharSequence description,
final boolean isWide, final int subId, boolean roaming, boolean showTriangle) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setMobileDataIndicators: ")
+ .append("statusIcon=").append(statusIcon).append(",")
+ .append("qsIcon=").append(qsIcon).append(",")
+ .append("statusType=").append(statusType).append(",")
+ .append("qsType=").append(qsType).append(",")
+ .append("activityIn=").append(activityIn).append(",")
+ .append("activityOut=").append(activityOut).append(",")
+ .append("typeContentDescription=").append(typeContentDescription).append(",")
+ .append("typeContentDescriptionHtml=").append(typeContentDescriptionHtml)
+ .append(",")
+ .append("description=").append(description).append(",")
+ .append("isWide=").append(isWide).append(",")
+ .append("subId=").append(subId).append(",")
+ .append("roaming=").append(roaming).append(",")
+ .append("showTriangle=").append(showTriangle)
+ .toString();
+ recordLastCallback(log);
post(() -> {
for (SignalCallback signalCluster : mSignalCallbacks) {
signalCluster.setMobileDataIndicators(statusIcon, qsIcon, statusType, qsType,
@@ -138,6 +181,14 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
@Override
public void setConnectivityStatus(boolean noDefaultNetwork, boolean noValidatedNetwork,
boolean noNetworksAvailable) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setConnectivityStatus: ")
+ .append("noDefaultNetwork=").append(noDefaultNetwork).append(",")
+ .append("noValidatedNetwork=").append(noValidatedNetwork).append(",")
+ .append("noNetworksAvailable=").append(noNetworksAvailable)
+ .toString();
+ recordLastCallback(log);
post(() -> {
for (SignalCallback signalCluster : mSignalCallbacks) {
signalCluster.setConnectivityStatus(
@@ -148,6 +199,13 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
@Override
public void setNoCallingStatus(boolean noCalling, int subId) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setNoCallingStatus: ")
+ .append("noCalling=").append(noCalling).append(",")
+ .append("subId=").append(subId)
+ .toString();
+ recordLastCallback(log);
post(() -> {
for (SignalCallback signalCluster : mSignalCallbacks) {
signalCluster.setNoCallingStatus(noCalling, subId);
@@ -157,16 +215,35 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
@Override
public void setSubs(List<SubscriptionInfo> subs) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setSubs: ")
+ .append("subs=").append(subs == null ? "" : subs.toString())
+ .toString();
+ recordLastCallback(log);
obtainMessage(MSG_SUBS_CHANGED, subs).sendToTarget();
}
@Override
public void setNoSims(boolean show, boolean simDetected) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setNoSims: ")
+ .append("show=").append(show).append(",")
+ .append("simDetected=").append(simDetected)
+ .toString();
+ recordLastCallback(log);
obtainMessage(MSG_NO_SIM_VISIBLE_CHANGED, show ? 1 : 0, simDetected ? 1 : 0).sendToTarget();
}
@Override
public void setMobileDataEnabled(boolean enabled) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setMobileDataEnabled: ")
+ .append("enabled=").append(enabled)
+ .toString();
+ recordLastCallback(log);
obtainMessage(MSG_MOBILE_DATA_ENABLED_CHANGED, enabled ? 1 : 0, 0).sendToTarget();
}
@@ -177,11 +254,23 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
@Override
public void setEthernetIndicators(IconState icon) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setEthernetIndicators: ")
+ .append("icon=").append(icon)
+ .toString();
+ recordLastCallback(log);
obtainMessage(MSG_ETHERNET_CHANGED, icon).sendToTarget();;
}
@Override
public void setIsAirplaneMode(IconState icon) {
+ String log = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("setIsAirplaneMode: ")
+ .append("icon=").append(icon)
+ .toString();
+ recordLastCallback(log);
obtainMessage(MSG_AIRPLANE_MODE_CHANGED, icon).sendToTarget();;
}
@@ -193,4 +282,25 @@ public class CallbackHandler extends Handler implements EmergencyListener, Signa
obtainMessage(MSG_ADD_REMOVE_SIGNAL, listening ? 1 : 0, 0, listener).sendToTarget();
}
+ protected void recordLastCallback(String callback) {
+ mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)] = callback;
+ }
+
+ /**
+ * Dump the Callback logs
+ */
+ public void dump(PrintWriter pw) {
+ pw.println(" - CallbackHandler -----");
+ int size = 0;
+ for (int i = 0; i < HISTORY_SIZE; i++) {
+ if (mHistory[i] != null) size++;
+ }
+ // Print out the previous states in ordered number.
+ for (int i = mHistoryIndex + HISTORY_SIZE - 1;
+ i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
+ pw.println(" Previous Callback(" + (mHistoryIndex + HISTORY_SIZE - i) + "): "
+ + mHistory[i & (HISTORY_SIZE - 1)]);
+ }
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 39472ded4a3f..0fe338ea118d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -46,6 +46,7 @@ import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.mobile.MobileMappings.Config;
import com.android.settingslib.mobile.MobileStatusTracker;
+import com.android.settingslib.mobile.MobileStatusTracker.MobileStatus;
import com.android.settingslib.mobile.MobileStatusTracker.SubscriptionDefaults;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
@@ -54,6 +55,7 @@ import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.BitSet;
import java.util.List;
import java.util.Map;
@@ -62,6 +64,8 @@ import java.util.Map;
* Monitors the mobile signal changes and update the SysUI icons.
*/
public class MobileSignalController extends SignalController<MobileState, MobileIconGroup> {
+ private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+
private final TelephonyManager mPhone;
private final SubscriptionDefaults mDefaults;
private final String mNetworkNameDefault;
@@ -90,6 +94,11 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
@VisibleForTesting
MobileStatusTracker mMobileStatusTracker;
+ // Save the previous HISTORY_SIZE states for logging.
+ private final String[] mMobileStatusHistory = new String[HISTORY_SIZE];
+ // Where to copy the next state into.
+ private int mMobileStatusHistoryIndex;
+
// TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
// need listener lists anymore.
public MobileSignalController(Context context, Config config, boolean hasMobileData,
@@ -126,12 +135,17 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
mCallback = new MobileStatusTracker.Callback() {
@Override
public void onMobileStatusChanged(boolean updateTelephony,
- MobileStatusTracker.MobileStatus mobileStatus) {
+ MobileStatus mobileStatus) {
if (Log.isLoggable(mTag, Log.DEBUG)) {
Log.d(mTag, "onMobileStatusChanged="
+ " updateTelephony=" + updateTelephony
+ " mobileStatus=" + mobileStatus.toString());
}
+ String status = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append(mobileStatus.toString())
+ .toString();
+ recordLastMobileStatus(status);
updateMobileStatus(mobileStatus);
if (updateTelephony) {
updateTelephony();
@@ -343,16 +357,8 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
return Utils.isInService(mServiceState);
}
- String getNonDefaultCarrierName() {
- if (!mCurrentState.networkNameData.equals(mNetworkNameDefault)) {
- return mCurrentState.networkNameData;
- } else if (mSubscriptionInfo.getCarrierName() != null) {
- return mSubscriptionInfo.getCarrierName().toString();
- } else if (mSubscriptionInfo.getDisplayName() != null) {
- return mSubscriptionInfo.getDisplayName().toString();
- } else {
- return "";
- }
+ String getNetworkNameForCarrierWiFi() {
+ return mPhone.getSimOperatorName();
}
private boolean isRoaming() {
@@ -455,7 +461,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
return CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
- private void updateMobileStatus(MobileStatusTracker.MobileStatus mobileStatus) {
+ private void updateMobileStatus(MobileStatus mobileStatus) {
mCurrentState.activityIn = mobileStatus.activityIn;
mCurrentState.activityOut = mobileStatus.activityOut;
mCurrentState.dataSim = mobileStatus.dataSim;
@@ -570,6 +576,10 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
notifyListenersIfNecessary();
}
+ private void recordLastMobileStatus(String mobileStatus) {
+ mMobileStatusHistory[mMobileStatusHistoryIndex++ & (HISTORY_SIZE - 1)] = mobileStatus;
+ }
+
@Override
public void dump(PrintWriter pw) {
super.dump(pw);
@@ -580,5 +590,17 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
pw.println(" mDataState=" + mDataState + ",");
pw.println(" mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
pw.println(" isDataDisabled=" + isDataDisabled() + ",");
+ pw.println(" MobileStatusHistory");
+ int size = 0;
+ for (int i = 0; i < HISTORY_SIZE; i++) {
+ if (mMobileStatusHistory[i] != null) size++;
+ }
+ // Print out the previous states in ordered number.
+ for (int i = mMobileStatusHistoryIndex + HISTORY_SIZE - 1;
+ i >= mMobileStatusHistoryIndex + HISTORY_SIZE - size; i--) {
+ pw.println(" Previous MobileStatus("
+ + (mMobileStatusHistoryIndex + HISTORY_SIZE - i) + "): "
+ + mMobileStatusHistory[i & (HISTORY_SIZE - 1)]);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index e13e30b74c3c..80c78115f7bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -76,6 +76,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
@@ -100,6 +101,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
private static final int EMERGENCY_VOICE_CONTROLLER = 200;
private static final int EMERGENCY_NO_SUB = 300;
private static final int EMERGENCY_ASSUMED_VOICE_CONTROLLER = 400;
+ private static final int HISTORY_SIZE = 16;
+ private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
private final Context mContext;
private final TelephonyManager mPhone;
@@ -150,6 +153,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
// This list holds our ordering.
private List<SubscriptionInfo> mCurrentSubscriptions = new ArrayList<>();
+ // Save the previous HISTORY_SIZE states for logging.
+ private final String[] mHistory = new String[HISTORY_SIZE];
+ // Where to copy the next state into.
+ private int mHistoryIndex;
+
@VisibleForTesting
boolean mListening;
@@ -307,6 +315,12 @@ public class NetworkControllerImpl extends BroadcastReceiver
public void onLost(Network network) {
mLastNetwork = null;
mLastNetworkCapabilities = null;
+ String callback = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("onLost: ")
+ .append("network=").append(network)
+ .toString();
+ recordLastNetworkCallback(callback);
updateConnectivity();
}
@@ -327,6 +341,13 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
mLastNetwork = network;
mLastNetworkCapabilities = networkCapabilities;
+ String callback = new StringBuilder()
+ .append(SSDF.format(System.currentTimeMillis())).append(",")
+ .append("onCapabilitiesChanged: ")
+ .append("network=").append(network).append(",")
+ .append("networkCapabilities=").append(networkCapabilities)
+ .toString();
+ recordLastNetworkCallback(callback);
updateConnectivity();
}
};
@@ -528,9 +549,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
}
- String getNonDefaultMobileDataNetworkName(int subId) {
+ String getNetworkNameForCarrierWiFi(int subId) {
MobileSignalController controller = getControllerWithSubId(subId);
- return controller != null ? controller.getNonDefaultCarrierName() : "";
+ return controller != null ? controller.getNetworkNameForCarrierWiFi() : "";
}
private void notifyControllersMobileDataChanged() {
@@ -996,6 +1017,19 @@ public class NetworkControllerImpl extends BroadcastReceiver
pw.print(" mEmergencySource=");
pw.println(emergencyToString(mEmergencySource));
+ pw.println(" - DefaultNetworkCallback -----");
+ int size = 0;
+ for (int i = 0; i < HISTORY_SIZE; i++) {
+ if (mHistory[i] != null) {
+ size++;
+ }
+ }
+ for (int i = mHistoryIndex + HISTORY_SIZE - 1;
+ i >= mHistoryIndex + HISTORY_SIZE - size; i--) {
+ pw.println(" Previous NetworkCallback(" + (mHistoryIndex + HISTORY_SIZE - i) + "): "
+ + mHistory[i & (HISTORY_SIZE - 1)]);
+ }
+
pw.println(" - config ------");
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
@@ -1006,6 +1040,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
mEthernetSignalController.dump(pw);
mAccessPoints.dump(pw);
+
+ mCallbackHandler.dump(pw);
}
private static final String emergencyToString(int emergencySource) {
@@ -1235,6 +1271,10 @@ public class NetworkControllerImpl extends BroadcastReceiver
return s;
}
+ private void recordLastNetworkCallback(String callback) {
+ mHistory[mHistoryIndex++ & (HISTORY_SIZE - 1)] = callback;
+ }
+
private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
null, null, null, "", false, null, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 9380d9110c35..8e833c05b447 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -73,6 +73,7 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
@@ -80,6 +81,7 @@ import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewW
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LightBarController;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -99,6 +101,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private final SendButtonTextWatcher mTextWatcher;
private final TextView.OnEditorActionListener mEditorActionHandler;
+ private final NotificationRemoteInputManager mRemoteInputManager;
+ private final List<OnFocusChangeListener> mEditTextFocusChangeListeners = new ArrayList<>();
private RemoteEditText mEditText;
private ImageButton mSendButton;
private ProgressBar mProgressBar;
@@ -121,12 +125,14 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private boolean mResetting;
private NotificationViewWrapper mWrapper;
private Consumer<Boolean> mOnVisibilityChangedListener;
+ private NotificationRemoteInputManager.BouncerChecker mBouncerChecker;
public RemoteInputView(Context context, AttributeSet attrs) {
super(context, attrs);
mTextWatcher = new SendButtonTextWatcher();
mEditorActionHandler = new EditorActionHandler();
mRemoteInputQuickSettingsDisabler = Dependency.get(RemoteInputQuickSettingsDisabler.class);
+ mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
mStatusBarManagerService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}
@@ -200,6 +206,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
}
private void sendRemoteInput(Intent intent) {
+ if (mBouncerChecker != null && mBouncerChecker.showBouncerIfNecessary()) {
+ mEditText.hideIme();
+ return;
+ }
+
mEditText.setEnabled(false);
mSendButton.setVisibility(INVISIBLE);
mProgressBar.setVisibility(VISIBLE);
@@ -351,6 +362,11 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
}
}
+ /** Populates the text field of the remote input with the given content. */
+ public void setEditTextContent(@Nullable CharSequence editTextContent) {
+ mEditText.setText(editTextContent);
+ }
+
public void focusAnimated() {
if (getVisibility() != VISIBLE) {
Animator animator = ViewAnimationUtils.createCircularReveal(
@@ -552,6 +568,37 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
return getVisibility() == VISIBLE && mController.isSpinning(mEntry.getKey(), mToken);
}
+ /**
+ * Sets a {@link com.android.systemui.statusbar.NotificationRemoteInputManager.BouncerChecker}
+ * that will be used to determine if the device needs to be unlocked before sending the
+ * RemoteInput.
+ */
+ public void setBouncerChecker(
+ @Nullable NotificationRemoteInputManager.BouncerChecker bouncerChecker) {
+ mBouncerChecker = bouncerChecker;
+ }
+
+ /** Registers a listener for focus-change events on the EditText */
+ public void addOnEditTextFocusChangedListener(View.OnFocusChangeListener listener) {
+ mEditTextFocusChangeListeners.add(listener);
+ }
+
+ /** Removes a previously-added listener for focus-change events on the EditText */
+ public void removeOnEditTextFocusChangedListener(View.OnFocusChangeListener listener) {
+ mEditTextFocusChangeListeners.remove(listener);
+ }
+
+ /** Determines if the EditText has focus. */
+ public boolean editTextHasFocus() {
+ return mEditText != null && mEditText.hasFocus();
+ }
+
+ private void onEditTextFocusChanged(RemoteEditText remoteEditText, boolean focused) {
+ for (View.OnFocusChangeListener listener : mEditTextFocusChangeListeners) {
+ listener.onFocusChange(remoteEditText, focused);
+ }
+ }
+
/** Handler for button click on send action in IME. */
private class EditorActionHandler implements TextView.OnEditorActionListener {
@@ -603,6 +650,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
private RemoteInputView mRemoteInputView;
boolean mShowImeOnInputConnection;
private LightBarController mLightBarController;
+ private InputMethodManager mInputMethodManager;
UserHandle mUser;
public RemoteEditText(Context context, AttributeSet attrs) {
@@ -621,6 +669,12 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
setOnReceiveContentListener(types, listener);
}
+ private void hideIme() {
+ if (mInputMethodManager != null) {
+ mInputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+ }
+ }
+
private void defocusIfNeeded(boolean animate) {
if (mRemoteInputView != null && mRemoteInputView.mEntry.getRow().isChangingPosition()
|| isTemporarilyDetached()) {
@@ -654,6 +708,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
+ if (mRemoteInputView != null) {
+ mRemoteInputView.onEditTextFocusChanged(this, focused);
+ }
if (!focused) {
defocusIfNeeded(true /* animate */);
}
@@ -724,17 +781,16 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
if (mShowImeOnInputConnection && ic != null) {
Context targetContext = userContext != null ? userContext : getContext();
- final InputMethodManager imm =
- targetContext.getSystemService(InputMethodManager.class);
- if (imm != null) {
+ mInputMethodManager = targetContext.getSystemService(InputMethodManager.class);
+ if (mInputMethodManager != null) {
// onCreateInputConnection is called by InputMethodManager in the middle of
// setting up the connection to the IME; wait with requesting the IME until that
// work has completed.
post(new Runnable() {
@Override
public void run() {
- imm.viewClicked(RemoteEditText.this);
- imm.showSoftInput(RemoteEditText.this, 0);
+ mInputMethodManager.viewClicked(RemoteEditText.this);
+ mInputMethodManager.showSoftInput(RemoteEditText.this, 0);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index b2120d47ab5d..1fd2ccbf8500 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -147,7 +147,7 @@ public class WifiSignalController extends
IconState qsIcon = new IconState(
mCurrentState.connected, getQsCurrentIconIdForCarrierWifi(), contentDescription);
CharSequence description =
- mNetworkController.getNonDefaultMobileDataNetworkName(mCurrentState.subId);
+ mNetworkController.getNetworkNameForCarrierWiFi(mCurrentState.subId);
callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
mCurrentState.activityIn, mCurrentState.activityOut, dataContentDescription,
dataContentDescriptionHtml, description, icons.isWide,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index b7aa907c6180..b42dde63d1c2 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -75,6 +75,7 @@ import com.android.wm.shell.sizecompatui.SizeCompatUI;
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.transition.RemoteTransitions;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -179,7 +180,7 @@ public abstract class WMShellBaseModule {
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
- Optional<SplitScreen> splitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
@@ -204,7 +205,7 @@ public abstract class WMShellBaseModule {
static Optional<ShellCommandHandler> provideShellCommandHandler(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional,
- Optional<SplitScreen> splitScreenOptional,
+ Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout,
@@ -319,12 +320,21 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
- static Optional<SplitScreen> provideSplitScreen(ShellTaskOrganizer shellTaskOrganizer,
+ static Optional<SplitScreen> provideSplitScreen(
+ Optional<SplitScreenController> splitScreenController) {
+ return splitScreenController.map((controller) -> controller.asSplitScreen());
+ }
+
+ @WMSingleton
+ @Provides
+ static Optional<SplitScreenController> provideSplitScreenController(
+ ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
- RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
+ RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+ @ShellMainThread ShellExecutor mainExecutor) {
if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context,
- rootTaskDisplayAreaOrganizer));
+ rootTaskDisplayAreaOrganizer, mainExecutor));
} else {
return Optional.empty();
}
@@ -388,6 +398,12 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
+ static RemoteTransitions provideRemoteTransitions(Transitions transitions) {
+ return Transitions.asRemoteTransitions(transitions);
+ }
+
+ @WMSingleton
+ @Provides
static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool,
@ShellMainThread ShellExecutor mainExecutor,
@ShellAnimationThread ShellExecutor animExecutor) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
new file mode 100644
index 000000000000..b6729adeb9b3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard;
+
+
+import static com.android.keyguard.KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCase {
+
+ private static final String TEST_MESSAGE = "test message";
+ private static final String TEST_MESSAGE_2 = "test message 2";
+
+ @Mock
+ private DelayableExecutor mExecutor;
+ @Mock
+ private KeyguardIndicationTextView mView;
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ @Captor
+ private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
+
+ private KeyguardIndicationRotateTextViewController mController;
+ private StatusBarStateController.StateListener mStatusBarStateListener;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mView.getTextColors()).thenReturn(ColorStateList.valueOf(Color.WHITE));
+ mController = new KeyguardIndicationRotateTextViewController(mView, mExecutor,
+ mStatusBarStateController, LOCK_SCREEN_MODE_LAYOUT_1);
+ mController.onViewAttached();
+
+ verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
+ mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
+ }
+
+ @Test
+ public void testInitialState_noIndication() {
+ assertFalse(mController.hasIndications());
+ }
+
+ @Test
+ public void testShowOneIndication() {
+ // WHEN we add our first indication
+ final KeyguardIndication indication = createIndication();
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, indication, false);
+
+ // THEN
+ // - we see controller has an indication
+ // - the indication shows immediately since it's the only one
+ // - no next indication is scheduled since there's only one indication
+ assertTrue(mController.hasIndications());
+ verify(mView).switchIndication(indication);
+ verify(mExecutor, never()).executeDelayed(any(), anyLong());
+ }
+
+ @Test
+ public void testShowTwoRotatingMessages() {
+ // GIVEN we already have an indication message
+ mController.updateIndication(
+ INDICATION_TYPE_OWNER_INFO, createIndication(), false);
+ reset(mView);
+
+ // WHEN we have a new indication type to display
+ final KeyguardIndication indication2 = createIndication();
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, indication2, false);
+
+ // THEN
+ // - we don't immediately see the new message until the delay
+ // - next indication is scheduled
+ verify(mView, never()).switchIndication(indication2);
+ verify(mExecutor).executeDelayed(any(), anyLong());
+ }
+
+ @Test
+ public void testUpdateCurrentMessage() {
+ // GIVEN we already have an indication message
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, createIndication(), false);
+ reset(mView);
+
+ // WHEN we have a new message for this indication type to display
+ final KeyguardIndication indication2 = createIndication();
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, indication2, false);
+
+ // THEN
+ // - new indication is updated immediately
+ // - we don't schedule to show anything later
+ verify(mView).switchIndication(indication2);
+ verify(mExecutor, never()).executeDelayed(any(), anyLong());
+ }
+
+ @Test
+ public void testUpdateRotatingMessageForUndisplayedIndication() {
+ // GIVEN we already have two indication messages
+ mController.updateIndication(
+ INDICATION_TYPE_OWNER_INFO, createIndication(), false);
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, createIndication(), false);
+ reset(mView);
+ reset(mExecutor);
+
+ // WHEN we have a new message for an undisplayed indication type
+ final KeyguardIndication indication3 = createIndication();
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, indication3, false);
+
+ // THEN
+ // - we don't immediately update
+ // - we don't schedule to show anything new
+ verify(mView, never()).switchIndication(indication3);
+ verify(mExecutor, never()).executeDelayed(any(), anyLong());
+ }
+
+ @Test
+ public void testUpdateImmediately() {
+ // GIVEN we already have three indication messages
+ mController.updateIndication(
+ INDICATION_TYPE_OWNER_INFO, createIndication(), false);
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, createIndication(), false);
+ mController.updateIndication(
+ INDICATION_TYPE_BATTERY, createIndication(), false);
+ reset(mView);
+ reset(mExecutor);
+
+ // WHEN we have a new message for a currently shown type that we want to show immediately
+ final KeyguardIndication indication4 = createIndication();
+ mController.updateIndication(
+ INDICATION_TYPE_BATTERY, indication4, true);
+
+ // THEN
+ // - we immediately update
+ // - we schedule a new delayable to show the next message later
+ verify(mView).switchIndication(indication4);
+ verify(mExecutor).executeDelayed(any(), anyLong());
+
+ // WHEN an already existing type is updated to show immediately
+ reset(mView);
+ reset(mExecutor);
+ final KeyguardIndication indication5 = createIndication();
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, indication5, true);
+
+ // THEN
+ // - we immediately update
+ // - we schedule a new delayable to show the next message later
+ verify(mView).switchIndication(indication5);
+ verify(mExecutor).executeDelayed(any(), anyLong());
+ }
+
+ @Test
+ public void testTransientIndication() {
+ // GIVEN we already have two indication messages
+ mController.updateIndication(
+ INDICATION_TYPE_OWNER_INFO, createIndication(), false);
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, createIndication(), false);
+ reset(mView);
+ reset(mExecutor);
+
+ // WHEN we have a transient message
+ mController.showTransient(TEST_MESSAGE_2, false);
+
+ // THEN
+ // - we immediately update
+ // - we schedule a new delayable to show the next message later
+ verify(mView).switchIndication(any(KeyguardIndication.class));
+ verify(mExecutor).executeDelayed(any(), anyLong());
+ }
+
+ @Test
+ public void testHideIndicationOneMessage() {
+ // GIVEN we have one indication message
+ mController.updateIndication(
+ INDICATION_TYPE_OWNER_INFO, createIndication(), false);
+
+ // WHEN we hide the current indication type
+ mController.hideIndication(INDICATION_TYPE_OWNER_INFO);
+
+ // THEN we immediately update the text to show no text
+ verify(mView).switchIndication(null);
+ }
+
+ @Test
+ public void testHideIndicationTwoMessages() {
+ // GIVEN we have two indication messages
+ final KeyguardIndication indication1 = createIndication();
+ final KeyguardIndication indication2 = createIndication();
+ mController.updateIndication(
+ INDICATION_TYPE_OWNER_INFO, indication1, false);
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, indication2, false);
+ assertTrue(mController.isNextIndicationScheduled());
+
+ // WHEN we hide the current indication type
+ mController.hideIndication(INDICATION_TYPE_OWNER_INFO);
+
+ // THEN we show the next indication and there's no scheduled next indication
+ verify(mView).switchIndication(indication2);
+ assertFalse(mController.isNextIndicationScheduled());
+ }
+
+ @Test
+ public void testStartDozing() {
+ // WHEN the device is dozing
+ mStatusBarStateListener.onDozingChanged(true);
+
+ // THEN the view is GONE
+ verify(mView).setVisibility(View.GONE);
+ }
+
+ @Test
+ public void testStoppedDozing() {
+ // GIVEN we're dozing & we have an indication message
+ mStatusBarStateListener.onDozingChanged(true);
+ final KeyguardIndication indication = createIndication();
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, indication, false);
+ reset(mView);
+ reset(mExecutor);
+
+ // WHEN the device is no longer dozing
+ mStatusBarStateListener.onDozingChanged(false);
+
+ // THEN show the next message
+ verify(mView).switchIndication(indication);
+ }
+
+ @Test
+ public void testIsDozing() {
+ // GIVEN the device is dozing
+ mStatusBarStateListener.onDozingChanged(true);
+ reset(mView);
+
+ // WHEN an indication is updated
+ final KeyguardIndication indication = createIndication();
+ mController.updateIndication(
+ INDICATION_TYPE_DISCLOSURE, indication, false);
+
+ // THEN no message is shown since we're dozing
+ verify(mView, never()).switchIndication(any());
+ }
+
+ private KeyguardIndication createIndication() {
+ return new KeyguardIndication.Builder()
+ .setMessage(TEST_MESSAGE)
+ .setTextColor(ColorStateList.valueOf(Color.WHITE))
+ .build();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
index 78af20f9db31..ffd747e09e23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -75,6 +75,7 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase {
mFakeSettings = new FakeSettings();
mTile = new ReduceBrightColorsTile(
+ true,
mHost,
mTestableLooper.getLooper(),
new Handler(mTestableLooper.getLooper()),
@@ -95,7 +96,6 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase {
assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);
assertEquals(mTile.getState().label.toString(),
mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
- assertEquals(mTile.getState().secondaryLabel.toString(), "");
}
@Test
@@ -128,13 +128,5 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase {
assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
assertEquals(mTile.getState().label.toString(),
mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
-
- final int intensity = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mUserTracker.getUserId());
-
- assertEquals(
- mContext.getString(
- R.string.quick_settings_reduce_bright_colors_secondary_label, intensity),
- mTile.getState().secondaryLabel.toString());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
index 451c78fd1202..6d2b8e415e96 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
@@ -43,7 +43,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
-import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.transition.RemoteTransitions;
import org.junit.Before;
import org.junit.Test;
@@ -78,7 +78,7 @@ public class OverviewProxyServiceTest extends SysuiTestCase {
@Mock private Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional;
@Mock private PackageManager mPackageManager;
@Mock private SysUiState mMockSysUiState;
- @Mock private Transitions mMockTransitions;
+ @Mock private RemoteTransitions mMockTransitions;
@Before
public void setUp() throws RemoteException {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 2c96535b52bd..0cae67427e3b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
@@ -27,13 +29,11 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.Instrumentation;
@@ -51,7 +51,6 @@ import android.os.BatteryManager;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserManager;
-import android.view.View;
import android.view.ViewGroup;
import androidx.test.InstrumentationRegistry;
@@ -60,18 +59,21 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.app.IBatteryStats;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.keyguard.KeyguardIndication;
+import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.WakeLockFake;
import org.junit.After;
@@ -93,6 +95,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
private static final String ORGANIZATION_NAME = "organization";
private String mDisclosureWithOrganization;
+ private String mDisclosureGeneric;
@Mock
private DevicePolicyManager mDevicePolicyManager;
@@ -101,7 +104,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
- private KeyguardIndicationTextView mDisclosure;
+ private KeyguardIndicationTextView mIndicationAreaBottom;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
@@ -118,8 +121,20 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
private IBatteryStats mIBatteryStats;
@Mock
private DockManager mDockManager;
+ @Mock
+ private KeyguardIndicationRotateTextViewController mRotateTextViewController;
@Captor
private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
+ @Captor
+ private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
+ @Captor
+ private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
+ @Captor
+ private ArgumentCaptor<KeyguardIndication> mKeyguardIndicationCaptor;
+ private StatusBarStateController.StateListener mStatusBarStateListener;
+ private BroadcastReceiver mBroadcastReceiver;
+ private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+
private KeyguardIndicationTextView mTextView;
private KeyguardIndicationController mController;
@@ -140,15 +155,15 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
ORGANIZATION_NAME);
+ mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
- when(mIndicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure))
- .thenReturn(mDisclosure);
+ when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom))
+ .thenReturn(mIndicationAreaBottom);
when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
- when(mDisclosure.getAlpha()).thenReturn(1f);
mWakeLock = new WakeLockFake();
mWakeLockBuilder = new WakeLockFake.Builder(mContext);
@@ -168,11 +183,15 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mController = new KeyguardIndicationController(mContext, mWakeLockBuilder,
mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
- mUserManager);
+ mUserManager, mExecutor);
mController.setIndicationArea(mIndicationArea);
+ verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
+ mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
+ verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
+ mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
+ mController.mRotateTextViewController = mRotateTextViewController;
mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
clearInvocations(mIBatteryStats);
- verify(mDisclosure).getAlpha();
}
@Test
@@ -223,7 +242,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
createController();
verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
mController.setVisible(true);
- mController.setDozing(true);
+ mStatusBarStateListener.onDozingChanged(true);
mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR);
});
@@ -241,7 +260,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
createController();
verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
mController.setVisible(true);
- mController.setDozing(true);
+ mStatusBarStateListener.onDozingChanged(true);
mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
});
@@ -255,136 +274,108 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
@Test
public void disclosure_unmanaged() {
+ createController();
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(false);
- createController();
+ sendUpdateDisclosureBroadcast();
- verify(mDisclosure).setVisibility(View.GONE);
- verifyNoMoreInteractions(mDisclosure);
+ verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_DISCLOSURE);
+ verify(mRotateTextViewController, never()).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
+ any(), anyBoolean());
}
@Test
- public void disclosure_deviceOwner_noOwnerName() {
+ public void disclosure_deviceOwner_noOrganizationName() {
+ createController();
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
- createController();
+ sendUpdateDisclosureBroadcast();
- verify(mDisclosure).setVisibility(View.VISIBLE);
- verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
- verifyNoMoreInteractions(mDisclosure);
+ verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
+ mKeyguardIndicationCaptor.capture(), eq(false));
+ assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
+ .isEqualTo(mDisclosureGeneric);
}
@Test
- public void disclosure_orgOwnedDeviceWithManagedProfile_noOwnerName() {
+ public void disclosure_orgOwnedDeviceWithManagedProfile_noOrganizationName() {
+ createController();
when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(true);
when(mUserManager.getProfiles(anyInt())).thenReturn(Collections.singletonList(
new UserInfo(10, /* name */ null, /* flags */ FLAG_MANAGED_PROFILE)));
when(mDevicePolicyManager.getOrganizationNameForUser(eq(10))).thenReturn(null);
- createController();
-
- verify(mDisclosure).setVisibility(View.VISIBLE);
- verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
- verifyNoMoreInteractions(mDisclosure);
- }
-
- @Test
- public void disclosure_hiddenWhenDozing() {
- when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
- when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
- createController();
-
- mController.setVisible(true);
- mController.onDozeAmountChanged(1, 1);
- mController.setDozing(true);
+ sendUpdateDisclosureBroadcast();
- verify(mDisclosure).setVisibility(View.VISIBLE);
- verify(mDisclosure).setAlpha(0f);
- verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
- verifyNoMoreInteractions(mDisclosure);
+ verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
+ mKeyguardIndicationCaptor.capture(), eq(false));
+ assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
+ .isEqualTo(mDisclosureGeneric);
}
@Test
- public void disclosure_visibleWhenDozing() {
- when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
- when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
+ public void disclosure_deviceOwner_withOrganizationName() {
createController();
-
- mController.setVisible(true);
- mController.onDozeAmountChanged(0, 0);
- mController.setDozing(false);
-
- verify(mDisclosure).setVisibility(View.VISIBLE);
- verify(mDisclosure).setAlpha(1f);
- verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
- verifyNoMoreInteractions(mDisclosure);
- }
-
- @Test
- public void disclosure_deviceOwner_withOwnerName() {
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
- createController();
+ sendUpdateDisclosureBroadcast();
- verify(mDisclosure).setVisibility(View.VISIBLE);
- verify(mDisclosure).switchIndication(mDisclosureWithOrganization);
- verifyNoMoreInteractions(mDisclosure);
+ verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
+ mKeyguardIndicationCaptor.capture(), eq(false));
+ assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
+ .isEqualTo(mDisclosureWithOrganization);
}
@Test
- public void disclosure_orgOwnedDeviceWithManagedProfile_withOwnerName() {
+ public void disclosure_orgOwnedDeviceWithManagedProfile_withOrganizationName() {
+ createController();
when(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).thenReturn(true);
when(mUserManager.getProfiles(anyInt())).thenReturn(Collections.singletonList(
new UserInfo(10, /* name */ null, FLAG_MANAGED_PROFILE)));
when(mDevicePolicyManager.getOrganizationNameForUser(eq(10))).thenReturn(ORGANIZATION_NAME);
- createController();
+ sendUpdateDisclosureBroadcast();
- verify(mDisclosure).setVisibility(View.VISIBLE);
- verify(mDisclosure).switchIndication(mDisclosureWithOrganization);
- verifyNoMoreInteractions(mDisclosure);
+ verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
+ mKeyguardIndicationCaptor.capture(), eq(false));
+ assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
+ .isEqualTo(mDisclosureWithOrganization);
}
@Test
public void disclosure_updateOnTheFly() {
- ArgumentCaptor<BroadcastReceiver> receiver = ArgumentCaptor.forClass(
- BroadcastReceiver.class);
- doNothing().when(mBroadcastDispatcher).registerReceiver(receiver.capture(), any());
-
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
createController();
- final KeyguardUpdateMonitorCallback monitor = mController.getKeyguardCallback();
- reset(mDisclosure);
-
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
- receiver.getValue().onReceive(mContext, new Intent());
+ sendUpdateDisclosureBroadcast();
- verify(mDisclosure).setVisibility(View.VISIBLE);
- verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
- verifyNoMoreInteractions(mDisclosure);
- reset(mDisclosure);
+ verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
+ mKeyguardIndicationCaptor.capture(), eq(false));
+ assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
+ .isEqualTo(mDisclosureGeneric);
+ reset(mRotateTextViewController);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
- receiver.getValue().onReceive(mContext, new Intent());
+ sendUpdateDisclosureBroadcast();
- verify(mDisclosure).setVisibility(View.VISIBLE);
- verify(mDisclosure).switchIndication(mDisclosureWithOrganization);
- verifyNoMoreInteractions(mDisclosure);
- reset(mDisclosure);
+ verify(mRotateTextViewController).updateIndication(eq(INDICATION_TYPE_DISCLOSURE),
+ mKeyguardIndicationCaptor.capture(), eq(false));
+ assertThat(mKeyguardIndicationCaptor.getValue().getMessage())
+ .isEqualTo(mDisclosureWithOrganization);
+ reset(mRotateTextViewController);
when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
- receiver.getValue().onReceive(mContext, new Intent());
+ sendUpdateDisclosureBroadcast();
- verify(mDisclosure).setVisibility(View.GONE);
- verifyNoMoreInteractions(mDisclosure);
+ verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_DISCLOSURE);
}
@Test
public void transientIndication_holdsWakeLock_whenDozing() {
createController();
- mController.setDozing(true);
+ mStatusBarStateListener.onDozingChanged(true);
mController.showTransientIndication("Test");
assertTrue(mWakeLock.isHeld());
@@ -394,7 +385,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
public void transientIndication_releasesWakeLock_afterHiding() {
createController();
- mController.setDozing(true);
+ mStatusBarStateListener.onDozingChanged(true);
mController.showTransientIndication("Test");
mController.hideTransientIndication();
@@ -406,7 +397,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mInstrumentation.runOnMainSync(() -> {
createController();
- mController.setDozing(true);
+ mStatusBarStateListener.onDozingChanged(true);
mController.showTransientIndication("Test");
mController.hideTransientIndicationDelayed(0);
});
@@ -425,7 +416,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mController.setVisible(true);
mController.showTransientIndication("Test");
- mController.setDozing(true);
+ mStatusBarStateListener.onDozingChanged(true);
assertThat(mTextView.getText()).isEqualTo("Test");
assertThat(mTextView.getCurrentTextColor()).isEqualTo(Color.WHITE);
@@ -442,7 +433,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message,
BiometricSourceType.FACE);
assertThat(mTextView.getText()).isEqualTo(message);
- mController.setDozing(true);
+ mStatusBarStateListener.onDozingChanged(true);
assertThat(mTextView.getText()).isNotEqualTo(message);
}
@@ -457,7 +448,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
"A message", BiometricSourceType.FACE);
assertThat(mTextView.getText()).isEqualTo(message);
- mController.setDozing(true);
+ mStatusBarStateListener.onDozingChanged(true);
assertThat(mTextView.getText()).isNotEqualTo(message);
}
@@ -528,8 +519,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
public void setDozing_noIBatteryCalls() throws RemoteException {
createController();
mController.setVisible(true);
- mController.setDozing(true);
- mController.setDozing(false);
+ mStatusBarStateListener.onDozingChanged(true);
+ mStatusBarStateListener.onDozingChanged(false);
verify(mIBatteryStats, never()).computeChargeTimeRemaining();
}
@@ -537,7 +528,6 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
public void updateMonitor_listener() {
createController();
verify(mKeyguardStateController).addCallback(eq(mController));
- verify(mStatusBarStateController).addCallback(eq(mController));
verify(mKeyguardUpdateMonitor, times(2)).registerCallback(any());
}
@@ -612,10 +602,14 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
0 /* maxChargingWattage */, true /* present */);
mController.getKeyguardCallback().onRefreshBatteryInfo(status);
- mController.setDozing(true);
+ mStatusBarStateListener.onDozingChanged(true);
mController.setVisible(true);
String percentage = NumberFormat.getPercentInstance().format(90 / 100f);
assertThat(mTextView.getText()).isEqualTo(percentage);
}
+
+ private void sendUpdateDisclosureBroadcast() {
+ mBroadcastReceiver.onReceive(mContext, new Intent());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index fa253e62ef0a..b9fd75ef5fda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -35,6 +35,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.tuner.TunerService;
@@ -57,6 +58,7 @@ public class DozeParametersTest extends SysuiTestCase {
@Mock private PowerManager mPowerManager;
@Mock private TunerService mTunerService;
@Mock private BatteryController mBatteryController;
+ @Mock private FeatureFlags mFeatureFlags;
@Before
public void setup() {
@@ -67,7 +69,8 @@ public class DozeParametersTest extends SysuiTestCase {
mAlwaysOnDisplayPolicy,
mPowerManager,
mBatteryController,
- mTunerService
+ mTunerService,
+ mFeatureFlags
);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
index 0e775047aef7..6068f0d17720 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
@@ -51,21 +51,21 @@ public class KeyguardIndicationTextViewTest extends SysuiTestCase {
@Test
public void switchIndication_null_hideIndication() {
- mKeyguardIndicationTextView.switchIndication(null /* text */);
+ mKeyguardIndicationTextView.switchIndication(null /* text */, null);
assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("");
}
@Test
public void switchIndication_emptyText_hideIndication() {
- mKeyguardIndicationTextView.switchIndication("" /* text */);
+ mKeyguardIndicationTextView.switchIndication("" /* text */, null);
assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("");
}
@Test
public void switchIndication_newText_updateProperly() {
- mKeyguardIndicationTextView.switchIndication("test_indication" /* text */);
+ mKeyguardIndicationTextView.switchIndication("test_indication" /* text */, null);
assertThat(mKeyguardIndicationTextView.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("test_indication");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index cae488a561a2..253460db0d07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -97,6 +97,7 @@ import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -258,6 +259,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private DemoModeController mDemoModeController;
@Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
@Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
+ @Mock private FeatureFlags mFeatureFlags;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private InitController mInitController = new InitController();
@@ -418,7 +420,8 @@ public class StatusBarTest extends SysuiTestCase {
mNotificationShadeDepthControllerLazy,
mStatusBarTouchableRegionManager,
mNotificationIconAreaController,
- mBrightnessSliderFactory);
+ mBrightnessSliderFactory,
+ mFeatureFlags);
when(mNotificationShadeWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
mLockIconContainer);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 2626654aabf2..a9e8ea03eab8 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -372,12 +372,11 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect
@Override
public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
- final boolean isTouchableDisplay = mWindowManagerService.isTouchableDisplay(displayId);
synchronized (mLock) {
if (mSecurityPolicy.canPerformGestures(this)) {
MotionEventInjector motionEventInjector =
mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId);
- if (motionEventInjector != null && isTouchableDisplay) {
+ if (mWindowManagerService.isTouchOrFaketouchDevice()) {
motionEventInjector.injectEvents(
gestureSteps.getList(), mServiceInterface, sequence, displayId);
} else {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index e4a86c3744ce..eff410caa2d4 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -2647,6 +2647,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
info.icon = activityInfo.getIconResource();
info.previewImage = sa.getResourceId(
com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
+ info.previewLayout = sa.getResourceId(
+ com.android.internal.R.styleable.AppWidgetProviderInfo_previewLayout, 0);
info.autoAdvanceViewId = sa.getResourceId(
com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
info.resizeMode = sa.getInt(
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 55e3ef2e427f..96b69dcc45d6 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -17,9 +17,17 @@
package com.android.server.companion;
+import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
+import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
+import static android.content.Context.BIND_IMPORTANT;
+import static android.content.pm.PackageManager.MATCH_ALL;
+
+import static com.android.internal.util.CollectionUtils.any;
import static com.android.internal.util.CollectionUtils.emptyIfNull;
+import static com.android.internal.util.CollectionUtils.filter;
import static com.android.internal.util.CollectionUtils.find;
import static com.android.internal.util.CollectionUtils.forEach;
+import static com.android.internal.util.CollectionUtils.map;
import static com.android.internal.util.FunctionalUtils.uncheckExceptions;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -40,22 +48,32 @@ import android.app.PendingIntent;
import android.app.role.RoleManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
import android.companion.Association;
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
+import android.companion.CompanionDeviceService;
import android.companion.DeviceNotAssociatedException;
import android.companion.ICompanionDeviceDiscoveryService;
import android.companion.ICompanionDeviceManager;
+import android.companion.ICompanionDeviceService;
import android.companion.IFindDeviceCallback;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.net.NetworkPolicyManager;
import android.os.Binder;
@@ -77,6 +95,7 @@ import android.permission.PermissionControllerManager;
import android.provider.Settings;
import android.provider.SettingsStringUtil.ComponentNameSet;
import android.text.BidiFormatter;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.ExceptionUtils;
@@ -115,6 +134,7 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -135,6 +155,9 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
".DeviceDiscoveryService");
+ private static final long DEVICE_DISAPPEARED_TIMEOUT_MS = 10 * 1000;
+ private static final long DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS = 10 * 60 * 1000;
+
private static final boolean DEBUG = false;
private static final String LOG_TAG = "CompanionDeviceManagerService";
@@ -146,18 +169,23 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
private static final String XML_ATTR_PACKAGE = "package";
private static final String XML_ATTR_DEVICE = "device";
private static final String XML_ATTR_PROFILE = "profile";
- private static final String XML_ATTR_PERSISTENT_PROFILE_GRANTS = "persistent_profile_grants";
+ private static final String XML_ATTR_NOTIFY_DEVICE_NEARBY = "notify_device_nearby";
private static final String XML_FILE_NAME = "companion_device_manager_associations.xml";
private final CompanionDeviceManagerImpl mImpl;
private final ConcurrentMap<Integer, AtomicFile> mUidToStorage = new ConcurrentHashMap<>();
private PowerWhitelistManager mPowerWhitelistManager;
private PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>> mServiceConnectors;
+ /** userId -> packageName -> serviceConnector */
+ private PerUser<ArrayMap<String, ServiceConnector<ICompanionDeviceService>>>
+ mDeviceListenerServiceConnectors;
private IAppOpsService mAppOpsManager;
private RoleManager mRoleManager;
private BluetoothAdapter mBluetoothAdapter;
+ private UserManager mUserManager;
private IFindDeviceCallback mFindDeviceCallback;
+ private ScanCallback mBleScanCallback = new BleScanCallback();
private AssociationRequest mRequest;
private String mCallingPackage;
private AndroidFuture<Association> mOngoingDeviceDiscovery;
@@ -165,9 +193,16 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
private BluetoothDeviceConnectedListener mBluetoothDeviceConnectedListener =
new BluetoothDeviceConnectedListener();
+ private BleStateBroadcastReceiver mBleStateBroadcastReceiver = new BleStateBroadcastReceiver();
private List<String> mCurrentlyConnectedDevices = new ArrayList<>();
+ private ArrayMap<String, Date> mDevicesLastNearby = new ArrayMap<>();
+ private UnbindDeviceListenersRunnable
+ mUnbindDeviceListenersRunnable = new UnbindDeviceListenersRunnable();
+ private ArrayMap<String, TriggerDeviceDisappearedRunnable> mTriggerDeviceDisappearedRunnables =
+ new ArrayMap<>();
private final Object mLock = new Object();
+ private final Handler mMainHandler = Handler.getMain();
/** userId -> [association] */
@GuardedBy("mLock")
@@ -189,6 +224,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mPermissionControllerManager = requireNonNull(
context.getSystemService(PermissionControllerManager.class));
+ mUserManager = context.getSystemService(UserManager.class);
Intent serviceIntent = new Intent().setComponent(SERVICE_TO_BIND_TO);
mServiceConnectors = new PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>>() {
@@ -201,6 +237,16 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
};
+ mDeviceListenerServiceConnectors = new PerUser<ArrayMap<String,
+ ServiceConnector<ICompanionDeviceService>>>() {
+ @NonNull
+ @Override
+ protected ArrayMap<String, ServiceConnector<ICompanionDeviceService>> create(
+ int userId) {
+ return new ArrayMap<>();
+ }
+ };
+
registerPackageMonitor();
}
@@ -208,10 +254,13 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
new PackageMonitor() {
@Override
public void onPackageRemoved(String packageName, int uid) {
+ int userId = getChangingUserId();
updateAssociations(
as -> CollectionUtils.filter(as,
a -> !Objects.equals(a.getPackageName(), packageName)),
- getChangingUserId());
+ userId);
+
+ unbindDevicePresenceListener(packageName, userId);
}
@Override
@@ -225,6 +274,15 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}.register(getContext(), FgThread.get().getLooper(), UserHandle.ALL, true);
}
+ private void unbindDevicePresenceListener(String packageName, int userId) {
+ ServiceConnector<ICompanionDeviceService> deviceListener =
+ mDeviceListenerServiceConnectors.forUser(userId)
+ .remove(packageName);
+ if (deviceListener != null) {
+ deviceListener.unbind();
+ }
+ }
+
@Override
public void onStart() {
publishBinderService(Context.COMPANION_DEVICE_SERVICE, mImpl);
@@ -233,11 +291,17 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ // Init Bluetooth
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter != null) {
mBluetoothAdapter.registerBluetoothConnectionCallback(
getContext().getMainExecutor(),
mBluetoothDeviceConnectedListener);
+ getContext().registerReceiver(
+ mBleStateBroadcastReceiver, mBleStateBroadcastReceiver.mIntentFilter);
+ initBleScanning();
+ } else {
+ Log.w(LOG_TAG, "No BluetoothAdapter available");
}
}
}
@@ -287,7 +351,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
@Override
public void binderDied() {
- Handler.getMain().post(this::cleanup);
+ mMainHandler.post(this::cleanup);
}
private void cleanup() {
@@ -399,7 +463,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
checkCallerIsSystemOr(callingPackage, userId);
checkUsesFeature(callingPackage, getCallingUserId());
}
- return new ArrayList<>(CollectionUtils.map(
+ return new ArrayList<>(map(
getAllAssociations(userId, callingPackage),
a -> a.getDeviceMacAddress()));
}
@@ -497,7 +561,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
return true;
}
- return CollectionUtils.any(
+ return any(
getAllAssociations(userId, packageName),
a -> Objects.equals(a.getDeviceMacAddress(), macAddress));
}
@@ -506,22 +570,18 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
public void registerDevicePresenceListenerService(
String packageName, String deviceAddress)
throws RemoteException {
- checkCanRegisterObserverService(packageName, deviceAddress);
-
- //TODO(eugenesusla) implement
+ registerDevicePresenceListenerActive(packageName, deviceAddress, true);
}
@Override
public void unregisterDevicePresenceListenerService(
String packageName, String deviceAddress)
throws RemoteException {
- checkCanRegisterObserverService(packageName, deviceAddress);
-
- //TODO(eugenesusla) implement
+ registerDevicePresenceListenerActive(packageName, deviceAddress, false);
}
- private void checkCanRegisterObserverService(String packageName, String deviceAddress)
- throws RemoteException {
+ private void registerDevicePresenceListenerActive(String packageName, String deviceAddress,
+ boolean active) throws RemoteException {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE,
"[un]registerDevicePresenceListenerService");
@@ -537,6 +597,20 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
+ " is not associated with device " + deviceAddress
+ " for user " + userId));
}
+
+ updateAssociations(associations -> map(associations, association -> {
+ if (Objects.equals(association.getPackageName(), packageName)
+ && Objects.equals(association.getDeviceMacAddress(), deviceAddress)) {
+ return new Association(
+ association.getUserId(),
+ association.getDeviceMacAddress(),
+ association.getPackageName(),
+ association.getDeviceProfile(),
+ active /* notifyOnDeviceNearby */);
+ } else {
+ return association;
+ }
+ }));
}
private void checkCanCallNotificationApi(String callingPackage) throws RemoteException {
@@ -693,6 +767,10 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
if (mCurrentlyConnectedDevices.contains(association.getDeviceMacAddress())) {
grantDeviceProfile(association);
}
+
+ if (association.isNotifyOnDeviceNearby()) {
+ restartBleScan();
+ }
}
private void exemptFromAutoRevoke(String packageName, int uid) {
@@ -795,9 +873,9 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
association.getDeviceMacAddress());
if (association.getDeviceProfile() != null) {
tag.attribute(null, XML_ATTR_PROFILE, association.getDeviceProfile());
- tag.attribute(null, XML_ATTR_PERSISTENT_PROFILE_GRANTS,
+ tag.attribute(null, XML_ATTR_NOTIFY_DEVICE_NEARBY,
Boolean.toString(
- association.isKeepProfilePrivilegesWhenDeviceAway()));
+ association.isNotifyOnDeviceNearby()));
}
tag.endTag(null, XML_TAG_ASSOCIATION);
});
@@ -835,7 +913,12 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
private List<UserInfo> getAllUsers() {
- return getContext().getSystemService(UserManager.class).getUsers();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mUserManager.getUsers();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Nullable
@@ -845,6 +928,19 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
a -> Objects.equals(packageFilter, a.getPackageName()));
}
+ private Set<Association> getAllAssociations() {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ ArraySet<Association> result = new ArraySet<>();
+ for (UserInfo user : mUserManager.getAliveUsers()) {
+ result.addAll(getAllAssociations(user.id));
+ }
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
private Set<Association> readAllAssociations(int userId) {
final AtomicFile file = getStorageFileForUser(userId);
@@ -865,7 +961,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
final String profile = parser.getAttributeValue(null, XML_ATTR_PROFILE);
final boolean persistentGrants = Boolean.valueOf(
- parser.getAttributeValue(null, XML_ATTR_PERSISTENT_PROFILE_GRANTS));
+ parser.getAttributeValue(null, XML_ATTR_NOTIFY_DEVICE_NEARBY));
if (appPackage == null || deviceAddress == null) continue;
@@ -896,6 +992,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
}
}
+
+ onDeviceNearby(address);
}
private void grantDeviceProfile(Association association) {
@@ -919,6 +1017,267 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
void onDeviceDisconnected(String address) {
mCurrentlyConnectedDevices.remove(address);
+
+ onDeviceDisappeared(address);
+ }
+
+ private ServiceConnector<ICompanionDeviceService> getDeviceListenerServiceConnector(
+ Association a) {
+ return mDeviceListenerServiceConnectors.forUser(a.getUserId()).computeIfAbsent(
+ a.getPackageName(),
+ pkg -> createDeviceListenerServiceConnector(a));
+ }
+
+ private ServiceConnector<ICompanionDeviceService> createDeviceListenerServiceConnector(
+ Association a) {
+ List<ResolveInfo> resolveInfos = getContext().getPackageManager().queryIntentServicesAsUser(
+ new Intent(CompanionDeviceService.SERVICE_INTERFACE), MATCH_ALL, a.getUserId());
+ List<ResolveInfo> packageResolveInfos = filter(resolveInfos,
+ info -> Objects.equals(info.serviceInfo.packageName, a.getPackageName()));
+ if (packageResolveInfos.size() != 1) {
+ Log.w(LOG_TAG, "Device presence listener package must have exactly one "
+ + "CompanionDeviceService, but " + a.getPackageName()
+ + " has " + packageResolveInfos.size());
+ return new ServiceConnector.NoOp<>();
+ }
+ ComponentName componentName = packageResolveInfos.get(0).serviceInfo.getComponentName();
+ Log.i(LOG_TAG, "Initializing CompanionDeviceService binding for " + componentName);
+ return new ServiceConnector.Impl<>(getContext(),
+ new Intent(CompanionDeviceService.SERVICE_INTERFACE).setComponent(componentName),
+ BIND_IMPORTANT,
+ a.getUserId(),
+ ICompanionDeviceService.Stub::asInterface);
+ }
+
+ private class BleScanCallback extends ScanCallback {
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onScanResult(callbackType = "
+ + callbackType + ", result = " + result + ")");
+ }
+
+ onDeviceNearby(result.getDevice().getAddress());
+ }
+
+ @Override
+ public void onBatchScanResults(List<ScanResult> results) {
+ for (int i = 0, size = results.size(); i < size; i++) {
+ onScanResult(CALLBACK_TYPE_ALL_MATCHES, results.get(i));
+ }
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ if (errorCode == SCAN_FAILED_ALREADY_STARTED) {
+ // ignore - this might happen if BT tries to auto-restore scans for us in the
+ // future
+ Log.i(LOG_TAG, "Ignoring BLE scan error: SCAN_FAILED_ALREADY_STARTED");
+ } else {
+ Log.w(LOG_TAG, "Failed to start BLE scan: error " + errorCode);
+ }
+ }
+ }
+
+ private class BleStateBroadcastReceiver extends BroadcastReceiver {
+
+ final IntentFilter mIntentFilter =
+ new IntentFilter(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, -1);
+ int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+ Log.i(LOG_TAG, "Received BT state transition broadcast: "
+ + BluetoothAdapter.nameForState(previousState)
+ + " -> " + BluetoothAdapter.nameForState(newState));
+
+ boolean bleOn = newState == BluetoothAdapter.STATE_ON
+ || newState == BluetoothAdapter.STATE_BLE_ON;
+ if (bleOn) {
+ if (mBluetoothAdapter.getBluetoothLeScanner() != null) {
+ startBleScan();
+ } else {
+ Log.wtf(LOG_TAG, "BLE on, but BluetoothLeScanner == null");
+ }
+ }
+ }
+ }
+
+ private class UnbindDeviceListenersRunnable implements Runnable {
+
+ public String getJobId(String address) {
+ return "CDM_deviceGone_unbind_" + address;
+ }
+
+ @Override
+ public void run() {
+ int size = mDevicesLastNearby.size();
+ for (int i = 0; i < size; i++) {
+ String address = mDevicesLastNearby.keyAt(i);
+ Date lastNearby = mDevicesLastNearby.valueAt(i);
+
+ if (System.currentTimeMillis() - lastNearby.getTime()
+ >= DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS) {
+ for (Association association : getAllAssociations(address)) {
+ if (association.isNotifyOnDeviceNearby()) {
+ getDeviceListenerServiceConnector(association).unbind();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private class TriggerDeviceDisappearedRunnable implements Runnable {
+
+ private final String mAddress;
+
+ TriggerDeviceDisappearedRunnable(String address) {
+ mAddress = address;
+ }
+
+ public void schedule() {
+ mMainHandler.removeCallbacks(this);
+ mMainHandler.postDelayed(this, this, DEVICE_DISAPPEARED_TIMEOUT_MS);
+ }
+
+ @Override
+ public void run() {
+ onDeviceDisappeared(mAddress);
+ }
+ }
+
+ private Set<Association> getAllAssociations(String deviceAddress) {
+ List<UserInfo> aliveUsers = mUserManager.getAliveUsers();
+ Set<Association> result = new ArraySet<>();
+ for (int i = 0, size = aliveUsers.size(); i < size; i++) {
+ UserInfo user = aliveUsers.get(i);
+ for (Association association : getAllAssociations(user.id)) {
+ if (Objects.equals(association.getDeviceMacAddress(), deviceAddress)) {
+ result.add(association);
+ }
+ }
+ }
+ return result;
+ }
+
+ private void onDeviceNearby(String address) {
+ Date timestamp = new Date();
+ Date oldTimestamp = mDevicesLastNearby.put(address, timestamp);
+
+ cancelUnbindDeviceListener(address);
+
+ mTriggerDeviceDisappearedRunnables
+ .computeIfAbsent(address, addr -> new TriggerDeviceDisappearedRunnable(address))
+ .schedule();
+
+ // Avoid spamming the app if device is already known to be nearby
+ boolean justAppeared = oldTimestamp == null
+ || timestamp.getTime() - oldTimestamp.getTime() >= DEVICE_DISAPPEARED_TIMEOUT_MS;
+ if (justAppeared) {
+ for (Association association : getAllAssociations(address)) {
+ if (association.isNotifyOnDeviceNearby()) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Device " + address
+ + " managed by " + association.getPackageName()
+ + " is nearby on " + timestamp);
+ }
+ getDeviceListenerServiceConnector(association).run(
+ service -> service.onDeviceAppeared(association.getDeviceMacAddress()));
+ }
+ }
+ }
+ }
+
+ private void onDeviceDisappeared(String address) {
+ boolean hasDeviceListeners = false;
+ for (Association association : getAllAssociations(address)) {
+ if (association.isNotifyOnDeviceNearby()) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Device " + address
+ + " managed by " + association.getPackageName()
+ + " disappeared; last seen on " + mDevicesLastNearby.get(address));
+ }
+
+ getDeviceListenerServiceConnector(association).run(
+ service -> service.onDeviceDisappeared(address));
+ hasDeviceListeners = true;
+ }
+ }
+
+ cancelUnbindDeviceListener(address);
+ if (hasDeviceListeners) {
+ mMainHandler.postDelayed(
+ mUnbindDeviceListenersRunnable,
+ mUnbindDeviceListenersRunnable.getJobId(address),
+ DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS);
+ }
+ }
+
+ private void cancelUnbindDeviceListener(String address) {
+ mMainHandler.removeCallbacks(
+ mUnbindDeviceListenersRunnable, mUnbindDeviceListenersRunnable.getJobId(address));
+ }
+
+ private void initBleScanning() {
+ Log.i(LOG_TAG, "initBleScanning()");
+
+ boolean bluetoothReady = mBluetoothAdapter.registerServiceLifecycleCallback(
+ new BluetoothAdapter.ServiceLifecycleCallback() {
+ @Override
+ public void onBluetoothServiceUp() {
+ Log.i(LOG_TAG, "Bluetooth stack is up");
+ startBleScan();
+ }
+
+ @Override
+ public void onBluetoothServiceDown() {
+ Log.w(LOG_TAG, "Bluetooth stack is down");
+ }
+ });
+ if (bluetoothReady) {
+ startBleScan();
+ }
+ }
+
+ void startBleScan() {
+ Log.i(LOG_TAG, "startBleScan()");
+
+ List<ScanFilter> filters = getBleScanFilters();
+ if (filters.isEmpty()) {
+ return;
+ }
+ BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
+ if (scanner == null) {
+ Log.w(LOG_TAG, "scanner == null (likely BLE isn't ON yet)");
+ } else {
+ scanner.startScan(
+ filters,
+ new ScanSettings.Builder().setScanMode(SCAN_MODE_BALANCED).build(),
+ mBleScanCallback);
+ }
+ }
+
+ void restartBleScan() {
+ mBluetoothAdapter.getBluetoothLeScanner().stopScan(mBleScanCallback);
+ startBleScan();
+ }
+
+ private List<ScanFilter> getBleScanFilters() {
+ ArrayList<ScanFilter> result = new ArrayList<>();
+ ArraySet<String> addressesSeen = new ArraySet<>();
+ for (Association association : getAllAssociations()) {
+ String address = association.getDeviceMacAddress();
+ if (addressesSeen.contains(address)) {
+ continue;
+ }
+ if (association.isNotifyOnDeviceNearby()) {
+ result.add(new ScanFilter.Builder().setDeviceAddress(address).build());
+ addressesSeen.add(address);
+ }
+ }
+ return result;
}
private AndroidFuture<String> getDeviceProfilePermissionDescription(String deviceProfile) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3933e379e872..2f883517a378 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -45,6 +45,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
@@ -1038,7 +1039,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetworkRanker = new NetworkRanker();
final NetworkRequest defaultInternetRequest = createDefaultInternetRequestForTransport(
-1, NetworkRequest.Type.REQUEST);
- mDefaultRequest = new NetworkRequestInfo(null, defaultInternetRequest, new Binder());
+ mDefaultRequest = new NetworkRequestInfo(null, defaultInternetRequest, new Binder(),
+ null /* attributionTag */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
mDefaultNetworkRequests.add(mDefaultRequest);
mNetworkRequestInfoLogs.log("REGISTER " + mDefaultRequest);
@@ -1246,6 +1248,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
netCap.setSingleUid(uid);
return netCap;
@@ -1255,6 +1258,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
int transportType, NetworkRequest.Type type) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
if (transportType > -1) {
netCap.addTransportType(transportType);
@@ -1308,7 +1312,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- null, networkRequest, new Binder()));
+ null, networkRequest, new Binder(), null /* attributionTag */));
} else {
handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
/* callOnUnavailable */ false);
@@ -1643,7 +1647,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
- int userId, String callingPackageName) {
+ int userId, String callingPackageName, @Nullable String callingAttributionTag) {
// The basic principle is: if an app's traffic could possibly go over a
// network, without the app doing anything multinetwork-specific,
// (hence, by "default"), then include that network's capabilities in
@@ -1674,7 +1678,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
result.put(
nai.network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, mDeps.getCallingUid(), callingPackageName));
+ nc, mDeps.getCallingUid(), callingPackageName,
+ callingAttributionTag));
}
}
@@ -1687,7 +1692,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
result.put(
network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, mDeps.getCallingUid(), callingPackageName));
+ nc, mDeps.getCallingUid(), callingPackageName,
+ callingAttributionTag));
}
}
}
@@ -1762,12 +1768,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@Override
- public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
+ public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName,
+ @Nullable String callingAttributionTag) {
mAppOpsManager.checkPackage(mDeps.getCallingUid(), callingPackageName);
enforceAccessPermission();
return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
getNetworkCapabilitiesInternal(network),
- mDeps.getCallingUid(), callingPackageName);
+ mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
}
@VisibleForTesting
@@ -1786,11 +1793,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
return newNc;
}
- private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName) {
+ private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName,
+ @Nullable String callingAttributionTag) {
final long token = Binder.clearCallingIdentity();
try {
return mLocationPermissionChecker.checkLocationPermission(
- callerPkgName, null /* featureId */, callerUid, null /* message */);
+ callerPkgName, callingAttributionTag, callerUid, null /* message */);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1799,7 +1807,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
@VisibleForTesting
@Nullable
NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) {
+ @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName,
+ @Nullable String callingAttributionTag) {
if (nc == null) {
return null;
}
@@ -1808,7 +1817,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Avoid doing location permission check if the transport info has no location sensitive
// data.
if (nc.getTransportInfo() != null && nc.getTransportInfo().hasLocationSensitiveFields()) {
- hasLocationPermission = hasLocationPermission(callerUid, callerPkgName);
+ hasLocationPermission =
+ hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
newNc = new NetworkCapabilities(nc, hasLocationPermission);
} else {
newNc = new NetworkCapabilities(nc, false /* parcelLocationSensitiveFields */);
@@ -1825,7 +1835,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
if (hasLocationPermission == null) {
// Location permission not checked yet, check now for masking owner UID.
- hasLocationPermission = hasLocationPermission(callerUid, callerPkgName);
+ hasLocationPermission =
+ hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
}
// Reset owner uid if the app has no location permission.
if (!hasLocationPermission) {
@@ -1883,7 +1894,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
final ArrayList<NetworkState> result = new ArrayList<>();
for (Network network : getAllNetworks()) {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai != null) {
+ // TODO: Consider include SUSPENDED networks.
+ if (nai != null && nai.networkInfo.isConnected()) {
// TODO (b/73321673) : NetworkState contains a copy of the
// NetworkCapabilities, which may contain UIDs of apps to which the
// network applies. Should the UIDs be cleared so as not to leak or
@@ -5541,6 +5553,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
final int mPid;
final int mUid;
final Messenger messenger;
+ @Nullable
+ final String mCallingAttributionTag;
/**
* Get the list of UIDs this nri applies to.
@@ -5554,7 +5568,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
return uids;
}
- NetworkRequestInfo(NetworkRequest r, PendingIntent pi) {
+ NetworkRequestInfo(NetworkRequest r, PendingIntent pi,
+ @Nullable String callingAttributionTag) {
mRequests = initializeRequests(r);
ensureAllNetworkRequestsHaveType(mRequests);
mPendingIntent = pi;
@@ -5563,9 +5578,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mCallingAttributionTag = callingAttributionTag;
}
- NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder) {
+ NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder,
+ @Nullable String callingAttributionTag) {
super();
messenger = m;
mRequests = initializeRequests(r);
@@ -5575,6 +5592,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mUid = mDeps.getCallingUid();
mPendingIntent = null;
mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mCallingAttributionTag = callingAttributionTag;
try {
mBinder.linkToDeath(this, 0);
@@ -5584,7 +5602,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
NetworkRequestInfo(NetworkRequest r) {
- this(r, null);
+ this(r, null /* pi */, null /* callingAttributionTag */);
}
// True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
@@ -5777,7 +5795,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
- NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
+ NetworkRequestInfo nri =
+ new NetworkRequestInfo(messenger, networkRequest, binder, callingAttributionTag);
if (DBG) log("requestNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
@@ -5866,7 +5885,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
- NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);
+ NetworkRequestInfo nri =
+ new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
if (DBG) log("pendingRequest for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
nri));
@@ -5910,7 +5930,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, IBinder binder, @NonNull String callingPackageName) {
+ Messenger messenger, IBinder binder, @NonNull String callingPackageName,
+ @Nullable String callingAttributionTag) {
final int callingUid = mDeps.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
@@ -5930,7 +5951,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
- NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
+ NetworkRequestInfo nri =
+ new NetworkRequestInfo(messenger, networkRequest, binder, callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -5939,7 +5961,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
- PendingIntent operation, @NonNull String callingPackageName) {
+ PendingIntent operation, @NonNull String callingPackageName,
+ @Nullable String callingAttributionTag) {
Objects.requireNonNull(operation, "PendingIntent cannot be null.");
final int callingUid = mDeps.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
@@ -5953,7 +5976,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
- NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);
+ NetworkRequestInfo nri =
+ new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
if (VDBG) log("pendingListenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -7168,7 +7192,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, nri.mUid, nrForCallback.getRequestorPackageName()));
+ nc, nri.mUid, nrForCallback.getRequestorPackageName(),
+ nri.mCallingAttributionTag));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid));
// For this notification, arg1 contains the blocked status.
@@ -7187,7 +7212,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, nri.mUid, nrForCallback.getRequestorPackageName()));
+ netCap, nri.mUid, nrForCallback.getRequestorPackageName(),
+ nri.mCallingAttributionTag));
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 7d6515600c2a..1ad0176d3c5b 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -890,7 +890,7 @@ class StorageManagerService extends IStorageManager.Stub
ZramWriteback.scheduleZramWriteback(mContext);
}
- updateTranscodeEnabled();
+ configureTranscoding();
}
/**
@@ -922,7 +922,7 @@ class StorageManagerService extends IStorageManager.Stub
}
}
- private void updateTranscodeEnabled() {
+ private void configureTranscoding() {
// See MediaProvider TranscodeHelper#getBooleanProperty for more information
boolean transcodeEnabled = false;
boolean defaultValue = true;
@@ -935,6 +935,15 @@ class StorageManagerService extends IStorageManager.Stub
"transcode_enabled", defaultValue);
}
SystemProperties.set("sys.fuse.transcode_enabled", String.valueOf(transcodeEnabled));
+
+ if (transcodeEnabled) {
+ LocalServices.getService(ActivityManagerInternal.class)
+ .registerAnrController((packageName, uid) -> {
+ // TODO: Retrieve delay from ExternalStorageService that can check
+ // transcoding status
+ return SystemProperties.getInt("sys.fuse.transcode_anr_delay_ms", 0);
+ });
+ }
}
/**
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index e685ee2899af..1b6b9d70d5ac 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -643,8 +643,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
final Sensor sensor = mSensors.valueAt(i);
final int sensorId = mSensors.keyAt(i);
PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
- sensor.getScheduler().recordCrashState();
- sensor.getScheduler().reset();
+ sensor.onBinderDied();
}
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 640838c6ee04..baeb3fdda67d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -33,7 +33,6 @@ import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.keymaster.HardwareAuthToken;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserManager;
import android.util.Slog;
@@ -63,7 +62,7 @@ import java.util.Map;
/**
* Maintains the state of a single sensor within an instance of the {@link IFace} HAL.
*/
-public class Sensor implements IBinder.DeathRecipient {
+public class Sensor {
private boolean mTestHalEnabled;
@@ -481,7 +480,6 @@ public class Sensor implements IBinder.DeathRecipient {
mTag, mScheduler, sensorId, userId, callback);
final ISession newSession = daemon.createSession(sensorId, userId, resultController);
- newSession.asBinder().linkToDeath(this, 0 /* flags */);
mCurrentSession = new Session(mTag, newSession, userId, resultController);
}
@@ -523,24 +521,21 @@ public class Sensor implements IBinder.DeathRecipient {
proto.end(sensorToken);
}
- @Override
- public void binderDied() {
- Slog.e(mTag, "Binder died");
- mHandler.post(() -> {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
- if (client instanceof Interruptable) {
- Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
- final Interruptable interruptable = (Interruptable) client;
- interruptable.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
- 0 /* vendorCode */);
-
- mScheduler.recordCrashState();
+ public void onBinderDied() {
+ final BaseClientMonitor client = mScheduler.getCurrentClient();
+ if (client instanceof Interruptable) {
+ Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+ final Interruptable interruptable = (Interruptable) client;
+ interruptable.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+
+ FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+ BiometricsProtoEnums.MODALITY_FACE,
+ BiometricsProtoEnums.ISSUE_HAL_DEATH);
+ }
- FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
- BiometricsProtoEnums.MODALITY_FACE,
- BiometricsProtoEnums.ISSUE_HAL_DEATH);
- mCurrentSession = null;
- }
- });
+ mScheduler.recordCrashState();
+ mScheduler.reset();
+ mCurrentSession = null;
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index ced46e140c0a..0bd2f241ed8d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -697,8 +697,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
final Sensor sensor = mSensors.valueAt(i);
final int sensorId = mSensors.keyAt(i);
PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
- sensor.getScheduler().recordCrashState();
- sensor.getScheduler().reset();
+ sensor.onBinderDied();
}
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index f0e7e1cf5d25..7e4ee9e77ab2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -31,7 +31,6 @@ import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.keymaster.HardwareAuthToken;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserManager;
import android.util.Slog;
@@ -65,7 +64,7 @@ import java.util.Map;
* {@link android.hardware.biometrics.fingerprint.IFingerprint} HAL.
*/
@SuppressWarnings("deprecation")
-class Sensor implements IBinder.DeathRecipient {
+class Sensor {
private boolean mTestHalEnabled;
@@ -461,7 +460,6 @@ class Sensor implements IBinder.DeathRecipient {
mTag, mScheduler, sensorId, userId, callback);
final ISession newSession = daemon.createSession(sensorId, userId, resultController);
- newSession.asBinder().linkToDeath(this, 0 /* flags */);
mCurrentSession = new Session(mTag, newSession, userId, resultController);
}
@@ -503,24 +501,21 @@ class Sensor implements IBinder.DeathRecipient {
proto.end(sensorToken);
}
- @Override
- public void binderDied() {
- Slog.e(mTag, "Binder died");
- mHandler.post(() -> {
- final BaseClientMonitor client = mScheduler.getCurrentClient();
- if (client instanceof Interruptable) {
- Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
- final Interruptable interruptable = (Interruptable) client;
- interruptable.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
- 0 /* vendorCode */);
-
- mScheduler.recordCrashState();
+ public void onBinderDied() {
+ final BaseClientMonitor client = mScheduler.getCurrentClient();
+ if (client instanceof Interruptable) {
+ Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+ final Interruptable interruptable = (Interruptable) client;
+ interruptable.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+
+ FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT,
+ BiometricsProtoEnums.ISSUE_HAL_DEATH);
+ }
- FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
- BiometricsProtoEnums.MODALITY_FINGERPRINT,
- BiometricsProtoEnums.ISSUE_HAL_DEATH);
- mCurrentSession = null;
- }
- });
+ mScheduler.recordCrashState();
+ mScheduler.reset();
+ mCurrentSession = null;
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 0950d5dd076f..01fee5645475 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2579,14 +2579,14 @@ public final class DisplayManagerService extends SystemService {
}
@Override // Binder call
- public void setTemporaryBrightness(float brightness) {
+ public void setTemporaryBrightness(int displayId, float brightness) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
"Permission required to set the display's brightness");
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
- mDisplayPowerControllers.get(Display.DEFAULT_DISPLAY)
+ mDisplayPowerControllers.get(displayId)
.setTemporaryBrightness(brightness);
}
} finally {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7e6a13766746..73ebb2e48037 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -105,17 +105,18 @@ final class LocalDisplayAdapter extends DisplayAdapter {
Slog.w(TAG, "No valid info found for display device " + physicalDisplayId);
return;
}
- SurfaceControl.DisplayConfig[] configs = SurfaceControl.getDisplayConfigs(displayToken);
- if (configs == null) {
- // There are no valid configs for this device, so we can't use it
- Slog.w(TAG, "No valid configs found for display device " + physicalDisplayId);
+ SurfaceControl.DisplayMode[] displayModes =
+ SurfaceControl.getDisplayModes(displayToken);
+ if (displayModes == null) {
+ // There are no valid modes for this device, so we can't use it
+ Slog.w(TAG, "No valid modes found for display device " + physicalDisplayId);
return;
}
- int activeConfig = SurfaceControl.getActiveConfig(displayToken);
- if (activeConfig < 0) {
- // There is no active config, and for now we don't have the
+ int activeDisplayMode = SurfaceControl.getActiveDisplayMode(displayToken);
+ if (activeDisplayMode < 0) {
+ // There is no active mode, and for now we don't have the
// policy to set one.
- Slog.w(TAG, "No active config found for display device " + physicalDisplayId);
+ Slog.w(TAG, "No active mode found for display device " + physicalDisplayId);
return;
}
int activeColorMode = SurfaceControl.getActiveColorMode(displayToken);
@@ -127,8 +128,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
physicalDisplayId);
activeColorMode = Display.COLOR_MODE_INVALID;
}
- SurfaceControl.DesiredDisplayConfigSpecs configSpecs =
- SurfaceControl.getDesiredDisplayConfigSpecs(displayToken);
+ SurfaceControl.DesiredDisplayModeSpecs modeSpecsSpecs =
+ SurfaceControl.getDesiredDisplayModeSpecs(displayToken);
int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken);
Display.HdrCapabilities hdrCapabilities =
SurfaceControl.getHdrCapabilities(displayToken);
@@ -136,13 +137,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
if (device == null) {
// Display was added.
final boolean isDefaultDisplay = mDevices.size() == 0;
- device = new LocalDisplayDevice(displayToken, physicalDisplayId, info,
- configs, activeConfig, configSpecs, colorModes, activeColorMode,
+ device = new LocalDisplayDevice(displayToken, physicalDisplayId, info, displayModes,
+ activeDisplayMode, modeSpecsSpecs, colorModes, activeColorMode,
hdrCapabilities, isDefaultDisplay);
mDevices.put(physicalDisplayId, device);
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
- } else if (device.updateDisplayPropertiesLocked(info, configs, activeConfig,
- configSpecs, colorModes, activeColorMode, hdrCapabilities)) {
+ } else if (device.updateDisplayPropertiesLocked(info, displayModes, activeDisplayMode,
+ modeSpecsSpecs, colorModes, activeColorMode, hdrCapabilities)) {
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
} else {
@@ -189,12 +190,12 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// This is only set in the runnable returned from requestDisplayStateLocked.
private float mBrightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private int mDefaultModeId;
- private int mDefaultConfigGroup;
+ private int mDefaultModeGroup;
private int mActiveModeId;
private DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs =
new DisplayModeDirector.DesiredDisplayModeSpecs();
private boolean mDisplayModeSpecsInvalid;
- private int mActiveConfigId;
+ private int mActiveDisplayModeId;
private int mActiveColorMode;
private Display.HdrCapabilities mHdrCapabilities;
private boolean mAllmSupported;
@@ -204,7 +205,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private boolean mSidekickActive;
private SidekickInternal mSidekickInternal;
private SurfaceControl.DisplayInfo mDisplayInfo;
- private SurfaceControl.DisplayConfig[] mDisplayConfigs;
+ private SurfaceControl.DisplayMode[] mDisplayModes;
private Spline mSystemBrightnessToNits;
private Spline mNitsToHalBrightness;
private DisplayDeviceConfig mDisplayDeviceConfig;
@@ -213,15 +214,15 @@ final class LocalDisplayAdapter extends DisplayAdapter {
new DisplayEventReceiver.FrameRateOverride[0];
LocalDisplayDevice(IBinder displayToken, long physicalDisplayId,
- SurfaceControl.DisplayInfo info, SurfaceControl.DisplayConfig[] configs,
- int activeConfigId, SurfaceControl.DesiredDisplayConfigSpecs configSpecs,
+ SurfaceControl.DisplayInfo info, SurfaceControl.DisplayMode[] displayModes,
+ int activeDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs,
int[] colorModes, int activeColorMode, Display.HdrCapabilities hdrCapabilities,
boolean isDefaultDisplay) {
super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId);
mPhysicalDisplayId = physicalDisplayId;
mIsDefaultDisplay = isDefaultDisplay;
- updateDisplayPropertiesLocked(info, configs, activeConfigId, configSpecs, colorModes,
- activeColorMode, hdrCapabilities);
+ updateDisplayPropertiesLocked(info, displayModes, activeDisplayModeId, modeSpecs,
+ colorModes, activeColorMode, hdrCapabilities);
mSidekickInternal = LocalServices.getService(SidekickInternal.class);
mBacklightAdapter = new BacklightAdapter(displayToken, isDefaultDisplay);
mAllmSupported = SurfaceControl.getAutoLowLatencyModeSupport(displayToken);
@@ -241,10 +242,11 @@ final class LocalDisplayAdapter extends DisplayAdapter {
* Returns true if there is a change.
**/
public boolean updateDisplayPropertiesLocked(SurfaceControl.DisplayInfo info,
- SurfaceControl.DisplayConfig[] configs,
- int activeConfigId, SurfaceControl.DesiredDisplayConfigSpecs configSpecs,
+ SurfaceControl.DisplayMode[] displayModes,
+ int activeDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs,
int[] colorModes, int activeColorMode, Display.HdrCapabilities hdrCapabilities) {
- boolean changed = updateDisplayConfigsLocked(configs, activeConfigId, configSpecs);
+ boolean changed = updateDisplayModesLocked(
+ displayModes, activeDisplayModeId, modeSpecs);
changed |= updateDisplayInfo(info);
changed |= updateColorModesLocked(colorModes, activeColorMode);
changed |= updateHdrCapabilitiesLocked(hdrCapabilities);
@@ -255,35 +257,35 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return changed;
}
- public boolean updateDisplayConfigsLocked(
- SurfaceControl.DisplayConfig[] configs, int activeConfigId,
- SurfaceControl.DesiredDisplayConfigSpecs configSpecs) {
- mDisplayConfigs = Arrays.copyOf(configs, configs.length);
- mActiveConfigId = activeConfigId;
+ public boolean updateDisplayModesLocked(
+ SurfaceControl.DisplayMode[] displayModes, int activeDisplayModeId,
+ SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
+ mDisplayModes = Arrays.copyOf(displayModes, displayModes.length);
+ mActiveDisplayModeId = activeDisplayModeId;
// Build an updated list of all existing modes.
ArrayList<DisplayModeRecord> records = new ArrayList<>();
boolean modesAdded = false;
- for (int i = 0; i < configs.length; i++) {
- SurfaceControl.DisplayConfig config = configs[i];
+ for (int i = 0; i < displayModes.length; i++) {
+ SurfaceControl.DisplayMode mode = displayModes[i];
List<Float> alternativeRefreshRates = new ArrayList<>();
- for (int j = 0; j < configs.length; j++) {
- SurfaceControl.DisplayConfig other = configs[j];
- boolean isAlternative = j != i && other.width == config.width
- && other.height == config.height
- && other.refreshRate != config.refreshRate
- && other.configGroup == config.configGroup;
+ for (int j = 0; j < displayModes.length; j++) {
+ SurfaceControl.DisplayMode other = displayModes[j];
+ boolean isAlternative = j != i && other.width == mode.width
+ && other.height == mode.height
+ && other.refreshRate != mode.refreshRate
+ && other.group == mode.group;
if (isAlternative) {
- alternativeRefreshRates.add(configs[j].refreshRate);
+ alternativeRefreshRates.add(displayModes[j].refreshRate);
}
}
Collections.sort(alternativeRefreshRates);
// First, check to see if we've already added a matching mode. Since not all
// configuration options are exposed via Display.Mode, it's possible that we have
- // multiple DisplayConfigs that would generate the same Display.Mode.
+ // multiple DisplayModess that would generate the same Display.Mode.
boolean existingMode = false;
for (DisplayModeRecord record : records) {
- if (record.hasMatchingMode(config)
+ if (record.hasMatchingMode(mode)
&& refreshRatesEquals(alternativeRefreshRates,
record.mMode.getAlternativeRefreshRates())) {
existingMode = true;
@@ -296,13 +298,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// If we haven't already added a mode for this configuration to the new set of
// supported modes then check to see if we have one in the prior set of supported
// modes to reuse.
- DisplayModeRecord record = findDisplayModeRecord(config, alternativeRefreshRates);
+ DisplayModeRecord record = findDisplayModeRecord(mode, alternativeRefreshRates);
if (record == null) {
float[] alternativeRates = new float[alternativeRefreshRates.size()];
for (int j = 0; j < alternativeRates.length; j++) {
alternativeRates[j] = alternativeRefreshRates.get(j);
}
- record = new DisplayModeRecord(config, alternativeRates);
+ record = new DisplayModeRecord(mode, alternativeRates);
modesAdded = true;
}
records.add(record);
@@ -312,7 +314,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
DisplayModeRecord activeRecord = null;
for (int i = 0; i < records.size(); i++) {
DisplayModeRecord record = records.get(i);
- if (record.hasMatchingMode(configs[activeConfigId])) {
+ if (record.hasMatchingMode(displayModes[activeDisplayModeId])) {
activeRecord = record;
break;
}
@@ -334,20 +336,20 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// Check whether surface flinger spontaneously changed display config specs out from
// under us. If so, schedule a traversal to reapply our display config specs.
if (mDisplayModeSpecs.baseModeId != NO_DISPLAY_MODE_ID) {
- int activeBaseMode = findMatchingModeIdLocked(configSpecs.defaultConfig);
- // If we can't map the defaultConfig index to a mode, then the physical display
- // configs must have changed, and the code below for handling changes to the
- // list of available modes will take care of updating display config specs.
+ int activeBaseMode = findMatchingModeIdLocked(modeSpecs.defaultMode);
+ // If we can't map the defaultMode index to a mode, then the physical display
+ // modes must have changed, and the code below for handling changes to the
+ // list of available modes will take care of updating display mode specs.
if (activeBaseMode != NO_DISPLAY_MODE_ID) {
if (mDisplayModeSpecs.baseModeId != activeBaseMode
|| mDisplayModeSpecs.primaryRefreshRateRange.min
- != configSpecs.primaryRefreshRateMin
+ != modeSpecs.primaryRefreshRateMin
|| mDisplayModeSpecs.primaryRefreshRateRange.max
- != configSpecs.primaryRefreshRateMax
+ != modeSpecs.primaryRefreshRateMax
|| mDisplayModeSpecs.appRequestRefreshRateRange.min
- != configSpecs.appRequestRefreshRateMin
+ != modeSpecs.appRequestRefreshRateMin
|| mDisplayModeSpecs.appRequestRefreshRateRange.max
- != configSpecs.appRequestRefreshRateMax) {
+ != modeSpecs.appRequestRefreshRateMax) {
mDisplayModeSpecsInvalid = true;
sendTraversalRequestLocked();
}
@@ -368,17 +370,17 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// For a new display, we need to initialize the default mode ID.
if (mDefaultModeId == NO_DISPLAY_MODE_ID) {
mDefaultModeId = activeRecord.mMode.getModeId();
- mDefaultConfigGroup = configs[activeConfigId].configGroup;
+ mDefaultModeGroup = displayModes[activeDisplayModeId].group;
} else if (modesAdded && activeModeChanged) {
Slog.d(TAG, "New display modes are added and the active mode has changed, "
+ "use active mode as default mode.");
mDefaultModeId = activeRecord.mMode.getModeId();
- mDefaultConfigGroup = configs[activeConfigId].configGroup;
- } else if (findDisplayConfigIdLocked(mDefaultModeId, mDefaultConfigGroup) < 0) {
+ mDefaultModeGroup = displayModes[activeDisplayModeId].group;
+ } else if (findDisplayModeIdLocked(mDefaultModeId, mDefaultModeGroup) < 0) {
Slog.w(TAG, "Default display mode no longer available, using currently"
+ " active mode as default.");
mDefaultModeId = activeRecord.mMode.getModeId();
- mDefaultConfigGroup = configs[activeConfigId].configGroup;
+ mDefaultModeGroup = displayModes[activeDisplayModeId].group;
}
// Determine whether the display mode specs' base mode is still there.
@@ -518,11 +520,11 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return true;
}
- private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayConfig config,
+ private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayMode mode,
List<Float> alternativeRefreshRates) {
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
- if (record.hasMatchingMode(config)
+ if (record.hasMatchingMode(mode)
&& refreshRatesEquals(alternativeRefreshRates,
record.mMode.getAlternativeRefreshRates())) {
return record;
@@ -554,10 +556,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
if (mInfo == null) {
- SurfaceControl.DisplayConfig config = mDisplayConfigs[mActiveConfigId];
+ SurfaceControl.DisplayMode mode = mDisplayModes[mActiveDisplayModeId];
mInfo = new DisplayDeviceInfo();
- mInfo.width = config.width;
- mInfo.height = config.height;
+ mInfo.width = mode.width;
+ mInfo.height = mode.height;
mInfo.modeId = mActiveModeId;
mInfo.defaultModeId = mDefaultModeId;
mInfo.supportedModes = getDisplayModes(mSupportedModes);
@@ -570,16 +572,16 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.supportedColorModes[i] = mSupportedColorModes.get(i);
}
mInfo.hdrCapabilities = mHdrCapabilities;
- mInfo.appVsyncOffsetNanos = config.appVsyncOffsetNanos;
- mInfo.presentationDeadlineNanos = config.presentationDeadlineNanos;
+ mInfo.appVsyncOffsetNanos = mode.appVsyncOffsetNanos;
+ mInfo.presentationDeadlineNanos = mode.presentationDeadlineNanos;
mInfo.state = mState;
mInfo.uniqueId = getUniqueId();
final DisplayAddress.Physical physicalAddress =
DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
mInfo.address = physicalAddress;
mInfo.densityDpi = (int) (mDisplayInfo.density * 160 + 0.5f);
- mInfo.xDpi = config.xDpi;
- mInfo.yDpi = config.yDpi;
+ mInfo.xDpi = mode.xDpi;
+ mInfo.yDpi = mode.yDpi;
mInfo.deviceProductInfo = mDisplayInfo.deviceProductInfo;
// Assume that all built-in displays that have secure output (eg. HDCP) also
@@ -835,16 +837,16 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return;
}
- // Find the config Id based on the desired mode specs. In case there is more than one
- // config matching the mode spec, prefer the one that is in the default config group.
- // For now the default config group is taken from the active config when we got the
+ // Find the mode Id based on the desired mode specs. In case there is more than one
+ // mode matching the mode spec, prefer the one that is in the default mode group.
+ // For now the default config mode is taken from the active mode when we got the
// hotplug event for the display. In the future we might want to change the default
- // config based on vendor requirements.
- // Note: We prefer the default config group over the current one as this is the config
+ // mode based on vendor requirements.
+ // Note: We prefer the default mode group over the current one as this is the mode
// group the vendor prefers.
- int baseConfigId = findDisplayConfigIdLocked(displayModeSpecs.baseModeId,
- mDefaultConfigGroup);
- if (baseConfigId < 0) {
+ int baseModeId = findDisplayModeIdLocked(displayModeSpecs.baseModeId,
+ mDefaultModeGroup);
+ if (baseModeId < 0) {
// When a display is hotplugged, it's possible for a mode to be removed that was
// previously valid. Because of the way display changes are propagated through the
// framework, and the caching of the display mode specs in LogicalDisplay, it's
@@ -862,7 +864,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
getHandler().sendMessage(PooledLambda.obtainMessage(
LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this,
getDisplayTokenLocked(),
- new SurfaceControl.DesiredDisplayConfigSpecs(baseConfigId,
+ new SurfaceControl.DesiredDisplayModeSpecs(baseModeId,
mDisplayModeSpecs.allowGroupSwitching,
mDisplayModeSpecs.primaryRefreshRateRange.min,
mDisplayModeSpecs.primaryRefreshRateRange.max,
@@ -872,13 +874,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
private void setDesiredDisplayModeSpecsAsync(IBinder displayToken,
- SurfaceControl.DesiredDisplayConfigSpecs configSpecs) {
+ SurfaceControl.DesiredDisplayModeSpecs modeSpecs) {
// Do not lock when calling these SurfaceControl methods because they are sync
// operations that may block for a while when setting display power mode.
- SurfaceControl.setDesiredDisplayConfigSpecs(displayToken, configSpecs);
- final int activePhysIndex = SurfaceControl.getActiveConfig(displayToken);
+ SurfaceControl.setDesiredDisplayModeSpecs(displayToken, modeSpecs);
+ final int activeMode = SurfaceControl.getActiveDisplayMode(displayToken);
synchronized (getSyncRoot()) {
- if (updateActiveModeLocked(activePhysIndex)) {
+ if (updateActiveModeLocked(activeMode)) {
updateDeviceInfoLocked();
}
}
@@ -889,8 +891,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
updateDeviceInfoLocked();
}
- public void onActiveDisplayConfigChangedLocked(int configId) {
- if (updateActiveModeLocked(configId)) {
+ public void onActiveDisplayModeChangedLocked(int modeId) {
+ if (updateActiveModeLocked(modeId)) {
updateDeviceInfoLocked();
}
}
@@ -902,15 +904,15 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
- public boolean updateActiveModeLocked(int activeConfigId) {
- if (mActiveConfigId == activeConfigId) {
+ public boolean updateActiveModeLocked(int activeModeId) {
+ if (mActiveDisplayModeId == activeModeId) {
return false;
}
- mActiveConfigId = activeConfigId;
- mActiveModeId = findMatchingModeIdLocked(activeConfigId);
+ mActiveDisplayModeId = activeModeId;
+ mActiveModeId = findMatchingModeIdLocked(activeModeId);
if (mActiveModeId == NO_DISPLAY_MODE_ID) {
- Slog.w(TAG, "In unknown mode after setting allowed configs"
- + ", activeConfigId=" + mActiveConfigId);
+ Slog.w(TAG, "In unknown mode after setting allowed modes"
+ + ", activeModeId=" + mActiveDisplayModeId);
}
return true;
}
@@ -990,7 +992,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
pw.println("mDisplayModeSpecs={" + mDisplayModeSpecs + "}");
pw.println("mDisplayModeSpecsInvalid=" + mDisplayModeSpecsInvalid);
- pw.println("mActiveConfigId=" + mActiveConfigId);
+ pw.println("mActiveDisplayModeId=" + mActiveDisplayModeId);
pw.println("mActiveModeId=" + mActiveModeId);
pw.println("mActiveColorMode=" + mActiveColorMode);
pw.println("mDefaultModeId=" + mDefaultModeId);
@@ -1002,9 +1004,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mGameContentTypeSupported=" + mGameContentTypeSupported);
pw.println("mGameContentTypeRequested=" + mGameContentTypeRequested);
pw.println("mDisplayInfo=" + mDisplayInfo);
- pw.println("mDisplayConfigs=");
- for (int i = 0; i < mDisplayConfigs.length; i++) {
- pw.println(" " + mDisplayConfigs[i]);
+ pw.println("mDisplayModes=");
+ for (int i = 0; i < mDisplayModes.length; i++) {
+ pw.println(" " + mDisplayModes[i]);
}
pw.println("mSupportedModes=");
for (int i = 0; i < mSupportedModes.size(); i++) {
@@ -1014,37 +1016,37 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mDisplayDeviceConfig=" + mDisplayDeviceConfig);
}
- private int findDisplayConfigIdLocked(int modeId, int configGroup) {
- int matchingConfigId = SurfaceControl.DisplayConfig.INVALID_DISPLAY_CONFIG_ID;
+ private int findDisplayModeIdLocked(int modeId, int modeGroup) {
+ int matchingModeId = SurfaceControl.DisplayMode.INVALID_DISPLAY_MODE_ID;
DisplayModeRecord record = mSupportedModes.get(modeId);
if (record != null) {
- for (int i = 0; i < mDisplayConfigs.length; i++) {
- SurfaceControl.DisplayConfig config = mDisplayConfigs[i];
- if (record.hasMatchingMode(config)) {
- if (matchingConfigId
- == SurfaceControl.DisplayConfig.INVALID_DISPLAY_CONFIG_ID) {
- matchingConfigId = i;
+ for (int i = 0; i < mDisplayModes.length; i++) {
+ SurfaceControl.DisplayMode mode = mDisplayModes[i];
+ if (record.hasMatchingMode(mode)) {
+ if (matchingModeId
+ == SurfaceControl.DisplayMode.INVALID_DISPLAY_MODE_ID) {
+ matchingModeId = i;
}
- // Prefer to return a config that matches the configGroup
- if (config.configGroup == configGroup) {
+ // Prefer to return a mode that matches the modeGroup
+ if (mode.group == modeGroup) {
return i;
}
}
}
}
- return matchingConfigId;
+ return matchingModeId;
}
- private int findMatchingModeIdLocked(int configId) {
- if (configId < 0 || configId >= mDisplayConfigs.length) {
- Slog.e(TAG, "Invalid display config index " + configId);
+ private int findMatchingModeIdLocked(int modeId) {
+ if (modeId < 0 || modeId >= mDisplayModes.length) {
+ Slog.e(TAG, "Invalid display config index " + modeId);
return NO_DISPLAY_MODE_ID;
}
- SurfaceControl.DisplayConfig config = mDisplayConfigs[configId];
+ SurfaceControl.DisplayMode mode = mDisplayModes[modeId];
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
- if (record.hasMatchingMode(config)) {
+ if (record.hasMatchingMode(mode)) {
return record.mMode.getModeId();
}
}
@@ -1091,30 +1093,29 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
/**
- * Keeps track of a display configuration.
+ * Keeps track of a display mode.
*/
private static final class DisplayModeRecord {
public final Display.Mode mMode;
- DisplayModeRecord(SurfaceControl.DisplayConfig config,
+ DisplayModeRecord(SurfaceControl.DisplayMode mode,
float[] alternativeRefreshRates) {
- mMode = createMode(config.width, config.height, config.refreshRate,
+ mMode = createMode(mode.width, mode.height, mode.refreshRate,
alternativeRefreshRates);
}
/**
- * Returns whether the mode generated by the given DisplayConfig matches the mode
+ * Returns whether the mode generated by the given DisplayModes matches the mode
* contained by the record modulo mode ID.
*
- * Note that this doesn't necessarily mean that the DisplayConfigs are identical, just
+ * Note that this doesn't necessarily mean that the DisplayModes are identical, just
* that they generate identical modes.
*/
- public boolean hasMatchingMode(SurfaceControl.DisplayConfig config) {
- int modeRefreshRate = Float.floatToIntBits(mMode.getRefreshRate());
- int configRefreshRate = Float.floatToIntBits(config.refreshRate);
- return mMode.getPhysicalWidth() == config.width
- && mMode.getPhysicalHeight() == config.height
- && modeRefreshRate == configRefreshRate;
+ public boolean hasMatchingMode(SurfaceControl.DisplayMode mode) {
+ return mMode.getPhysicalWidth() == mode.width
+ && mMode.getPhysicalHeight() == mode.height
+ && Float.floatToIntBits(mMode.getRefreshRate())
+ == Float.floatToIntBits(mode.refreshRate);
}
public String toString() {
@@ -1131,7 +1132,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public interface DisplayEventListener {
void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected);
- void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId);
+ void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId);
void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
DisplayEventReceiver.FrameRateOverride[] overrides);
@@ -1141,7 +1142,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private final DisplayEventListener mListener;
ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) {
super(looper, VSYNC_SOURCE_APP,
- EVENT_REGISTRATION_CONFIG_CHANGED_FLAG
+ EVENT_REGISTRATION_MODE_CHANGED_FLAG
| EVENT_REGISTRATION_FRAME_RATE_OVERRIDE_FLAG);
mListener = listener;
}
@@ -1152,8 +1153,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
- public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
- mListener.onConfigChanged(timestampNanos, physicalDisplayId, configId);
+ public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
+ mListener.onModeChanged(timestampNanos, physicalDisplayId, modeId);
}
@Override
@@ -1176,23 +1177,23 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
- public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
+ public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) {
if (DEBUG) {
- Slog.d(TAG, "onConfigChanged("
+ Slog.d(TAG, "onModeChanged("
+ "timestampNanos=" + timestampNanos
+ ", physicalDisplayId=" + physicalDisplayId
- + ", configId=" + configId + ")");
+ + ", modeId=" + modeId + ")");
}
synchronized (getSyncRoot()) {
LocalDisplayDevice device = mDevices.get(physicalDisplayId);
if (device == null) {
if (DEBUG) {
- Slog.d(TAG, "Received config change for unhandled physical display: "
+ Slog.d(TAG, "Received mode change for unhandled physical display: "
+ "physicalDisplayId=" + physicalDisplayId);
}
return;
}
- device.onActiveDisplayConfigChangedLocked(configId);
+ device.onActiveDisplayModeChangedLocked(modeId);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 0ae1994bd368..bdf92ca4a7ef 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -541,7 +541,7 @@ public class HdmiControlService extends SystemService {
private void bootCompleted() {
// on boot, if device is interactive, set HDMI CEC state as powered on as well
if (mPowerManager.isInteractive() && isPowerStandbyOrTransient()) {
- onWakeUp(WAKE_UP_BOOT_UP);
+ mPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 2e4200c1f7d9..4e974112a5c3 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -57,6 +57,7 @@ import android.os.CombinedVibrationEffect;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IVibratorStateListener;
import android.os.InputEventInjectionResult;
import android.os.InputEventInjectionSync;
import android.os.LocaleList;
@@ -64,6 +65,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
@@ -77,6 +79,7 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.IInputFilter;
import android.view.IInputFilterHost;
@@ -100,6 +103,7 @@ import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
@@ -221,13 +225,16 @@ public class InputManagerService extends IInputManager.Stub
private Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<IBinder, VibratorToken>();
private int mNextVibratorTokenValue;
+ // List of currently registered vibrator state changed listeners by device id.
+ @GuardedBy("mVibratorLock")
+ private final SparseArray<RemoteCallbackList<IVibratorStateListener>> mVibratorStateListeners =
+ new SparseArray<RemoteCallbackList<IVibratorStateListener>>();
+ // List of vibrator states by device id.
+ @GuardedBy("mVibratorLock")
+ private final SparseBooleanArray mIsVibrating = new SparseBooleanArray();
+
// State for lid switch
- // Lock for the lid switch state. Held when triggering callbacks to guarantee lid switch events
- // are delivered in order. For ex, when a new lid switch callback is registered the lock is held
- // while the callback is processing the initial lid switch event which guarantees that any
- // events that occur at the same time are delivered after the callback has returned.
private final Object mLidSwitchLock = new Object();
- @GuardedBy("mLidSwitchLock")
private List<LidSwitchCallback> mLidSwitchCallbacks = new ArrayList<>();
// State for the currently installed input filter.
@@ -375,6 +382,9 @@ public class InputManagerService extends IInputManager.Stub
public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
+ /** Indicates an open state for the lid switch. */
+ public static final int SW_STATE_LID_OPEN = 0;
+
/** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
final boolean mUseDevInputEventForAudioJack;
@@ -410,18 +420,13 @@ public class InputManagerService extends IInputManager.Stub
}
void registerLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
+ boolean lidOpen;
synchronized (mLidSwitchLock) {
mLidSwitchCallbacks.add(callback);
-
- // Skip triggering the initial callback if the system is not yet ready as the switch
- // state will be reported as KEY_STATE_UNKNOWN. The callback will be triggered in
- // systemRunning().
- if (mSystemReady) {
- boolean lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID)
- == KEY_STATE_UP;
- callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen);
- }
+ lidOpen = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID)
+ == SW_STATE_LID_OPEN;
}
+ callback.notifyLidSwitchChanged(0 /* whenNanos */, lidOpen);
}
void unregisterLidSwitchCallbackInternal(@NonNull LidSwitchCallback callback) {
@@ -469,18 +474,7 @@ public class InputManagerService extends IInputManager.Stub
}
mNotificationManager = (NotificationManager)mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
-
- synchronized (mLidSwitchLock) {
- mSystemReady = true;
-
- // Send the initial lid switch state to any callback registered before the system was
- // ready.
- int switchState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY, SW_LID);
- for (int i = 0; i < mLidSwitchCallbacks.size(); i++) {
- LidSwitchCallback callback = mLidSwitchCallbacks.get(i);
- callback.notifyLidSwitchChanged(0 /* whenNanos */, switchState == KEY_STATE_UP);
- }
- }
+ mSystemReady = true;
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -2008,6 +2002,92 @@ public class InputManagerService extends IInputManager.Stub
}
}
+ // Native callback.
+ private void notifyVibratorState(int deviceId, boolean isOn) {
+ if (DEBUG) {
+ Slog.d(TAG, "notifyVibratorState: deviceId=" + deviceId + " isOn=" + isOn);
+ }
+ synchronized (mVibratorLock) {
+ mIsVibrating.put(deviceId, isOn);
+ notifyVibratorStateListenersLocked(deviceId);
+ }
+ }
+
+ @GuardedBy("mVibratorLock")
+ private void notifyVibratorStateListenersLocked(int deviceId) {
+ if (!mVibratorStateListeners.contains(deviceId)) {
+ if (DEBUG) {
+ Slog.v(TAG, "Device " + deviceId + " doesn't have vibrator state listener.");
+ }
+ return;
+ }
+ RemoteCallbackList<IVibratorStateListener> listeners =
+ mVibratorStateListeners.get(deviceId);
+ final int length = listeners.beginBroadcast();
+ try {
+ for (int i = 0; i < length; i++) {
+ notifyVibratorStateListenerLocked(deviceId, listeners.getBroadcastItem(i));
+ }
+ } finally {
+ listeners.finishBroadcast();
+ }
+ }
+
+ @GuardedBy("mVibratorLock")
+ private void notifyVibratorStateListenerLocked(int deviceId, IVibratorStateListener listener) {
+ try {
+ listener.onVibrating(mIsVibrating.get(deviceId));
+ } catch (RemoteException | RuntimeException e) {
+ Slog.e(TAG, "Vibrator state listener failed to call", e);
+ }
+ }
+
+ @Override // Binder call
+ public boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
+ Preconditions.checkNotNull(listener, "listener must not be null");
+
+ RemoteCallbackList<IVibratorStateListener> listeners;
+ synchronized (mVibratorLock) {
+ if (!mVibratorStateListeners.contains(deviceId)) {
+ listeners = new RemoteCallbackList<>();
+ mVibratorStateListeners.put(deviceId, listeners);
+ } else {
+ listeners = mVibratorStateListeners.get(deviceId);
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!listeners.register(listener)) {
+ Slog.e(TAG, "Could not register vibrator state listener " + listener);
+ return false;
+ }
+ // Notify its callback after new client registered.
+ notifyVibratorStateListenerLocked(deviceId, listener);
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ @Override // Binder call
+ public boolean unregisterVibratorStateListener(int deviceId, IVibratorStateListener listener) {
+ synchronized (mVibratorLock) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mVibratorStateListeners.contains(deviceId)) {
+ Slog.w(TAG, "Vibrator state listener " + deviceId + " doesn't exist");
+ return false;
+ }
+ RemoteCallbackList<IVibratorStateListener> listeners =
+ mVibratorStateListeners.get(deviceId);
+ return listeners.unregister(listener);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
// Binder call
@Override
public int getBatteryStatus(int deviceId) {
@@ -2251,13 +2331,14 @@ public class InputManagerService extends IInputManager.Stub
if ((switchMask & SW_LID_BIT) != 0) {
final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0);
+
+ ArrayList<LidSwitchCallback> callbacksCopy;
synchronized (mLidSwitchLock) {
- if (mSystemReady) {
- for (int i = 0; i < mLidSwitchCallbacks.size(); i++) {
- LidSwitchCallback callbacks = mLidSwitchCallbacks.get(i);
- callbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
- }
- }
+ callbacksCopy = new ArrayList<>(mLidSwitchCallbacks);
+ }
+ for (int i = 0; i < callbacksCopy.size(); i++) {
+ LidSwitchCallback callbacks = callbacksCopy.get(i);
+ callbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
}
}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 142f64f0a510..ea759bf500dd 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -66,6 +66,7 @@ import android.location.LocationManagerInternal;
import android.location.LocationProvider;
import android.location.LocationRequest;
import android.location.LocationTime;
+import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
@@ -882,6 +883,20 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
+ public void addProviderRequestListener(IProviderRequestListener listener) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.addProviderRequestListener(listener);
+ }
+ }
+
+ @Override
+ public void removeProviderRequestListener(IProviderRequestListener listener) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.removeProviderRequestListener(listener);
+ }
+ }
+
+ @Override
public void injectGnssMeasurementCorrections(GnssMeasurementCorrections corrections) {
if (mGnssManagerService != null) {
mGnssManagerService.injectGnssMeasurementCorrections(corrections);
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 221d4fb40ef9..48a012e57a02 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -55,6 +55,7 @@ import android.location.LocationManagerInternal;
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.LocationRequest;
import android.location.LocationResult;
+import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
import android.location.provider.ProviderRequest;
import android.location.util.identity.CallerIdentity;
@@ -117,6 +118,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
/**
@@ -1219,6 +1221,8 @@ public class LocationProviderManager extends
@GuardedBy("mLock")
private final ArrayList<ProviderEnabledListener> mEnabledListeners;
+ private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;
+
protected final LocationManagerInternal mLocationManagerInternal;
protected final SettingsHelper mSettingsHelper;
protected final UserInfoHelper mUserHelper;
@@ -1279,6 +1283,7 @@ public class LocationProviderManager extends
mLastLocations = new SparseArray<>(2);
mEnabledListeners = new ArrayList<>();
+ mProviderRequestListeners = new CopyOnWriteArrayList<>();
mLocationManagerInternal = Objects.requireNonNull(
LocalServices.getService(LocationManagerInternal.class));
@@ -1344,6 +1349,7 @@ public class LocationProviderManager extends
// if external entities are registering listeners it's their responsibility to
// unregister them before stopManager() is called
Preconditions.checkState(mEnabledListeners.isEmpty());
+ mProviderRequestListeners.clear();
mEnabled.clear();
mLastLocations.clear();
@@ -1404,6 +1410,16 @@ public class LocationProviderManager extends
}
}
+ /** Add a {@link IProviderRequestListener}. */
+ public void addProviderRequestListener(IProviderRequestListener listener) {
+ mProviderRequestListeners.add(listener);
+ }
+
+ /** Remove a {@link IProviderRequestListener}. */
+ public void removeProviderRequestListener(IProviderRequestListener listener) {
+ mProviderRequestListeners.remove(listener);
+ }
+
public void setRealProvider(@Nullable AbstractLocationProvider provider) {
synchronized (mLock) {
Preconditions.checkState(mState != STATE_STOPPED);
@@ -1873,8 +1889,7 @@ public class LocationProviderManager extends
Preconditions.checkState(delayMs >= 0 && delayMs <= newRequest.getIntervalMillis());
if (delayMs < MIN_REQUEST_DELAY_MS) {
- mLocationEventLog.logProviderUpdateRequest(mName, newRequest);
- mProvider.getController().setRequest(newRequest);
+ setProviderRequest(newRequest);
} else {
if (D) {
Log.d(TAG, mName + " provider delaying request update " + newRequest + " by "
@@ -1886,8 +1901,7 @@ public class LocationProviderManager extends
public void onAlarm() {
synchronized (mLock) {
if (mDelayedRegister == this) {
- mLocationEventLog.logProviderUpdateRequest(mName, newRequest);
- mProvider.getController().setRequest(newRequest);
+ setProviderRequest(newRequest);
mDelayedRegister = null;
}
}
@@ -1906,8 +1920,23 @@ public class LocationProviderManager extends
Preconditions.checkState(Thread.holdsLock(mLock));
}
- mLocationEventLog.logProviderUpdateRequest(mName, ProviderRequest.EMPTY_REQUEST);
- mProvider.getController().setRequest(ProviderRequest.EMPTY_REQUEST);
+ setProviderRequest(ProviderRequest.EMPTY_REQUEST);
+ }
+
+ @GuardedBy("mLock")
+ private void setProviderRequest(ProviderRequest request) {
+ mLocationEventLog.logProviderUpdateRequest(mName, request);
+ mProvider.getController().setRequest(request);
+
+ FgThread.getHandler().post(() -> {
+ for (IProviderRequestListener listener : mProviderRequestListeners) {
+ try {
+ listener.onProviderRequestChanged(mName, request);
+ } catch (RemoteException e) {
+ mProviderRequestListeners.remove(listener);
+ }
+ }
+ });
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index e2e5046d98bf..87e170ad12df 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -18,6 +18,7 @@ package com.android.server.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -58,6 +59,16 @@ final class MediaButtonReceiverHolder {
private static final String TAG = "PendingIntentHolder";
private static final boolean DEBUG_KEY_EVENT = MediaSessionService.DEBUG_KEY_EVENT;
private static final String COMPONENT_NAME_USER_ID_DELIM = ",";
+ // Filter apps regardless of the phone's locked/unlocked state.
+ private static final int PACKAGE_MANAGER_COMMON_FLAGS =
+ PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+
+ /**
+ * Denotes the duration during which a media button receiver will be exempted from
+ * FGS-from-BG restriction and so will be allowed to start an FGS even if it is in the
+ * background state while it receives a media key event.
+ */
+ private static final long FGS_STARTS_TEMP_ALLOWLIST_DURATION_MS = 10_000;
private final int mUserId;
private final PendingIntent mPendingIntent;
@@ -105,40 +116,22 @@ final class MediaButtonReceiverHolder {
* @return Can be {@code null} if pending intent was null.
*/
public static MediaButtonReceiverHolder create(Context context, int userId,
- PendingIntent pendingIntent) {
+ PendingIntent pendingIntent, String sessionPackageName) {
if (pendingIntent == null) {
return null;
}
- ComponentName componentName = (pendingIntent != null && pendingIntent.getIntent() != null)
- ? pendingIntent.getIntent().getComponent() : null;
+ int componentType = getComponentType(pendingIntent);
+ ComponentName componentName = getComponentName(pendingIntent, componentType);
if (componentName != null) {
- // Explicit intent, where component name is in the PendingIntent.
return new MediaButtonReceiverHolder(userId, pendingIntent, componentName,
- getComponentType(context, componentName));
- }
-
- // Implicit intent, where component name isn't in the PendingIntent. Try resolve.
- PackageManager pm = context.getPackageManager();
- Intent intent = pendingIntent.getIntent();
- if ((componentName = resolveImplicitServiceIntent(pm, intent)) != null) {
- return new MediaButtonReceiverHolder(
- userId, pendingIntent, componentName, COMPONENT_TYPE_SERVICE);
- } else if ((componentName = resolveManifestDeclaredBroadcastReceiverIntent(pm, intent))
- != null) {
- return new MediaButtonReceiverHolder(
- userId, pendingIntent, componentName, COMPONENT_TYPE_BROADCAST);
- } else if ((componentName = resolveImplicitActivityIntent(pm, intent)) != null) {
- return new MediaButtonReceiverHolder(
- userId, pendingIntent, componentName, COMPONENT_TYPE_ACTIVITY);
+ componentType);
}
// Failed to resolve target component for the pending intent. It's unlikely to be usable.
- // However, the pending intent would be still used, just to follow the legacy behavior.
+ // However, the pending intent would be still used, so setting the package name to the
+ // package name of the session that set this pending intent.
Log.w(TAG, "Unresolvable implicit intent is set, pi=" + pendingIntent);
- String packageName = (pendingIntent != null && pendingIntent.getIntent() != null)
- ? pendingIntent.getIntent().getPackage() : null;
- return new MediaButtonReceiverHolder(userId, pendingIntent,
- packageName != null ? packageName : "");
+ return new MediaButtonReceiverHolder(userId, pendingIntent, sessionPackageName);
}
public static MediaButtonReceiverHolder create(int userId, ComponentName broadcastReceiver) {
@@ -201,6 +194,9 @@ final class MediaButtonReceiverHolder {
// TODO: Find a way to also send PID/UID in secure way.
mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callingPackageName);
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setTemporaryAppWhitelistDuration(
+ FGS_STARTS_TEMP_ALLOWLIST_DURATION_MS);
if (mPendingIntent != null) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to the last known PendingIntent "
@@ -208,7 +204,8 @@ final class MediaButtonReceiverHolder {
}
try {
mPendingIntent.send(
- context, resultCode, mediaButtonIntent, onFinishedListener, handler);
+ context, resultCode, mediaButtonIntent, onFinishedListener, handler,
+ /* requiredPermission= */ null, options.toBundle());
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Error sending key event to media button receiver " + mPendingIntent, e);
return false;
@@ -231,7 +228,8 @@ final class MediaButtonReceiverHolder {
break;
default:
// Legacy behavior for other cases.
- context.sendBroadcastAsUser(mediaButtonIntent, userHandle);
+ context.sendBroadcastAsUser(mediaButtonIntent, userHandle,
+ /* receiverPermission= */ null, options.toBundle());
}
} catch (Exception e) {
Log.w(TAG, "Error sending media button to the restored intent "
@@ -269,6 +267,18 @@ final class MediaButtonReceiverHolder {
String.valueOf(mComponentType));
}
+ @ComponentType
+ private static int getComponentType(PendingIntent pendingIntent) {
+ if (pendingIntent.isBroadcast()) {
+ return COMPONENT_TYPE_BROADCAST;
+ } else if (pendingIntent.isActivity()) {
+ return COMPONENT_TYPE_ACTIVITY;
+ } else if (pendingIntent.isForegroundService() || pendingIntent.isService()) {
+ return COMPONENT_TYPE_SERVICE;
+ }
+ return COMPONENT_TYPE_INVALID;
+ }
+
/**
* Gets the type of the component
*
@@ -284,9 +294,7 @@ final class MediaButtonReceiverHolder {
PackageManager pm = context.getPackageManager();
try {
ActivityInfo activityInfo = pm.getActivityInfo(componentName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.GET_ACTIVITIES);
+ PACKAGE_MANAGER_COMMON_FLAGS | PackageManager.GET_ACTIVITIES);
if (activityInfo != null) {
return COMPONENT_TYPE_ACTIVITY;
}
@@ -294,9 +302,7 @@ final class MediaButtonReceiverHolder {
}
try {
ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.GET_SERVICES);
+ PACKAGE_MANAGER_COMMON_FLAGS | PackageManager.GET_SERVICES);
if (serviceInfo != null) {
return COMPONENT_TYPE_SERVICE;
}
@@ -306,40 +312,29 @@ final class MediaButtonReceiverHolder {
return COMPONENT_TYPE_BROADCAST;
}
- private static ComponentName resolveImplicitServiceIntent(PackageManager pm, Intent intent) {
- // Flag explanations.
- // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE:
- // filter apps regardless of the phone's locked/unlocked state.
- // - GET_SERVICES: Return service
- return createComponentName(pm.resolveService(intent,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.GET_SERVICES));
- }
-
- private static ComponentName resolveManifestDeclaredBroadcastReceiverIntent(
- PackageManager pm, Intent intent) {
- // Flag explanations.
- // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE:
- // filter apps regardless of the phone's locked/unlocked state.
- List<ResolveInfo> resolveInfos = pm.queryBroadcastReceivers(intent,
- PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
- return (resolveInfos != null && !resolveInfos.isEmpty())
- ? createComponentName(resolveInfos.get(0)) : null;
- }
-
- private static ComponentName resolveImplicitActivityIntent(PackageManager pm, Intent intent) {
- // Flag explanations.
- // - MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE:
- // Filter apps regardless of the phone's locked/unlocked state.
- // - MATCH_DEFAULT_ONLY:
- // Implicit intent receiver should be set as default. Only needed for activity.
- // - GET_ACTIVITIES: Return activity
- return createComponentName(pm.resolveActivity(intent,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DEFAULT_ONLY
- | PackageManager.GET_ACTIVITIES));
+ private static ComponentName getComponentName(PendingIntent pendingIntent, int componentType) {
+ List<ResolveInfo> resolveInfos = null;
+ switch (componentType) {
+ case COMPONENT_TYPE_ACTIVITY:
+ resolveInfos = pendingIntent.queryIntentComponents(
+ PACKAGE_MANAGER_COMMON_FLAGS
+ | PackageManager.MATCH_DEFAULT_ONLY /* Implicit intent receiver
+ should be set as default. Only needed for activity. */
+ | PackageManager.GET_ACTIVITIES);
+ break;
+ case COMPONENT_TYPE_SERVICE:
+ resolveInfos = pendingIntent.queryIntentComponents(
+ PACKAGE_MANAGER_COMMON_FLAGS | PackageManager.GET_SERVICES);
+ break;
+ case COMPONENT_TYPE_BROADCAST:
+ resolveInfos = pendingIntent.queryIntentComponents(
+ PACKAGE_MANAGER_COMMON_FLAGS | PackageManager.GET_RECEIVERS);
+ break;
+ }
+ if (resolveInfos != null && !resolveInfos.isEmpty()) {
+ return createComponentName(resolveInfos.get(0));
+ }
+ return null;
}
private static ComponentName createComponentName(ResolveInfo resolveInfo) {
diff --git a/services/core/java/com/android/server/media/MediaKeyDispatcher.java b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
index 63618eef250a..7ef4924879bf 100644
--- a/services/core/java/com/android/server/media/MediaKeyDispatcher.java
+++ b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
@@ -100,9 +100,12 @@ public abstract class MediaKeyDispatcher {
/**
* Implement this to customize the logic for which MediaButtonReceiver should consume a
* dispatched key event.
- *
- * Note: This pending intent will have lower priority over the {@link MediaSession.Token}
+ * <p>
+ * This pending intent will have lower priority over the {@link MediaSession.Token}
* returned from {@link #getMediaSession(KeyEvent, int, boolean)}.
+ * <p>
+ * Use a pending intent with an explicit intent; setting a pending intent with an implicit
+ * intent that cannot be resolved to a certain component name will fail.
*
* @return a {@link PendingIntent} instance that should receive the dispatched key event.
*/
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index ae58d4c40622..74111be419b5 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -843,7 +843,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
}
@Override
- public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException {
+ public void setMediaButtonReceiver(PendingIntent pi, String sessionPackageName)
+ throws RemoteException {
final long token = Binder.clearCallingIdentity();
try {
if ((mPolicies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER)
@@ -851,7 +852,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
return;
}
mMediaButtonReceiverHolder =
- MediaButtonReceiverHolder.create(mContext, mUserId, pi);
+ MediaButtonReceiverHolder.create(mContext, mUserId, pi, sessionPackageName);
mService.onMediaButtonReceiverChanged(MediaSessionRecord.this);
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index c0381e4b1715..6c1d3991c4e9 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -2124,7 +2124,8 @@ public class MediaSessionService extends SystemService implements Monitor {
uid, asSystemService);
if (pi != null) {
mediaButtonReceiverHolder = MediaButtonReceiverHolder.create(mContext,
- mCurrentFullUserRecord.mFullUserId, pi);
+ mCurrentFullUserRecord.mFullUserId, pi,
+ /* sessionPackageName= */ "");
}
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b99a55271943..aa7da54b2e1d 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1961,14 +1961,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (state.network != null) {
mNetIdToSubId.put(state.network.netId, parseSubId(state));
}
- if (state.networkInfo != null && state.networkInfo.isConnected()) {
- // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
- // in the object created here is never used and its value doesn't matter, so use
- // NETWORK_TYPE_UNKNOWN.
- final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
- true, TelephonyManager.NETWORK_TYPE_UNKNOWN /* subType */);
- identified.put(state, ident);
- }
+
+ // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
+ // in the object created here is never used and its value doesn't matter, so use
+ // NETWORK_TYPE_UNKNOWN.
+ final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
+ true, TelephonyManager.NETWORK_TYPE_UNKNOWN /* subType */);
+ identified.put(state, ident);
}
final ArraySet<String> newMeteredIfaces = new ArraySet<>();
@@ -2043,8 +2042,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// One final pass to catch any metered ifaces that don't have explicitly
// defined policies; typically Wi-Fi networks.
for (NetworkState state : states) {
- if (state.networkInfo != null && state.networkInfo.isConnected()
- && !state.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
+ if (!state.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
matchingIfaces.clear();
collectIfaces(matchingIfaces, state);
for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 0ab35a911025..9706bcece924 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -96,7 +96,6 @@ import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
-import android.net.NetworkInfo;
import android.net.NetworkStack;
import android.net.NetworkState;
import android.net.NetworkStats;
@@ -1264,7 +1263,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
/**
* Inspect all current {@link NetworkState} to derive mapping from {@code iface} to {@link
- * NetworkStatsHistory}. When multiple {@link NetworkInfo} are active on a single {@code iface},
+ * NetworkStatsHistory}. When multiple networks are active on a single {@code iface},
* they are combined under a single {@link NetworkIdentitySet}.
*/
@GuardedBy("mStatsLock")
@@ -1294,84 +1293,82 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled();
final ArraySet<String> mobileIfaces = new ArraySet<>();
for (NetworkState state : states) {
- if (state.networkInfo.isConnected()) {
- final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType());
- final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network);
- final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
- : getSubTypeForState(state);
- final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
- isDefault, subType);
-
- // Traffic occurring on the base interface is always counted for
- // both total usage and UID details.
- final String baseIface = state.linkProperties.getInterfaceName();
- if (baseIface != null) {
- findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
- findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
-
- // Build a separate virtual interface for VT (Video Telephony) data usage.
- // Only do this when IMS is not metered, but VT is metered.
- // If IMS is metered, then the IMS network usage has already included VT usage.
- // VT is considered always metered in framework's layer. If VT is not metered
- // per carrier's policy, modem will report 0 usage for VT calls.
- if (state.networkCapabilities.hasCapability(
- NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) {
-
- // Copy the identify from IMS one but mark it as metered.
- NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(),
- ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
- ident.getRoaming(), true /* metered */,
- true /* onDefaultNetwork */);
- findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
- findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
- }
+ final boolean isMobile = isNetworkTypeMobile(state.legacyNetworkType);
+ final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network);
+ final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
+ : getSubTypeForState(state);
+ final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
+ isDefault, subType);
+
+ // Traffic occurring on the base interface is always counted for
+ // both total usage and UID details.
+ final String baseIface = state.linkProperties.getInterfaceName();
+ if (baseIface != null) {
+ findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident);
+ findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident);
+
+ // Build a separate virtual interface for VT (Video Telephony) data usage.
+ // Only do this when IMS is not metered, but VT is metered.
+ // If IMS is metered, then the IMS network usage has already included VT usage.
+ // VT is considered always metered in framework's layer. If VT is not metered
+ // per carrier's policy, modem will report 0 usage for VT calls.
+ if (state.networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) {
+
+ // Copy the identify from IMS one but mark it as metered.
+ NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(),
+ ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
+ ident.getRoaming(), true /* metered */,
+ true /* onDefaultNetwork */);
+ findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
+ findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
+ }
- if (isMobile) {
- mobileIfaces.add(baseIface);
- }
+ if (isMobile) {
+ mobileIfaces.add(baseIface);
}
+ }
- // Traffic occurring on stacked interfaces is usually clatd.
- //
- // UID stats are always counted on the stacked interface and never on the base
- // interface, because the packets on the base interface do not actually match
- // application sockets (they're not IPv4) and thus the app uid is not known.
- // For receive this is obvious: packets must be translated from IPv6 to IPv4
- // before the application socket can be found.
- // For transmit: either they go through the clat daemon which by virtue of going
- // through userspace strips the original socket association during the IPv4 to
- // IPv6 translation process, or they are offloaded by eBPF, which doesn't:
- // However, on an ebpf device the accounting is done in cgroup ebpf hooks,
- // which don't trigger again post ebpf translation.
- // (as such stats accounted to the clat uid are ignored)
- //
- // Interface stats are more complicated.
- //
- // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus
- // *all* statistics are collected by iptables on the stacked v4-* interface.
- //
- // Additionally for ingress all packets bound for the clat IPv6 address are dropped
- // in ip6tables raw prerouting and thus even non-offloaded packets are only
- // accounted for on the stacked interface.
- //
- // For egress, packets subject to eBPF offload never appear on the base interface
- // and only appear on the stacked interface. Thus to ensure packets increment
- // interface stats, we must collate data from stacked interfaces. For xt_qtaguid
- // (or non eBPF offloaded) TX they would appear on both, however egress interface
- // accounting is explicitly bypassed for traffic from the clat uid.
- //
- final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
- for (LinkProperties stackedLink : stackedLinks) {
- final String stackedIface = stackedLink.getInterfaceName();
- if (stackedIface != null) {
- findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident);
- findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident);
- if (isMobile) {
- mobileIfaces.add(stackedIface);
- }
-
- mStatsFactory.noteStackedIface(stackedIface, baseIface);
+ // Traffic occurring on stacked interfaces is usually clatd.
+ //
+ // UID stats are always counted on the stacked interface and never on the base
+ // interface, because the packets on the base interface do not actually match
+ // application sockets (they're not IPv4) and thus the app uid is not known.
+ // For receive this is obvious: packets must be translated from IPv6 to IPv4
+ // before the application socket can be found.
+ // For transmit: either they go through the clat daemon which by virtue of going
+ // through userspace strips the original socket association during the IPv4 to
+ // IPv6 translation process, or they are offloaded by eBPF, which doesn't:
+ // However, on an ebpf device the accounting is done in cgroup ebpf hooks,
+ // which don't trigger again post ebpf translation.
+ // (as such stats accounted to the clat uid are ignored)
+ //
+ // Interface stats are more complicated.
+ //
+ // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus
+ // *all* statistics are collected by iptables on the stacked v4-* interface.
+ //
+ // Additionally for ingress all packets bound for the clat IPv6 address are dropped
+ // in ip6tables raw prerouting and thus even non-offloaded packets are only
+ // accounted for on the stacked interface.
+ //
+ // For egress, packets subject to eBPF offload never appear on the base interface
+ // and only appear on the stacked interface. Thus to ensure packets increment
+ // interface stats, we must collate data from stacked interfaces. For xt_qtaguid
+ // (or non eBPF offloaded) TX they would appear on both, however egress interface
+ // accounting is explicitly bypassed for traffic from the clat uid.
+ //
+ final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
+ for (LinkProperties stackedLink : stackedLinks) {
+ final String stackedIface = stackedLink.getInterfaceName();
+ if (stackedIface != null) {
+ findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident);
+ findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident);
+ if (isMobile) {
+ mobileIfaces.add(stackedIface);
}
+
+ mStatsFactory.noteStackedIface(stackedIface, baseIface);
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 571b6934e425..f7f1865f757e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -10104,7 +10104,9 @@ public class NotificationManagerService extends SystemService {
}
BackgroundThread.getHandler().post(() -> {
- if (info.isSystem || hasCompanionDevice(info)) {
+ if (info.isSystem
+ || hasCompanionDevice(info)
+ || mAssistants.isServiceTokenValidLocked(info.service)) {
notifyNotificationChannelChanged(
info, pkg, user, channel, modificationType);
}
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 6485c0c42ab7..d851e6ced91b 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -401,11 +401,16 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
String[] abiList = (cpuAbiOverride != null)
? new String[]{cpuAbiOverride} : Build.SUPPORTED_ABIS;
- // Enable gross and lame hacks for apps that are built with old
- // SDK tools. We must scan their APKs for renderscript bitcode and
- // not launch them if it's present. Don't bother checking on devices
- // that don't have 64 bit support.
+ // If an app that contains RenderScript has target API level < 21, it needs to run
+ // with 32-bit ABI, and its APK file will contain a ".bc" file.
+ // If an app that contains RenderScript has target API level >= 21, it can run with
+ // either 32-bit or 64-bit ABI, and its APK file will not contain a ".bc" file.
+ // Therefore, on a device that supports both 32-bit and 64-bit ABIs, we scan the app
+ // APK to see if it has a ".bc" file. If so, we will run it with 32-bit ABI.
+ // However, if the device only supports 64-bit ABI but does not support 32-bit ABI,
+ // we will fail the installation for such an app because it won't be able to run.
boolean needsRenderScriptOverride = false;
+ // No need to check if the device only supports 32-bit
if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null
&& NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
@@ -414,7 +419,8 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
} else {
throw new PackageManagerException(
INSTALL_FAILED_CPU_ABI_INCOMPATIBLE,
- "Apks with renderscript are not supported on 64-bit only devices");
+ "Apps that contain RenderScript with target API level < 21 are not "
+ + "supported on 64-bit only platforms");
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 81b65b294456..965f68bdcaf3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8940,7 +8940,6 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public List<String> getAllPackages() {
- enforceSystemOrRootOrShell("getAllPackages is limited to privileged callers");
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
synchronized (mLock) {
@@ -23934,7 +23933,8 @@ public class PackageManagerService extends IPackageManager.Stub
writer.println("Domain verification status:");
writer.increaseIndent();
try {
- mDomainVerificationManager.printState(writer, packageName, UserHandle.USER_ALL);
+ mDomainVerificationManager.printState(writer, packageName, UserHandle.USER_ALL,
+ mSettings::getPackageLPr);
} catch (PackageManager.NameNotFoundException e) {
pw.println("Failure printing domain verification information");
Slog.e(TAG, "Failure printing domain verification information", e);
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
index af9978b91e48..1925590112f8 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationDebug.java
@@ -32,15 +32,30 @@ import android.util.SparseArray;
import com.android.internal.util.CollectionUtils;
import com.android.server.pm.PackageSetting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
import com.android.server.pm.verify.domain.models.DomainVerificationUserState;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.Arrays;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Function;
+@SuppressWarnings("PointlessBooleanExpression")
public class DomainVerificationDebug {
+ // Disable to turn off all logging. This is used to allow a "basic" set of debug flags to be
+ // enabled and checked in, without having everything be on or off.
+ public static final boolean DEBUG_ANY = false;
+
+ // Enable to turn on all logging. Requires enabling DEBUG_ANY.
+ public static final boolean DEBUG_ALL = false;
+
+ public static final boolean DEBUG_APPROVAL = DEBUG_ANY && (DEBUG_ALL || true);
+ public static final boolean DEBUG_BROADCASTS = DEBUG_ANY && (DEBUG_ALL || false);
+ public static final boolean DEBUG_PROXIES = DEBUG_ANY && (DEBUG_ALL || false);
+
@NonNull
private final DomainVerificationCollector mCollector;
@@ -50,7 +65,7 @@ public class DomainVerificationDebug {
public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
@Nullable @UserIdInt Integer userId,
- @NonNull DomainVerificationService.Connection connection,
+ @NonNull Function<String, PackageSetting> pkgSettingFunction,
@NonNull DomainVerificationStateMap<DomainVerificationPkgState> stateMap)
throws NameNotFoundException {
ArrayMap<String, Integer> reusedMap = new ArrayMap<>();
@@ -61,7 +76,7 @@ public class DomainVerificationDebug {
for (int index = 0; index < size; index++) {
DomainVerificationPkgState pkgState = stateMap.valueAt(index);
String pkgName = pkgState.getPackageName();
- PackageSetting pkgSetting = connection.getPackageSettingLocked(pkgName);
+ PackageSetting pkgSetting = pkgSettingFunction.apply(pkgName);
if (pkgSetting == null || pkgSetting.getPkg() == null) {
continue;
}
@@ -77,7 +92,7 @@ public class DomainVerificationDebug {
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
- PackageSetting pkgSetting = connection.getPackageSettingLocked(packageName);
+ PackageSetting pkgSetting = pkgSettingFunction.apply(packageName);
if (pkgSetting == null || pkgSetting.getPkg() == null) {
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
index 7ad275a6f351..0474d78a3e53 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationManagerInternal.java
@@ -32,15 +32,16 @@ import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import com.android.server.pm.PackageSetting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
+import java.util.function.Function;
public interface DomainVerificationManagerInternal extends DomainVerificationManager {
@@ -191,12 +192,21 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
/**
* Print the verification state and user selection state of a package.
*
- * @param packageName the package whose state to change, or all packages if none is specified
- * @param userId the specific user to print, or null to skip printing user selection
- * states, supports {@link android.os.UserHandle#USER_ALL}
+ * @param packageName the package whose state to change, or all packages if none is
+ * specified
+ * @param userId the specific user to print, or null to skip printing user selection
+ * states, supports {@link android.os.UserHandle#USER_ALL}
+ * @param pkgSettingFunction the method by which to retrieve package data; if this is called
+ * from {@link com.android.server.pm.PackageManagerService}, it is
+ * expected to pass in the snapshot of {@link PackageSetting} objects,
+ * or if null is passed, the manager may decide to lock {@link
+ * com.android.server.pm.PackageManagerService} through {@link
+ * Connection#getPackageSettingLocked(String)}
*/
void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
- @Nullable @UserIdInt Integer userId) throws NameNotFoundException;
+ @Nullable @UserIdInt Integer userId,
+ @Nullable Function<String, PackageSetting> pkgSettingFunction)
+ throws NameNotFoundException;
@NonNull
DomainVerificationShell getShell();
@@ -225,7 +235,7 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
throws IllegalArgumentException, NameNotFoundException;
- interface Connection {
+ interface Connection extends Function<String, PackageSetting> {
/**
* Notify that a settings change has been made and that eventually
@@ -249,10 +259,19 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
*/
void schedule(int code, @Nullable Object object);
+ // TODO(b/178733426): Make DomainVerificationService PMS snapshot aware so it can avoid
+ // locking package state at all. This can be as simple as removing this method in favor of
+ // accepting a PackageSetting function in at every method call, although should probably
+ // be abstracted to a wrapper class.
@Nullable
PackageSetting getPackageSettingLocked(@NonNull String pkgName);
@Nullable
AndroidPackage getPackageLocked(@NonNull String pkgName);
+
+ @Override
+ default PackageSetting apply(@NonNull String pkgName) {
+ return getPackageSettingLocked(pkgName);
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 53540c8e0d4f..e24e5bbfa4f6 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -64,13 +64,14 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.function.Function;
public class DomainVerificationService extends SystemService
implements DomainVerificationManagerInternal, DomainVerificationShell.Callback {
private static final String TAG = "DomainVerificationService";
- public static final boolean DEBUG_APPROVAL = true;
+ public static final boolean DEBUG_APPROVAL = DomainVerificationDebug.DEBUG_APPROVAL;
/**
* The new user preference API for verifying domains marked autoVerify=true in
@@ -541,8 +542,6 @@ public class DomainVerificationService extends SystemService
userState.removeHosts(domains);
}
}
-
- mConnection.scheduleWriteSettings();
}
@Nullable
@@ -848,6 +847,7 @@ public class DomainVerificationService extends SystemService
public void setLegacyUserState(@NonNull String packageName, @UserIdInt int userId, int state) {
mEnforcer.callerIsLegacyUserSelector(mConnection.getCallingUid());
mLegacySettings.add(packageName, userId, state);
+ mConnection.scheduleWriteSettings();
}
@Override
@@ -890,9 +890,24 @@ public class DomainVerificationService extends SystemService
@Override
public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
- @Nullable @UserIdInt Integer userId) throws NameNotFoundException {
+ @Nullable Integer userId) throws NameNotFoundException {
+ // This method is only used by DomainVerificationShell, which doesn't lock PMS, so it's
+ // safe to pass mConnection directly here and lock PMS. This method is not exposed
+ // to the general system server/PMS.
+ printState(writer, packageName, userId, mConnection);
+ }
+
+ @Override
+ public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
+ @Nullable @UserIdInt Integer userId,
+ @Nullable Function<String, PackageSetting> pkgSettingFunction)
+ throws NameNotFoundException {
+ if (pkgSettingFunction == null) {
+ pkgSettingFunction = mConnection;
+ }
+
synchronized (mLock) {
- mDebug.printState(writer, packageName, userId, mConnection, mAttachedPkgStates);
+ mDebug.printState(writer, packageName, userId, pkgSettingFunction, mAttachedPkgStates);
}
}
@@ -1051,6 +1066,8 @@ public class DomainVerificationService extends SystemService
}
}
}
+
+ mConnection.scheduleWriteSettings();
}
/**
@@ -1108,6 +1125,8 @@ public class DomainVerificationService extends SystemService
}
}
}
+
+ mConnection.scheduleWriteSettings();
}
@Override
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxy.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxy.java
index 715d8fb0fc2d..09abdd092648 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxy.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxy.java
@@ -23,9 +23,10 @@ import android.content.Context;
import android.util.Slog;
import com.android.server.DeviceIdleInternal;
-import com.android.server.pm.verify.domain.DomainVerificationMessageCodes;
import com.android.server.pm.verify.domain.DomainVerificationCollector;
+import com.android.server.pm.verify.domain.DomainVerificationDebug;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
+import com.android.server.pm.verify.domain.DomainVerificationMessageCodes;
import java.util.Objects;
import java.util.Set;
@@ -35,7 +36,7 @@ public interface DomainVerificationProxy {
String TAG = "DomainVerificationProxy";
- boolean DEBUG_PROXIES = false;
+ boolean DEBUG_PROXIES = DomainVerificationDebug.DEBUG_PROXIES;
static <ConnectionType extends DomainVerificationProxyV1.Connection
& DomainVerificationProxyV2.Connection> DomainVerificationProxy makeProxy(
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
index eab89e987885..9389e63404f4 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV1.java
@@ -37,10 +37,11 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.verify.domain.DomainVerificationCollector;
+import com.android.server.pm.verify.domain.DomainVerificationDebug;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationMessageCodes;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.Collections;
import java.util.List;
@@ -52,7 +53,7 @@ public class DomainVerificationProxyV1 implements DomainVerificationProxy {
private static final String TAG = "DomainVerificationProxyV1";
- private static final boolean DEBUG_BROADCASTS = false;
+ private static final boolean DEBUG_BROADCASTS = DomainVerificationDebug.DEBUG_BROADCASTS;
@NonNull
private final Context mContext;
@@ -152,18 +153,22 @@ public class DomainVerificationProxyV1 implements DomainVerificationProxy {
UUID domainSetId = pair.first;
String packageName = pair.second;
- DomainVerificationInfo set;
+ DomainVerificationInfo info;
try {
- set = mManager.getDomainVerificationInfo(packageName);
+ info = mManager.getDomainVerificationInfo(packageName);
} catch (PackageManager.NameNotFoundException ignored) {
return true;
}
- if (!Objects.equals(domainSetId, set.getIdentifier())) {
+ if (info == null) {
+ return true;
+ }
+
+ if (!Objects.equals(domainSetId, info.getIdentifier())) {
return true;
}
- Set<String> successfulDomains = new ArraySet<>(set.getHostToStateMap().keySet());
+ Set<String> successfulDomains = new ArraySet<>(info.getHostToStateMap().keySet());
successfulDomains.removeAll(response.failedDomains);
int callingUid = response.callingUid;
diff --git a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
index 9fcbce2ad055..1ef06036021e 100644
--- a/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
+++ b/services/core/java/com/android/server/pm/verify/domain/proxy/DomainVerificationProxyV2.java
@@ -28,6 +28,7 @@ import android.os.Process;
import android.os.UserHandle;
import android.util.Slog;
+import com.android.server.pm.verify.domain.DomainVerificationDebug;
import com.android.server.pm.verify.domain.DomainVerificationMessageCodes;
import java.util.Set;
@@ -36,7 +37,7 @@ public class DomainVerificationProxyV2 implements DomainVerificationProxy {
private static final String TAG = "DomainVerificationProxyV2";
- private static final boolean DEBUG_BROADCASTS = true;
+ private static final boolean DEBUG_BROADCASTS = DomainVerificationDebug.DEBUG_BROADCASTS;
@NonNull
private final Context mContext;
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
index 03d76649e7ee..57cf986842da 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
@@ -150,7 +150,7 @@ public class RotationResolverManagerService extends
@Override
public void resolveRotation(
@NonNull RotationResolverCallbackInternal callbackInternal, int proposedRotation,
- int currentRotation, String packageName, long timeout,
+ int currentRotation, long timeout,
@NonNull CancellationSignal cancellationSignalInternal) {
Objects.requireNonNull(callbackInternal);
Objects.requireNonNull(cancellationSignalInternal);
@@ -159,7 +159,8 @@ public class RotationResolverManagerService extends
final RotationResolverManagerPerUserService service = getServiceForUserLocked(
UserHandle.getCallingUserId());
service.resolveRotationLocked(callbackInternal, proposedRotation,
- currentRotation, packageName, timeout, cancellationSignalInternal);
+ currentRotation, /* packageName */ "", timeout,
+ cancellationSignalInternal);
} else {
Slog.w(TAG, "Rotation Resolver service is disabled.");
callbackInternal.onFailure(ROTATION_RESULT_FAILURE_CANCELLED);
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 263776c63db6..5e681c674d8b 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -2509,7 +2509,6 @@ public class StatsPullAtomService extends SystemService {
try {
// force procstats to flush & combine old files into one store
long lastHighWaterMark = readProcStatsHighWaterMark(section);
- List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
ProtoOutputStream[] protoStreams = new ProtoOutputStream[MAX_PROCSTATS_SHARDS];
for (int i = 0; i < protoStreams.length; i++) {
@@ -2519,7 +2518,7 @@ public class StatsPullAtomService extends SystemService {
ProcessStats procStats = new ProcessStats(false);
// Force processStatsService to aggregate all in-storage and in-memory data.
long highWaterMark = processStatsService.getCommittedStatsMerged(
- lastHighWaterMark, section, true, statsFiles, procStats);
+ lastHighWaterMark, section, true, null, procStats);
procStats.dumpAggregatedProtoForStatsd(protoStreams, MAX_PROCSTATS_RAW_SHARD_SIZE);
for (int i = 0; i < protoStreams.length; i++) {
diff --git a/services/core/java/com/android/server/tracing/OWNERS b/services/core/java/com/android/server/tracing/OWNERS
new file mode 100644
index 000000000000..f5de4eb05c54
--- /dev/null
+++ b/services/core/java/com/android/server/tracing/OWNERS
@@ -0,0 +1,2 @@
+cfijalkovich@google.com
+carmenjackson@google.com
diff --git a/services/core/java/com/android/server/tracing/TracingServiceProxy.java b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
new file mode 100644
index 000000000000..8f227489740f
--- /dev/null
+++ b/services/core/java/com/android/server/tracing/TracingServiceProxy.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.tracing;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.UserHandle;
+import android.tracing.ITracingServiceProxy;
+import android.util.Log;
+
+import com.android.server.SystemService;
+
+/**
+ * TracingServiceProxy is the system_server intermediary between the Perfetto tracing daemon and the
+ * system tracing app Traceur.
+ *
+ * @hide
+ */
+public class TracingServiceProxy extends SystemService {
+ private static final String TAG = "TracingServiceProxy";
+
+ public static final String TRACING_SERVICE_PROXY_BINDER_NAME = "tracing.proxy";
+
+ private static final String TRACING_APP_PACKAGE_NAME = "com.android.traceur";
+ private static final String TRACING_APP_ACTIVITY = "com.android.traceur.StopTraceService";
+
+ // Keep this in sync with the definitions in TraceService
+ private static final String INTENT_ACTION_NOTIFY_SESSION_STOPPED =
+ "com.android.traceur.NOTIFY_SESSION_STOPPED";
+ private static final String INTENT_ACTION_NOTIFY_SESSION_STOLEN =
+ "com.android.traceur.NOTIFY_SESSION_STOLEN";
+
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+
+ private final ITracingServiceProxy.Stub mTracingServiceProxy = new ITracingServiceProxy.Stub() {
+ /**
+ * Notifies system tracing app that a tracing session has ended. If a session is repurposed
+ * for use in a bugreport, sessionStolen can be set to indicate that tracing has ended but
+ * there is no buffer available to dump.
+ */
+ @Override
+ public void notifyTraceSessionEnded(boolean sessionStolen) {
+ notifyTraceur(sessionStolen);
+ }
+ };
+
+ public TracingServiceProxy(Context context) {
+ super(context);
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(TRACING_SERVICE_PROXY_BINDER_NAME, mTracingServiceProxy);
+ }
+
+ private void notifyTraceur(boolean sessionStolen) {
+ final Intent intent = new Intent();
+
+ try {
+ // Validate that Traceur is a system app.
+ PackageInfo info = mPackageManager.getPackageInfo(TRACING_APP_PACKAGE_NAME,
+ PackageManager.MATCH_SYSTEM_ONLY);
+
+ intent.setClassName(info.packageName, TRACING_APP_ACTIVITY);
+ if (sessionStolen) {
+ intent.setAction(INTENT_ACTION_NOTIFY_SESSION_STOLEN);
+ } else {
+ intent.setAction(INTENT_ACTION_NOTIFY_SESSION_STOPPED);
+ }
+
+ try {
+ mContext.startForegroundServiceAsUser(intent, UserHandle.SYSTEM);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to notifyTraceSessionEnded", e);
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Failed to locate Traceur", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 5ec527a7d6c4..3726407211d5 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -16,6 +16,7 @@
package com.android.server.vcn;
+import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull;
import android.net.NetworkCapabilities;
@@ -225,7 +226,7 @@ public class Vcn extends Handler {
private void handleConfigUpdated(@NonNull VcnConfig config) {
// TODO: Add a dump function in VcnConfig that omits PII. Until then, use hashCode()
- Slog.v(getLogTag(), String.format("Config updated: config = %s", config.hashCode()));
+ Slog.v(getLogTag(), "Config updated: config = " + config.hashCode());
mConfig = config;
@@ -251,17 +252,29 @@ public class Vcn extends Handler {
private void handleNetworkRequested(
@NonNull NetworkRequest request, int score, int providerId) {
if (score > getNetworkScore()) {
- Slog.v(getLogTag(),
- "Request already satisfied by higher-scoring (" + score + ") network from "
- + "provider " + providerId + ": " + request);
+ if (VDBG) {
+ Slog.v(
+ getLogTag(),
+ "Request already satisfied by higher-scoring ("
+ + score
+ + ") network from "
+ + "provider "
+ + providerId
+ + ": "
+ + request);
+ }
return;
}
// If preexisting VcnGatewayConnection(s) satisfy request, return
for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
- Slog.v(getLogTag(),
- "Request already satisfied by existing VcnGatewayConnection: " + request);
+ if (VDBG) {
+ Slog.v(
+ getLogTag(),
+ "Request already satisfied by existing VcnGatewayConnection: "
+ + request);
+ }
return;
}
}
@@ -308,7 +321,7 @@ public class Vcn extends Handler {
}
private String getLogTag() {
- return String.format("%s [%d]", TAG, mSubscriptionGroup.hashCode());
+ return TAG + " [" + mSubscriptionGroup.hashCode() + "]";
}
/** Retrieves the network score for a VCN Network */
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 9ecdf1b48789..2503e812f9e1 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -75,6 +75,7 @@ import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -297,9 +298,9 @@ public class VcnGatewayConnection extends StateMachine {
private static final int EVENT_SETUP_COMPLETED = 6;
private static class EventSetupCompletedInfo implements EventInfo {
- @NonNull public final ChildSessionConfiguration childSessionConfig;
+ @NonNull public final VcnChildSessionConfiguration childSessionConfig;
- EventSetupCompletedInfo(@NonNull ChildSessionConfiguration childSessionConfig) {
+ EventSetupCompletedInfo(@NonNull VcnChildSessionConfiguration childSessionConfig) {
this.childSessionConfig = Objects.requireNonNull(childSessionConfig);
}
@@ -471,7 +472,7 @@ public class VcnGatewayConnection extends StateMachine {
* <p>Set in Connected and Migrating states, always @NonNull in Connected, Migrating
* states, @Nullable otherwise.
*/
- private ChildSessionConfiguration mChildConfig;
+ private VcnChildSessionConfiguration mChildConfig;
/**
* The active network agent.
@@ -659,7 +660,7 @@ public class VcnGatewayConnection extends StateMachine {
new EventTransformCreatedInfo(direction, transform));
}
- private void childOpened(int token, @NonNull ChildSessionConfiguration childConfig) {
+ private void childOpened(int token, @NonNull VcnChildSessionConfiguration childConfig) {
sendMessage(EVENT_SETUP_COMPLETED, token, new EventSetupCompletedInfo(childConfig));
}
@@ -1008,7 +1009,7 @@ public class VcnGatewayConnection extends StateMachine {
protected void updateNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull NetworkAgent agent,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp =
@@ -1020,7 +1021,7 @@ public class VcnGatewayConnection extends StateMachine {
protected NetworkAgent buildNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp =
@@ -1068,15 +1069,15 @@ public class VcnGatewayConnection extends StateMachine {
protected void setupInterface(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
setupInterface(token, tunnelIface, childConfig, null);
}
protected void setupInterface(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig,
- @Nullable ChildSessionConfiguration oldChildConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig,
+ @Nullable VcnChildSessionConfiguration oldChildConfig) {
try {
final Set<LinkAddress> newAddrs =
new ArraySet<>(childConfig.getInternalAddresses());
@@ -1189,7 +1190,7 @@ public class VcnGatewayConnection extends StateMachine {
protected void setupInterfaceAndNetworkAgent(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
setupInterface(token, tunnelIface, childConfig);
if (mNetworkAgent == null) {
@@ -1207,7 +1208,64 @@ public class VcnGatewayConnection extends StateMachine {
*/
class RetryTimeoutState extends ActiveBaseState {
@Override
- protected void processStateMsg(Message msg) {}
+ protected void enterState() throws Exception {
+ // Reset upon entry to ConnectedState
+ mFailedAttempts++;
+
+ if (mUnderlying == null) {
+ Slog.wtf(TAG, "Underlying network was null in retry state");
+ transitionTo(mDisconnectedState);
+ } else {
+ sendMessageDelayed(
+ EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken, getNextRetryIntervalsMs());
+ }
+ }
+
+ @Override
+ protected void processStateMsg(Message msg) {
+ switch (msg.what) {
+ case EVENT_UNDERLYING_NETWORK_CHANGED:
+ final UnderlyingNetworkRecord oldUnderlying = mUnderlying;
+ mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+ // If new underlying is null, all networks were lost; go back to disconnected.
+ if (mUnderlying == null) {
+ removeMessages(EVENT_RETRY_TIMEOUT_EXPIRED);
+
+ transitionTo(mDisconnectedState);
+ return;
+ } else if (oldUnderlying != null
+ && mUnderlying.network.equals(oldUnderlying.network)) {
+ // If the network has not changed, do nothing.
+ return;
+ }
+
+ // Fallthrough
+ case EVENT_RETRY_TIMEOUT_EXPIRED:
+ removeMessages(EVENT_RETRY_TIMEOUT_EXPIRED);
+
+ transitionTo(mConnectingState);
+ break;
+ case EVENT_DISCONNECT_REQUESTED:
+ handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason);
+ break;
+ default:
+ logUnhandledMessage(msg);
+ break;
+ }
+ }
+
+ private long getNextRetryIntervalsMs() {
+ final int retryDelayIndex = mFailedAttempts - 1;
+ final long[] retryIntervalsMs = mConnectionConfig.getRetryIntervalsMs();
+
+ // Repeatedly use last item in retry timeout list.
+ if (retryDelayIndex >= retryIntervalsMs.length) {
+ return retryIntervalsMs[retryIntervalsMs.length - 1];
+ }
+
+ return retryIntervalsMs[retryDelayIndex];
+ }
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
@@ -1277,7 +1335,7 @@ public class VcnGatewayConnection extends StateMachine {
private static LinkProperties buildConnectedLinkProperties(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(tunnelIface.getInterfaceName());
@@ -1328,20 +1386,28 @@ public class VcnGatewayConnection extends StateMachine {
}
}
- private class ChildSessionCallbackImpl implements ChildSessionCallback {
+ /** Implementation of ChildSessionCallback, exposed for testing. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public class VcnChildSessionCallback implements ChildSessionCallback {
private final int mToken;
- ChildSessionCallbackImpl(int token) {
+ VcnChildSessionCallback(int token) {
mToken = token;
}
- @Override
- public void onOpened(@NonNull ChildSessionConfiguration childConfig) {
+ /** Internal proxy method for injecting of mocked ChildSessionConfiguration */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void onOpened(@NonNull VcnChildSessionConfiguration childConfig) {
Slog.v(TAG, "ChildOpened for token " + mToken);
childOpened(mToken, childConfig);
}
@Override
+ public void onOpened(@NonNull ChildSessionConfiguration childConfig) {
+ onOpened(new VcnChildSessionConfiguration(childConfig));
+ }
+
+ @Override
public void onClosed() {
Slog.v(TAG, "ChildClosed for token " + mToken);
sessionLost(mToken, null);
@@ -1421,7 +1487,7 @@ public class VcnGatewayConnection extends StateMachine {
buildIkeParams(),
buildChildParams(),
new IkeSessionCallbackImpl(token),
- new ChildSessionCallbackImpl(token));
+ new VcnChildSessionCallback(token));
}
/** External dependencies used by VcnGatewayConnection, for injection in tests */
@@ -1458,6 +1524,35 @@ public class VcnGatewayConnection extends StateMachine {
}
}
+ /**
+ * Proxy implementation of Child Session Configuration, used for testing.
+ *
+ * <p>This wrapper allows mocking of the final, parcelable ChildSessionConfiguration object for
+ * testing purposes. This is the unfortunate result of mockito-inline (for mocking final
+ * classes) not working properly with system services & associated classes.
+ *
+ * <p>This class MUST EXCLUSIVELY be a passthrough, proxying calls directly to the actual
+ * ChildSessionConfiguration.
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class VcnChildSessionConfiguration {
+ private final ChildSessionConfiguration mChildConfig;
+
+ public VcnChildSessionConfiguration(ChildSessionConfiguration childConfig) {
+ mChildConfig = childConfig;
+ }
+
+ /** Retrieves the addresses to be used inside the tunnel. */
+ public List<LinkAddress> getInternalAddresses() {
+ return mChildConfig.getInternalAddresses();
+ }
+
+ /** Retrieves the DNS servers to be used inside the tunnel. */
+ public List<InetAddress> getInternalDnsServers() {
+ return mChildConfig.getInternalDnsServers();
+ }
+ }
+
/** Proxy implementation of IKE session, used for testing. */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class VcnIkeSession {
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index fe4ea303610f..bfeec011a2c9 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -16,6 +16,8 @@
package com.android.server.vcn;
+import static com.android.server.VcnManagementService.VDBG;
+
import android.annotation.NonNull;
import android.content.Context;
import android.net.NetworkProvider;
@@ -83,11 +85,16 @@ public class VcnNetworkProvider extends NetworkProvider {
@Override
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
- Slog.v(
- TAG,
- String.format(
- "Network requested: Request = %s, score = %d, providerId = %d",
- request, score, providerId));
+ if (VDBG) {
+ Slog.v(
+ TAG,
+ "Network requested: Request = "
+ + request
+ + ", score = "
+ + score
+ + ", providerId = "
+ + providerId);
+ }
final NetworkRequestEntry entry = new NetworkRequestEntry(request, score, providerId);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index ccb349b9c5ab..68a2c5d5233c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7005,7 +7005,32 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
}
- super.onConfigurationChanged(newParentConfig);
+
+ final DisplayContent display = mDisplayContent;
+ if (inPinnedWindowingMode() && attachedToProcess() && display != null) {
+ // If the PIP activity is changing to fullscreen with display orientation change, the
+ // fixed rotation will take effect that requires to send fixed rotation adjustments
+ // before the process configuration (if the process is a configuration listener of the
+ // activity). So when performing process configuration on client side, it can apply
+ // the adjustments (see WindowToken#onFixedRotationStatePrepared).
+ try {
+ app.pauseConfigurationDispatch();
+ super.onConfigurationChanged(newParentConfig);
+ if (mVisibleRequested && !inMultiWindowMode()) {
+ final int rotation = display.rotationForActivityInDifferentOrientation(this);
+ if (rotation != ROTATION_UNDEFINED) {
+ app.resumeConfigurationDispatch();
+ display.setFixedRotationLaunchingApp(this, rotation);
+ }
+ }
+ } finally {
+ if (app.resumeConfigurationDispatch()) {
+ app.dispatchConfiguration(app.getConfiguration());
+ }
+ }
+ } else {
+ super.onConfigurationChanged(newParentConfig);
+ }
// Configuration's equality doesn't consider seq so if only seq number changes in resolved
// override configuration. Therefore ConfigurationContainer doesn't change merged override
@@ -7014,7 +7039,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
onMergedOverrideConfigurationChanged();
}
- final DisplayContent display = mDisplayContent;
if (display == null) {
return;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 79f8229c6162..3456e51d028a 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -772,6 +772,11 @@ class ActivityStarter {
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
}
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT, new IntentSender(target));
+ ActivityOptions options = mRequest.activityOptions.getOptions(mRequest.intent,
+ mRequest.activityInfo,
+ mService.getProcessController(mRequest.caller),
+ mSupervisor);
+ newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_ACTIVITY_OPTIONS, options.toBundle());
heavy.updateIntentForHeavyWeightActivity(newIntent);
newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
mRequest.activityInfo.packageName);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 4bcef408d9a0..f97af6259c9c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -176,6 +176,7 @@ import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.power.Mode;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -343,7 +344,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private StatusBarManagerInternal mStatusBarManagerInternal;
@VisibleForTesting
final ActivityTaskManagerInternal mInternal;
- PowerManagerInternal mPowerManagerInternal;
+ private PowerManagerInternal mPowerManagerInternal;
private UsageStatsManagerInternal mUsageStatsInternal;
PendingIntentController mPendingIntentController;
@@ -591,6 +592,22 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Retention(RetentionPolicy.SOURCE)
@IntDef({
+ POWER_MODE_REASON_START_ACTIVITY,
+ POWER_MODE_REASON_FREEZE_DISPLAY,
+ POWER_MODE_REASON_ALL,
+ })
+ @interface PowerModeReason {}
+
+ static final int POWER_MODE_REASON_START_ACTIVITY = 1 << 0;
+ static final int POWER_MODE_REASON_FREEZE_DISPLAY = 1 << 1;
+ /** This can only be used by {@link #endLaunchPowerMode(int)}.*/
+ static final int POWER_MODE_REASON_ALL = (1 << 2) - 1;
+
+ /** The reasons to use {@link Mode#LAUNCH} power mode. */
+ private @PowerModeReason int mLaunchPowerModeReasons;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
LAYOUT_REASON_CONFIG_CHANGED,
LAYOUT_REASON_VISIBILITY_CHANGED,
})
@@ -4095,6 +4112,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return changes;
}
+ void startLaunchPowerMode(@PowerModeReason int reason) {
+ if (mPowerManagerInternal == null) return;
+ mPowerManagerInternal.setPowerMode(Mode.LAUNCH, true);
+ mLaunchPowerModeReasons |= reason;
+ }
+
+ void endLaunchPowerMode(@PowerModeReason int reason) {
+ if (mPowerManagerInternal == null || mLaunchPowerModeReasons == 0) return;
+ mLaunchPowerModeReasons &= ~reason;
+ if (mLaunchPowerModeReasons == 0) {
+ mPowerManagerInternal.setPowerMode(Mode.LAUNCH, false);
+ }
+ }
+
/** @see WindowSurfacePlacer#deferLayout */
void deferWindowLayout() {
if (!mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index de436437769a..1264d0c53e0c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1755,7 +1755,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
// End power mode launch before going sleep
- mRootWindowContainer.endPowerModeLaunchIfNeeded();
+ mService.endLaunchPowerMode(ActivityTaskManagerService.POWER_MODE_REASON_ALL);
removeSleepTimeouts();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 112fe526f0a8..23eab98a671a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1603,7 +1603,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
&& mFixedRotationLaunchingApp != mFixedRotationTransitionListener.mAnimatingRecents;
}
- @VisibleForTesting
boolean isFixedRotationLaunchingApp(ActivityRecord r) {
return mFixedRotationLaunchingApp == r;
}
@@ -1832,8 +1831,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (w.mHasSurface && !rotateSeamlessly) {
ProtoLog.v(WM_DEBUG_ORIENTATION, "Set mOrientationChanging of %s", w);
w.setOrientationChanging(true);
- mWmService.mRoot.mOrientationChangeComplete = false;
- w.mLastFreezeDuration = 0;
}
w.mReportOrientationChanged = true;
}, true /* traverseTopToBottom */);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 35611c055ea5..b106657dee99 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -1499,6 +1499,21 @@ public class DisplayRotation {
}
@Override
+ public boolean canUseRotationResolver() {
+ if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) return false;
+
+ switch (mCurrentAppOrientation) {
+ case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
+ case ActivityInfo.SCREEN_ORIENTATION_USER:
+ case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
+ case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
+ case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
+ return true;
+ }
+ return false;
+ }
+
+ @Override
public void onProposedRotationChanged(int rotation) {
ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation);
Runnable r = mRunnableCache.get(rotation, null);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 26f0f096278c..4f8ea1ac377a 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -284,7 +284,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, OnRootTaskOrderChan
// Just to be sure end the launch hint in case the target activity was never launched.
// However, if we're keeping the activity and making it visible, we can leave it on.
if (reorderMode != REORDER_KEEP_IN_PLACE) {
- mService.mRootWindowContainer.endPowerModeLaunchIfNeeded();
+ mService.endLaunchPowerMode(
+ ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY);
}
// Once the target is shown, prevent spurious background app switches
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2c97f783e14d..ceebe9550846 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -89,7 +89,6 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
-import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
@@ -267,9 +266,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
*/
final SparseArray<SleepToken> mSleepTokens = new SparseArray<>();
- /** Set when a power mode launch has started, but not ended. */
- private boolean mPowerModeLaunchStarted;
-
// The default minimal size that will be used if the activity doesn't specify its minimal size.
// It will be calculated when the default display gets added.
int mDefaultMinSizeOfResizeableTaskDp = -1;
@@ -1184,10 +1180,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mUpdateRotation = true;
doRequest = true;
}
- if ((bulkUpdateParams & SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
- mOrientationChangeComplete = false;
- } else {
- mOrientationChangeComplete = true;
+ if (mOrientationChangeComplete) {
mLastWindowFreezeSource = mWmService.mAnimator.mLastWindowFreezeSource;
if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
doRequest = true;
@@ -3327,7 +3320,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
}
// End power mode launch when idle.
- endPowerModeLaunchIfNeeded();
+ mService.endLaunchPowerMode(ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY);
return true;
}
@@ -3540,17 +3533,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
sendPowerModeLaunch = noResumedActivities[0] || allFocusedProcessesDiffer[0];
}
- if (sendPowerModeLaunch && mService.mPowerManagerInternal != null) {
- mService.mPowerManagerInternal.setPowerMode(Mode.LAUNCH, true);
- mPowerModeLaunchStarted = true;
- }
- }
-
- void endPowerModeLaunchIfNeeded() {
- // Trigger launch power mode off if activity is launched
- if (mPowerModeLaunchStarted && mService.mPowerManagerInternal != null) {
- mService.mPowerManagerInternal.setPowerMode(Mode.LAUNCH, false);
- mPowerModeLaunchStarted = false;
+ if (sendPowerModeLaunch) {
+ mService.startLaunchPowerMode(
+ ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY);
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e44a028c897f..9bbbbe0a8535 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -810,6 +810,16 @@ class Task extends WindowContainer<WindowContainer> {
private boolean mDeferTaskAppear;
/**
+ * Forces this task to be unorganized. Currently it is used for deferring the control of
+ * organizer when windowing mode is changing from PiP to fullscreen with orientation change.
+ * It is true only during Task#setWindowingMode ~ DisplayRotation#continueRotation.
+ *
+ * TODO(b/179235349): Remove this field by making surface operations from task organizer sync
+ * with display rotation.
+ */
+ private boolean mForceNotOrganized;
+
+ /**
* This task was created by the task organizer which has the following implementations.
* <ul>
* <lis>The task won't be removed when it is empty. Removal has to be an explicit request
@@ -2246,6 +2256,21 @@ class Task extends WindowContainer<WindowContainer> {
if (pipChanging) {
mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(true);
+ // If the top activity is using fixed rotation, it should be changing from PiP to
+ // fullscreen with display orientation change. Do not notify fullscreen task organizer
+ // because the restoration of task surface and the transformation of activity surface
+ // need to be done synchronously.
+ final ActivityRecord r = topRunningActivity();
+ if (r != null && mDisplayContent.isFixedRotationLaunchingApp(r)) {
+ mForceNotOrganized = true;
+ }
+ } else if (mForceNotOrganized) {
+ // If the display orientation change is done, let the corresponding task organizer take
+ // back the control of this task.
+ final ActivityRecord r = topRunningActivity();
+ if (r == null || !mDisplayContent.isFixedRotationLaunchingApp(r)) {
+ mForceNotOrganized = false;
+ }
}
try {
// We have 2 reasons why we need to report orientation change here.
@@ -2835,6 +2860,9 @@ class Task extends WindowContainer<WindowContainer> {
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
}
+ // Commit the resolved windowing mode so the canSpecifyOrientation won't get the old
+ // mode that may cause the bounds to be miscalculated, e.g. letterboxed.
+ getConfiguration().windowConfiguration.setWindowingMode(windowingMode);
Rect outOverrideBounds =
getResolvedOverrideConfiguration().windowConfiguration.getBounds();
@@ -4533,6 +4561,9 @@ class Task extends WindowContainer<WindowContainer> {
pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture);
pw.print(" isResizeable="); pw.println(isResizeable());
pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
+ if (mForceNotOrganized) {
+ pw.print(prefix); pw.println("mForceNotOrganized=true");
+ }
pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
}
@@ -4977,6 +5008,9 @@ class Task extends WindowContainer<WindowContainer> {
}
private boolean canBeOrganized() {
+ if (mForceNotOrganized) {
+ return false;
+ }
// All root tasks can be organized
if (isRootTask()) {
return true;
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index e18219ef4f46..622fe05b6170 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -497,7 +497,7 @@ class TaskChangeNotificationController {
void notifyTaskDisplayChanged(int taskId, int newDisplayId) {
final Message msg = mHandler.obtainMessage(NOTIFY_TASK_DISPLAY_CHANGED_LISTENERS_MSG,
taskId, newDisplayId);
- forAllLocalListeners(mNotifyTaskStackChanged, msg);
+ forAllLocalListeners(mNotifyTaskDisplayChanged, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 91a6664e0b36..eb32486d6023 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -26,7 +26,6 @@ import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import android.content.Context;
import android.os.Trace;
@@ -134,8 +133,10 @@ public class WindowAnimator {
// Schedule next frame already such that back-pressure happens continuously.
scheduleAnimation();
+ final RootWindowContainer root = mService.mRoot;
mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
- mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
+ mBulkUpdateParams = 0;
+ root.mOrientationChangeComplete = true;
if (DEBUG_WINDOW_TRACE) {
Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
}
@@ -144,14 +145,14 @@ public class WindowAnimator {
mService.openSurfaceTransaction();
try {
// Remove all deferred displays, tasks, and activities.
- mService.mRoot.handleCompleteDeferredRemoval();
+ root.handleCompleteDeferredRemoval();
final AccessibilityController accessibilityController =
mService.mAccessibilityController;
final int numDisplays = mDisplayContentsAnimators.size();
for (int i = 0; i < numDisplays; i++) {
final int displayId = mDisplayContentsAnimators.keyAt(i);
- final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+ final DisplayContent dc = root.getDisplayContent(displayId);
// Update animations of all applications, including those associated with
// exiting/removed apps.
dc.updateWindowsForAnimator();
@@ -160,7 +161,7 @@ public class WindowAnimator {
for (int i = 0; i < numDisplays; i++) {
final int displayId = mDisplayContentsAnimators.keyAt(i);
- final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+ final DisplayContent dc = root.getDisplayContent(displayId);
dc.checkAppWindowsReadyToShow();
if (accessibilityController != null) {
@@ -179,13 +180,14 @@ public class WindowAnimator {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
}
- final boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
- final boolean doRequest = mBulkUpdateParams != 0 && mService.mRoot.copyAnimToLayoutParams();
+ final boolean hasPendingLayoutChanges = root.hasPendingLayoutChanges(this);
+ final boolean doRequest = (mBulkUpdateParams != 0 || root.mOrientationChangeComplete)
+ && root.copyAnimToLayoutParams();
if (hasPendingLayoutChanges || doRequest) {
mService.mWindowPlacerLocked.requestTraversal();
}
- final boolean rootAnimating = mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */,
+ final boolean rootAnimating = root.isAnimating(TRANSITION | CHILDREN /* flags */,
ANIMATION_TYPE_ALL /* typesToCheck */);
if (rootAnimating && !mLastRootAnimating) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
@@ -197,7 +199,7 @@ public class WindowAnimator {
mLastRootAnimating = rootAnimating;
final boolean runningExpensiveAnimations =
- mService.mRoot.isAnimating(TRANSITION | CHILDREN /* flags */,
+ root.isAnimating(TRANSITION | CHILDREN /* flags */,
ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_SCREEN_ROTATION
| ANIMATION_TYPE_RECENTS /* typesToCheck */);
if (runningExpensiveAnimations && !mRunningExpensiveAnimations) {
@@ -216,7 +218,7 @@ public class WindowAnimator {
ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
if (mRemoveReplacedWindows) {
- mService.mRoot.removeReplacedWindows();
+ root.removeReplacedWindows();
mRemoveReplacedWindows = false;
}
@@ -235,8 +237,8 @@ public class WindowAnimator {
if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) {
builder.append(" UPDATE_ROTATION");
}
- if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
- builder.append(" ORIENTATION_CHANGE_COMPLETE");
+ if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING) != 0) {
+ builder.append(" SET_WALLPAPER_ACTION_PENDING");
}
return builder.toString();
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index bb04ace423c2..e183ea0d81ab 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -611,9 +611,9 @@ public abstract class WindowManagerInternal {
public abstract void removeNonHighRefreshRatePackage(@NonNull String packageName);
/**
- * Checks if this display is touchable.
+ * Checks if the device supports touch or faketouch.
*/
- public abstract boolean isTouchableDisplay(int displayId);
+ public abstract boolean isTouchOrFaketouchDevice();
/**
* Returns the info associated with the input token used to determine if a key should be
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a41761f529be..3c7bab3da279 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -100,6 +100,7 @@ import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN;
import static com.android.server.LockGuard.INDEX_WINDOW;
import static com.android.server.LockGuard.installLock;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_FREEZE_DISPLAY;
import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
import static com.android.server.wm.DisplayContent.IME_TARGET_INPUT;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
@@ -750,6 +751,7 @@ public class WindowManagerService extends IWindowManager.Stub
final TaskSnapshotController mTaskSnapshotController;
boolean mIsTouchDevice;
+ boolean mIsFakeTouchDevice;
final H mH = new H();
@@ -4960,6 +4962,8 @@ public class WindowManagerService extends IWindowManager.Stub
mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
+ mIsFakeTouchDevice = mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_FAKETOUCH);
}
try {
@@ -5726,8 +5730,6 @@ public class WindowManagerService extends IWindowManager.Stub
if (!w.mToken.okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
ProtoLog.v(WM_DEBUG_ORIENTATION, "Changing surface while display frozen: %s", w);
w.setOrientationChanging(true);
- w.mLastFreezeDuration = 0;
- mRoot.mOrientationChangeComplete = false;
if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
// XXX should probably keep timeout from
@@ -5838,6 +5840,9 @@ public class WindowManagerService extends IWindowManager.Stub
"startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s",
exitAnim, enterAnim, Debug.getCallers(8));
mScreenFrozenLock.acquire();
+ // Apply launch power mode to reduce screen frozen time because orientation change may
+ // relaunch activity and redraw windows. This may also help speed up user switching.
+ mAtmService.startLaunchPowerMode(POWER_MODE_REASON_FREEZE_DISPLAY);
mDisplayFrozen = true;
mDisplayFreezeTime = SystemClock.elapsedRealtime();
@@ -5981,6 +5986,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (configChanged) {
displayContent.sendNewConfiguration();
}
+ mAtmService.endLaunchPowerMode(POWER_MODE_REASON_FREEZE_DISPLAY);
mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN);
}
@@ -7956,13 +7962,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public boolean isTouchableDisplay(int displayId) {
+ public boolean isTouchOrFaketouchDevice() {
synchronized (mGlobalLock) {
- final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- final Configuration configuration =
- displayContent != null ? displayContent.getConfiguration() : null;
- return configuration != null
- && configuration.touchscreen == Configuration.TOUCHSCREEN_FINGER;
+ // All touchable devices are also faketouchable.
+ return mIsFakeTouchDevice;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrientationListener.java b/services/core/java/com/android/server/wm/WindowOrientationListener.java
index da31bb253831..5ef9420a10d8 100644
--- a/services/core/java/com/android/server/wm/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/wm/WindowOrientationListener.java
@@ -16,25 +16,36 @@
package com.android.server.wm;
+import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER;
+
import static com.android.server.wm.WindowOrientationListenerProto.ENABLED;
import static com.android.server.wm.WindowOrientationListenerProto.ROTATION;
+import android.app.ActivityThread;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.rotationresolver.RotationResolverInternal;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Surface;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.LocalServices;
import java.io.PrintWriter;
import java.util.List;
+import java.util.Set;
/**
* A special helper class used by the WindowManager
@@ -55,6 +66,9 @@ public abstract class WindowOrientationListener {
private static final boolean USE_GRAVITY_SENSOR = false;
private static final int DEFAULT_BATCH_LATENCY = 100000;
+ private static final int DEFAULT_ROTATION_RESOLVER_ENABLED = 0; // disabled
+ private static final String KEY_ROTATION_RESOLVER_TIMEOUT = "rotation_resolver_timeout_millis";
+ private static final long DEFAULT_ROTATION_RESOLVER_TIMEOUT_MILLIS = 700L;
private Handler mHandler;
private SensorManager mSensorManager;
@@ -62,7 +76,13 @@ public abstract class WindowOrientationListener {
private int mRate;
private String mSensorType;
private Sensor mSensor;
- private OrientationJudge mOrientationJudge;
+
+ @VisibleForTesting
+ OrientationJudge mOrientationJudge;
+
+ @VisibleForTesting
+ RotationResolverInternal mRotationResolverService;
+
private int mCurrentRotation = -1;
private final Context mContext;
private final WindowManagerConstants mConstants;
@@ -256,6 +276,32 @@ public abstract class WindowOrientationListener {
}
/**
+ * Returns true if the current status of the phone is suitable for using rotation resolver
+ * service.
+ *
+ * To reduce the power consumption of rotation resolver service, rotation query should run less
+ * frequently than other low power orientation sensors. This method is used to check whether
+ * the current status of the phone is necessary to request a suggested screen rotation from the
+ * rotation resolver service. Note that it always returns {@code false} in the base class. It
+ * should be overridden in the derived classes.
+ */
+ public boolean canUseRotationResolver() {
+ return false;
+ }
+
+ /**
+ * Returns true if the rotation resolver feature is enabled by setting. It means {@link
+ * WindowOrientationListener} will then ask {@link RotationResolverInternal} for the appropriate
+ * screen rotation.
+ */
+ @VisibleForTesting
+ boolean isRotationResolverEnabled() {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.CAMERA_AUTOROTATE, DEFAULT_ROTATION_RESOLVER_ENABLED,
+ UserHandle.USER_CURRENT) == 1;
+ }
+
+ /**
* Called when the rotation view of the device has changed.
*
* This method is called whenever the orientation becomes certain of an orientation.
@@ -1045,6 +1091,30 @@ public abstract class WindowOrientationListener {
private int mProposedRotation = -1;
private int mDesiredRotation = -1;
private boolean mRotationEvaluationScheduled;
+ private long mRotationResolverTimeoutMillis;
+
+ OrientationSensorJudge() {
+ super();
+ setupRotationResolverParameters();
+ }
+
+ private void setupRotationResolverParameters() {
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_WINDOW_MANAGER,
+ ActivityThread.currentApplication().getMainExecutor(), (properties) -> {
+ final Set<String> keys = properties.getKeyset();
+ if (keys.contains(KEY_ROTATION_RESOLVER_TIMEOUT)) {
+ readRotationResolverParameters();
+ }
+ });
+ readRotationResolverParameters();
+ }
+
+ private void readRotationResolverParameters() {
+ mRotationResolverTimeoutMillis = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_ROTATION_RESOLVER_TIMEOUT,
+ DEFAULT_ROTATION_RESOLVER_TIMEOUT_MILLIS);
+ }
@Override
public int getProposedRotationLocked() {
@@ -1069,19 +1139,13 @@ public abstract class WindowOrientationListener {
@Override
public void onSensorChanged(SensorEvent event) {
- int newRotation;
-
int reportedRotation = (int) event.values[0];
if (reportedRotation < 0 || reportedRotation > 3) {
return;
}
- synchronized (mLock) {
- mDesiredRotation = reportedRotation;
- newRotation = evaluateRotationChangeLocked();
- }
- if (newRotation >= 0) {
- onProposedRotationChanged(newRotation);
+ // Log raw sensor rotation.
+ if (evaluateRotationChangeLocked() >= 0) {
if (mConstants.mRawSensorLoggingEnabled) {
FrameworkStatsLog.write(
FrameworkStatsLog.DEVICE_ROTATED,
@@ -1089,6 +1153,35 @@ public abstract class WindowOrientationListener {
rotationToLogEnum(reportedRotation));
}
}
+
+ if (isRotationResolverEnabled() && canUseRotationResolver()) {
+ if (mRotationResolverService == null) {
+ mRotationResolverService = LocalServices.getService(
+ RotationResolverInternal.class);
+ }
+
+ final CancellationSignal cancellationSignal = new CancellationSignal();
+ mRotationResolverService.resolveRotation(
+ new RotationResolverInternal.RotationResolverCallbackInternal() {
+ @Override
+ public void onSuccess(int result) {
+ finalizeRotation(result);
+ }
+
+ @Override
+ public void onFailure(int error) {
+ finalizeRotation(reportedRotation);
+ }
+ },
+ reportedRotation,
+ mCurrentRotation,
+ mRotationResolverTimeoutMillis,
+ cancellationSignal);
+ getHandler().postDelayed(cancellationSignal::cancel,
+ mRotationResolverTimeoutMillis);
+ } else {
+ finalizeRotation(reportedRotation);
+ }
}
@Override
@@ -1131,6 +1224,17 @@ public abstract class WindowOrientationListener {
return -1;
}
+ private void finalizeRotation(int reportedRotation) {
+ int newRotation;
+ synchronized (mLock) {
+ mDesiredRotation = reportedRotation;
+ newRotation = evaluateRotationChangeLocked();
+ }
+ if (newRotation >= 0) {
+ onProposedRotationChanged(newRotation);
+ }
+ }
+
private boolean isDesiredRotationAcceptableLocked(long now) {
if (mTouching) {
return false;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 8b4d415efcb5..264a3b4edfa6 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1329,6 +1329,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mHasPendingConfigurationChange = true;
return;
}
+ dispatchConfiguration(config);
+ }
+
+ void dispatchConfiguration(Configuration config) {
mHasPendingConfigurationChange = false;
if (mThread == null) {
if (Build.IS_DEBUGGABLE && mHasImeService) {
@@ -1367,8 +1371,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mPauseConfigurationDispatchCount++;
}
- void resumeConfigurationDispatch() {
+ /** Returns {@code true} if the configuration change is pending to dispatch. */
+ boolean resumeConfigurationDispatch() {
+ if (mPauseConfigurationDispatchCount == 0) {
+ return false;
+ }
mPauseConfigurationDispatchCount--;
+ return mHasPendingConfigurationChange;
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fc1c7edb234c..fd3d9ba499b7 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1490,6 +1490,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void setOrientationChanging(boolean changing) {
mOrientationChanging = changing;
mOrientationChangeTimedOut = false;
+ if (changing) {
+ mLastFreezeDuration = 0;
+ mWmService.mRoot.mOrientationChangeComplete = false;
+ }
}
void orientationChangeTimedOut() {
@@ -3287,7 +3291,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
ProtoLog.v(WM_DEBUG_ORIENTATION,
"set mOrientationChanging of %s", this);
setOrientationChanging(true);
- mWmService.mRoot.mOrientationChangeComplete = false;
}
mLastFreezeDuration = 0;
setDisplayLayoutNeeded();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 2da3dda831e1..fe70dc12d3a2 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -52,7 +52,6 @@ import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowStateAnimatorProto.DRAW_STATE;
import static com.android.server.wm.WindowStateAnimatorProto.SURFACE;
import static com.android.server.wm.WindowStateAnimatorProto.SYSTEM_DECOR_RECT;
-import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import android.content.Context;
import android.graphics.Matrix;
@@ -664,7 +663,7 @@ class WindowStateAnimator {
if (w.getOrientationChanging()) {
if (!w.isDrawn()) {
- mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
+ w.mWmService.mRoot.mOrientationChangeComplete = false;
mAnimator.mLastWindowFreezeSource = w;
ProtoLog.v(WM_DEBUG_ORIENTATION,
"Orientation continue waiting for draw in %s", w);
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 6b9fbcbf459f..2ee5fb01efb3 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -43,8 +43,7 @@ class WindowSurfacePlacer {
private int mLayoutRepeatCount;
static final int SET_UPDATE_ROTATION = 1 << 0;
- static final int SET_ORIENTATION_CHANGE_COMPLETE = 1 << 2;
- static final int SET_WALLPAPER_ACTION_PENDING = 1 << 3;
+ static final int SET_WALLPAPER_ACTION_PENDING = 1 << 1;
private boolean mTraversalScheduled;
private int mDeferDepth = 0;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index c3a4609c02a1..1c3fe029a56b 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -630,9 +630,14 @@ class WindowToken extends WindowContainer<WindowState> {
void updateSurfacePosition(SurfaceControl.Transaction t) {
super.updateSurfacePosition(t);
if (isFixedRotationTransforming()) {
- // The window is layouted in a simulated rotated display but the real display hasn't
- // rotated, so here transforms its surface to fit in the real display.
- mFixedRotationTransformState.transform(this);
+ final ActivityRecord r = asActivityRecord();
+ final Task rootTask = r != null ? r.getRootTask() : null;
+ // Don't transform the activity in PiP because the PiP task organizer will handle it.
+ if (rootTask == null || !rootTask.inPinnedWindowingMode()) {
+ // The window is laid out in a simulated rotated display but the real display hasn't
+ // rotated, so here transforms its surface to fit in the real display.
+ mFixedRotationTransformState.transform(this);
+ }
}
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 5b587e9859d8..643503d18bed 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -106,6 +106,7 @@ static struct {
jmethodID notifyFocusChanged;
jmethodID notifySensorEvent;
jmethodID notifySensorAccuracy;
+ jmethodID notifyVibratorState;
jmethodID notifyUntrustedTouch;
jmethodID filterInputEvent;
jmethodID interceptKeyBeforeQueueing;
@@ -305,6 +306,7 @@ public:
const std::vector<float>& values) override;
void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
InputDeviceSensorAccuracy accuracy) override;
+ void notifyVibratorState(int32_t deviceId, bool isOn) override;
void notifyUntrustedTouch(const std::string& obscuringPackage) override;
bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
@@ -918,6 +920,18 @@ void NativeInputManager::notifySensorAccuracy(int32_t deviceId, InputDeviceSenso
checkAndClearExceptionFromCallback(env, "notifySensorAccuracy");
}
+void NativeInputManager::notifyVibratorState(int32_t deviceId, bool isOn) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ ALOGD("notifyVibratorState isOn:%d", isOn);
+#endif
+ ATRACE_CALL();
+ JNIEnv* env = jniEnv();
+ ScopedLocalFrame localFrame(env);
+ env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyVibratorState,
+ static_cast<jint>(deviceId), static_cast<jboolean>(isOn));
+ checkAndClearExceptionFromCallback(env, "notifyVibratorState");
+}
+
void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
@@ -2248,6 +2262,8 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gServiceClassInfo.notifySensorAccuracy, clazz, "notifySensorAccuracy", "(III)V");
+ GET_METHOD_ID(gServiceClassInfo.notifyVibratorState, clazz, "notifyVibratorState", "(IZ)V");
+
GET_METHOD_ID(gServiceClassInfo.notifyUntrustedTouch, clazz, "notifyUntrustedTouch",
"(Ljava/lang/String;)V");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7a4c611c57b0..98c3b99124ee 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -186,6 +186,7 @@ import com.android.server.telecom.TelecomLoaderService;
import com.android.server.testharness.TestHarnessModeService;
import com.android.server.textclassifier.TextClassificationManagerService;
import com.android.server.textservices.TextServicesManagerService;
+import com.android.server.tracing.TracingServiceProxy;
import com.android.server.trust.TrustManagerService;
import com.android.server.tv.TvInputManagerService;
import com.android.server.tv.TvRemoteService;
@@ -2483,6 +2484,11 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(AppBindingService.Lifecycle.class);
t.traceEnd();
+ // Perfetto TracingServiceProxy
+ t.traceBegin("startTracingServiceProxy");
+ mSystemServiceManager.startService(TracingServiceProxy.class);
+ t.traceEnd();
+
// It is now time to start up the app processes...
t.traceBegin("MakeVibratorServiceReady");
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
new file mode 100644
index 000000000000..5792e02e37a2
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test.verify.domain
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.content.pm.PackageUserState
+import android.content.pm.verify.domain.DomainVerificationManager
+import android.content.pm.parsing.component.ParsedActivity
+import android.content.pm.parsing.component.ParsedIntentInfo
+import android.os.Build
+import android.os.Process
+import android.util.ArraySet
+import android.util.SparseArray
+import com.android.server.pm.PackageSetting
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
+import com.android.server.pm.verify.domain.DomainVerificationService
+import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.testutils.mockThrowOnUnmocked
+import com.android.server.testutils.spyThrowOnUnmocked
+import com.android.server.testutils.whenever
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.mockito.Mockito
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyLong
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.verify
+import java.io.File
+import java.util.UUID
+
+@RunWith(Parameterized::class)
+class DomainVerificationSettingsMutationTest {
+
+ companion object {
+ private const val TEST_PKG = "com.test"
+
+ // Pretend to be the system. This class doesn't verify any enforcement behavior.
+ private const val TEST_UID = Process.SYSTEM_UID
+ private const val TEST_USER_ID = 10
+ private val TEST_UUID = UUID.fromString("5168e42e-327e-432b-b562-cfb553518a70")
+
+ @JvmStatic
+ @Parameterized.Parameters(name = "{0}")
+ fun parameters(): Array<Any> {
+ val context: Context = mockThrowOnUnmocked {
+ whenever(
+ enforcePermission(
+ eq(android.Manifest.permission.DOMAIN_VERIFICATION_AGENT),
+ anyInt(), anyInt(), anyString()
+ )
+ )
+ whenever(
+ enforcePermission(
+ eq(android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION),
+ anyInt(), anyInt(), anyString()
+ )
+ )
+ whenever(
+ enforcePermission(
+ eq(android.Manifest.permission.INTERACT_ACROSS_USERS),
+ anyInt(), anyInt(), anyString()
+ )
+ )
+ whenever(
+ enforcePermission(
+ eq(android.Manifest.permission.SET_PREFERRED_APPLICATIONS),
+ anyInt(), anyInt(), anyString()
+ )
+ )
+ }
+ val proxy: DomainVerificationProxy = mockThrowOnUnmocked {
+ whenever(isCallerVerifier(anyInt())) { true }
+ whenever(sendBroadcastForPackages(any()))
+ }
+
+ val makeService: (DomainVerificationManagerInternal.Connection) -> DomainVerificationService =
+ { connection ->
+ DomainVerificationService(
+ context,
+ mockThrowOnUnmocked { whenever(linkedApps) { ArraySet<String>() } },
+ mockThrowOnUnmocked {
+ whenever(isChangeEnabled(anyLong(),any())) { true }
+ }).apply {
+ setConnection(connection)
+ }
+ }
+
+ fun service(name: String, block: DomainVerificationService.() -> Unit) =
+ Params(makeService, name) { service ->
+ service.proxy = proxy
+ service.addPackage(mockPkgSetting())
+ service.block()
+ }
+
+ return arrayOf(
+ service("clearPackage") {
+ clearPackage(TEST_PKG)
+ },
+ service("clearUser") {
+ clearUser(TEST_USER_ID)
+ },
+ service("clearState") {
+ clearDomainVerificationState(listOf(TEST_PKG))
+ },
+ service("clearUserSelections") {
+ clearUserSelections(listOf(TEST_PKG), TEST_USER_ID)
+ },
+ service("setStatus") {
+ setDomainVerificationStatus(
+ TEST_UUID,
+ setOf("example.com"),
+ DomainVerificationManager.STATE_SUCCESS
+ )
+ },
+ service("setStatusInternalPackageName") {
+ setDomainVerificationStatusInternal(
+ TEST_PKG,
+ DomainVerificationManager.STATE_SUCCESS,
+ ArraySet(setOf("example.com"))
+ )
+ },
+ service("setStatusInternalUid") {
+ setDomainVerificationStatusInternal(
+ TEST_UID,
+ TEST_UUID,
+ setOf("example.com"),
+ DomainVerificationManager.STATE_SUCCESS
+ )
+ },
+ service("setLinkHandlingAllowed") {
+ setDomainVerificationLinkHandlingAllowed(TEST_PKG, true)
+ },
+ service("setLinkHandlingAllowedUserId") {
+ setDomainVerificationLinkHandlingAllowed(TEST_PKG, true, TEST_USER_ID)
+ },
+ service("setLinkHandlingAllowedInternal") {
+ setDomainVerificationLinkHandlingAllowedInternal(TEST_PKG, true, TEST_USER_ID)
+ },
+ service("setUserSelection") {
+ setDomainVerificationUserSelection(TEST_UUID, setOf("example.com"), true)
+ },
+ service("setUserSelectionUserId") {
+ setDomainVerificationUserSelection(
+ TEST_UUID,
+ setOf("example.com"),
+ true,
+ TEST_USER_ID
+ )
+ },
+ service("setUserSelectionInternal") {
+ setDomainVerificationUserSelectionInternal(
+ TEST_USER_ID,
+ TEST_PKG,
+ true,
+ ArraySet(setOf("example.com")),
+ )
+ },
+ service("setLegacyUserState") {
+ setLegacyUserState(
+ TEST_PKG,
+ TEST_USER_ID,
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER
+ )
+ },
+ )
+ }
+
+ data class Params(
+ val construct: (
+ DomainVerificationManagerInternal.Connection
+ ) -> DomainVerificationService,
+ val name: String,
+ val method: (DomainVerificationService) -> Unit
+ ) {
+ override fun toString() = name
+ }
+
+
+ fun mockPkg() = mockThrowOnUnmocked<AndroidPackage> {
+ whenever(packageName) { TEST_PKG }
+ whenever(targetSdkVersion) { Build.VERSION_CODES.S }
+ whenever(activities) {
+ listOf(
+ ParsedActivity().apply {
+ addIntent(
+ ParsedIntentInfo().apply {
+ autoVerify = true
+ addAction(Intent.ACTION_VIEW)
+ addCategory(Intent.CATEGORY_BROWSABLE)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ addDataScheme("https")
+ addDataAuthority("example.com", null)
+ }
+ )
+ }
+ )
+ }
+ }
+
+ // TODO: PackageSetting field encapsulation to move to whenever(name)
+ fun mockPkgSetting() = spyThrowOnUnmocked(
+ PackageSetting(
+ TEST_PKG,
+ TEST_PKG,
+ File("/test"),
+ null,
+ null,
+ null,
+ null,
+ 1,
+ 0,
+ 0,
+ 0,
+ null,
+ null,
+ null,
+ TEST_UUID
+ )
+ ) {
+ whenever(getPkg()) { mockPkg() }
+ whenever(domainSetId) { TEST_UUID }
+ whenever(userState) {
+ SparseArray<PackageUserState>().apply {
+ this[0] = PackageUserState()
+ }
+ }
+ }
+ }
+
+ @Parameterized.Parameter(0)
+ lateinit var params: Params
+
+ @Test
+ fun writeScheduled() {
+ val connection = mockConnection()
+ val service = params.construct(connection)
+ params.method(service)
+
+ verify(connection).scheduleWriteSettings()
+ }
+
+ private fun mockConnection(): DomainVerificationManagerInternal.Connection =
+ mockThrowOnUnmocked {
+ whenever(callingUid) { TEST_UID }
+ whenever(callingUserId) { TEST_USER_ID }
+ whenever(getPackageSettingLocked(TEST_PKG)) { mockPkgSetting() }
+ whenever(getPackageLocked(TEST_PKG)) { mockPkg() }
+ whenever(schedule(anyInt(), any()))
+ whenever(scheduleWriteSettings())
+ }
+}
diff --git a/services/tests/inprocesstests/AndroidTest.xml b/services/tests/inprocesstests/AndroidTest.xml
index 89abe3c0891c..b541512fdc9e 100644
--- a/services/tests/inprocesstests/AndroidTest.xml
+++ b/services/tests/inprocesstests/AndroidTest.xml
@@ -24,8 +24,8 @@
</target_preparer>
<!-- Restart to clear test code from system server -->
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="teardown-command" value="am restart" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
+ <option name="cleanup-action" value="REBOOT" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index af4130d92cfe..ca534927bd66 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -200,12 +200,12 @@ public class LocalDisplayAdapterTest {
}
private static class DisplayModeWrapper {
- public SurfaceControl.DisplayConfig config;
+ public SurfaceControl.DisplayMode mode;
public float[] expectedAlternativeRefreshRates;
- DisplayModeWrapper(SurfaceControl.DisplayConfig config,
+ DisplayModeWrapper(SurfaceControl.DisplayMode mode,
float[] expectedAlternativeRefreshRates) {
- this.config = config;
+ this.mode = mode;
this.expectedAlternativeRefreshRates = expectedAlternativeRefreshRates;
}
}
@@ -215,14 +215,15 @@ public class LocalDisplayAdapterTest {
* <code>expectedAlternativeRefreshRates</code> are present for each of the
* <code>modes</code>.
*/
- private void testAlternativeRefreshRatesCommon(FakeDisplay display, DisplayModeWrapper[] modes)
+ private void testAlternativeRefreshRatesCommon(FakeDisplay display,
+ DisplayModeWrapper[] wrappedModes)
throws InterruptedException {
// Update the display.
- SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[modes.length];
- for (int i = 0; i < modes.length; i++) {
- configs[i] = modes[i].config;
+ SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[wrappedModes.length];
+ for (int i = 0; i < wrappedModes.length; i++) {
+ modes[i] = wrappedModes[i].mode;
}
- display.configs = configs;
+ display.modes = modes;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
@@ -233,11 +234,11 @@ public class LocalDisplayAdapterTest {
mListener.changedDisplays.get(mListener.changedDisplays.size() - 1);
displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
Display.Mode[] supportedModes = displayDevice.getDisplayDeviceInfoLocked().supportedModes;
- assertThat(supportedModes.length).isEqualTo(configs.length);
+ assertThat(supportedModes.length).isEqualTo(modes.length);
- for (int i = 0; i < modes.length; i++) {
- assertModeIsSupported(supportedModes, configs[i],
- modes[i].expectedAlternativeRefreshRates);
+ for (int i = 0; i < wrappedModes.length; i++) {
+ assertModeIsSupported(supportedModes, modes[i],
+ wrappedModes[i].expectedAlternativeRefreshRates);
}
}
@@ -251,56 +252,56 @@ public class LocalDisplayAdapterTest {
testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 60f, 0), new float[]{24f, 50f}),
+ createFakeDisplayMode(1920, 1080, 60f, 0), new float[]{24f, 50f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 50f, 0), new float[]{24f, 60f}),
+ createFakeDisplayMode(1920, 1080, 50f, 0), new float[]{24f, 60f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 24f, 0), new float[]{50f, 60f}),
+ createFakeDisplayMode(1920, 1080, 24f, 0), new float[]{50f, 60f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 60f, 0), new float[]{24f, 50f}),
+ createFakeDisplayMode(3840, 2160, 60f, 0), new float[]{24f, 50f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 50f, 0), new float[]{24f, 60f}),
+ createFakeDisplayMode(3840, 2160, 50f, 0), new float[]{24f, 60f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 24f, 0), new float[]{50f, 60f}),
+ createFakeDisplayMode(3840, 2160, 24f, 0), new float[]{50f, 60f}),
});
testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 60f, 0), new float[]{50f}),
+ createFakeDisplayMode(1920, 1080, 60f, 0), new float[]{50f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 50f, 0), new float[]{60f}),
+ createFakeDisplayMode(1920, 1080, 50f, 0), new float[]{60f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 24f, 1), new float[0]),
+ createFakeDisplayMode(1920, 1080, 24f, 1), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 60f, 2), new float[0]),
+ createFakeDisplayMode(3840, 2160, 60f, 2), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 50f, 3), new float[]{24f}),
+ createFakeDisplayMode(3840, 2160, 50f, 3), new float[]{24f}),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 24f, 3), new float[]{50f}),
+ createFakeDisplayMode(3840, 2160, 24f, 3), new float[]{50f}),
});
testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 60f, 0), new float[0]),
+ createFakeDisplayMode(1920, 1080, 60f, 0), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 50f, 1), new float[0]),
+ createFakeDisplayMode(1920, 1080, 50f, 1), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(1920, 1080, 24f, 2), new float[0]),
+ createFakeDisplayMode(1920, 1080, 24f, 2), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 60f, 3), new float[0]),
+ createFakeDisplayMode(3840, 2160, 60f, 3), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 50f, 4), new float[0]),
+ createFakeDisplayMode(3840, 2160, 50f, 4), new float[0]),
new DisplayModeWrapper(
- createFakeDisplayConfig(3840, 2160, 24f, 5), new float[0]),
+ createFakeDisplayMode(3840, 2160, 24f, 5), new float[0]),
});
}
@Test
public void testAfterDisplayChange_DisplayModesAreUpdated() throws Exception {
- SurfaceControl.DisplayConfig displayConfig = createFakeDisplayConfig(1920, 1080, 60f);
- SurfaceControl.DisplayConfig[] configs =
- new SurfaceControl.DisplayConfig[]{displayConfig};
- FakeDisplay display = new FakeDisplay(PORT_A, configs, 0);
+ SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(1920, 1080, 60f);
+ SurfaceControl.DisplayMode[] modes =
+ new SurfaceControl.DisplayMode[]{displayMode};
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, 0);
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -312,29 +313,29 @@ public class LocalDisplayAdapterTest {
DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(
0).getDisplayDeviceInfoLocked();
- assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(configs.length);
- assertModeIsSupported(displayDeviceInfo.supportedModes, displayConfig);
+ assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(modes.length);
+ assertModeIsSupported(displayDeviceInfo.supportedModes, displayMode);
Display.Mode defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId);
- assertThat(defaultMode.matches(displayConfig.width, displayConfig.height,
- displayConfig.refreshRate)).isTrue();
+ assertThat(defaultMode.matches(displayMode.width, displayMode.height,
+ displayMode.refreshRate)).isTrue();
Display.Mode activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId);
- assertThat(activeMode.matches(displayConfig.width, displayConfig.height,
- displayConfig.refreshRate)).isTrue();
+ assertThat(activeMode.matches(displayMode.width, displayMode.height,
+ displayMode.refreshRate)).isTrue();
// Change the display
- SurfaceControl.DisplayConfig addedDisplayInfo = createFakeDisplayConfig(3840, 2160,
+ SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(3840, 2160,
60f);
- configs = new SurfaceControl.DisplayConfig[]{displayConfig, addedDisplayInfo};
- display.configs = configs;
- display.activeConfig = 1;
+ modes = new SurfaceControl.DisplayMode[]{displayMode, addedDisplayInfo};
+ display.modes = modes;
+ display.activeMode = 1;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
- assertThat(SurfaceControl.getActiveConfig(display.token)).isEqualTo(1);
- assertThat(SurfaceControl.getDisplayConfigs(display.token).length).isEqualTo(2);
+ assertThat(SurfaceControl.getActiveDisplayMode(display.token)).isEqualTo(1);
+ assertThat(SurfaceControl.getDisplayModes(display.token).length).isEqualTo(2);
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
@@ -343,8 +344,8 @@ public class LocalDisplayAdapterTest {
displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked();
- assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(configs.length);
- assertModeIsSupported(displayDeviceInfo.supportedModes, displayConfig);
+ assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(modes.length);
+ assertModeIsSupported(displayDeviceInfo.supportedModes, displayMode);
assertModeIsSupported(displayDeviceInfo.supportedModes, addedDisplayInfo);
activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId);
@@ -358,11 +359,11 @@ public class LocalDisplayAdapterTest {
@Test
public void testAfterDisplayChange_ActiveModeIsUpdated() throws Exception {
- SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[]{
- createFakeDisplayConfig(1920, 1080, 60f),
- createFakeDisplayConfig(1920, 1080, 50f)
+ SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(1920, 1080, 60f),
+ createFakeDisplayMode(1920, 1080, 50f)
};
- FakeDisplay display = new FakeDisplay(PORT_A, configs, /* activeConfig */ 0);
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, /* activeMode */ 0);
setUpDisplay(display);
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -378,12 +379,12 @@ public class LocalDisplayAdapterTest {
assertThat(activeMode.matches(1920, 1080, 60f)).isTrue();
// Change the display
- display.activeConfig = 1;
+ display.activeMode = 1;
setUpDisplay(display);
mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
- assertThat(SurfaceControl.getActiveConfig(display.token)).isEqualTo(1);
+ assertThat(SurfaceControl.getActiveDisplayMode(display.token)).isEqualTo(1);
assertThat(mListener.addedDisplays.size()).isEqualTo(1);
assertThat(mListener.changedDisplays.size()).isEqualTo(1);
@@ -471,14 +472,14 @@ public class LocalDisplayAdapterTest {
}
@Test
- public void testDisplayChange_withStaleDesiredDisplayConfigSpecs() throws Exception {
- SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[]{
- createFakeDisplayConfig(1920, 1080, 60f),
- createFakeDisplayConfig(1920, 1080, 50f)
+ public void testDisplayChange_withStaleDesiredDisplayModeSpecs() throws Exception {
+ SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(1920, 1080, 60f),
+ createFakeDisplayMode(1920, 1080, 50f)
};
- final int activeConfig = 0;
- FakeDisplay display = new FakeDisplay(PORT_A, configs, activeConfig);
- display.desiredDisplayConfigSpecs.defaultConfig = 1;
+ final int activeMode = 0;
+ FakeDisplay display = new FakeDisplay(PORT_A, modes, activeMode);
+ display.desiredDisplayModeSpecs.defaultMode = 1;
setUpDisplay(display);
updateAvailableDisplays();
@@ -486,12 +487,12 @@ public class LocalDisplayAdapterTest {
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
// Change the display
- display.configs = new SurfaceControl.DisplayConfig[]{
- createFakeDisplayConfig(1920, 1080, 60f)
+ display.modes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(1920, 1080, 60f)
};
- // SurfaceFlinger can return a stale defaultConfig. Make sure this doesn't
+ // SurfaceFlinger can return a stale defaultMode. Make sure this doesn't
// trigger ArrayOutOfBoundsException.
- display.desiredDisplayConfigSpecs.defaultConfig = 1;
+ display.desiredDisplayModeSpecs.defaultMode = 1;
setUpDisplay(display);
updateAvailableDisplays();
@@ -562,13 +563,13 @@ public class LocalDisplayAdapterTest {
}
private void assertModeIsSupported(Display.Mode[] supportedModes,
- SurfaceControl.DisplayConfig mode) {
+ SurfaceControl.DisplayMode mode) {
assertThat(Arrays.stream(supportedModes).anyMatch(
x -> x.matches(mode.width, mode.height, mode.refreshRate))).isTrue();
}
private void assertModeIsSupported(Display.Mode[] supportedModes,
- SurfaceControl.DisplayConfig mode, float[] alternativeRefreshRates) {
+ SurfaceControl.DisplayMode mode, float[] alternativeRefreshRates) {
float[] sortedAlternativeRates =
Arrays.copyOf(alternativeRefreshRates, alternativeRefreshRates.length);
Arrays.sort(sortedAlternativeRates);
@@ -588,13 +589,13 @@ public class LocalDisplayAdapterTest {
public final DisplayAddress.Physical address;
public final IBinder token = new Binder();
public final SurfaceControl.DisplayInfo info;
- public SurfaceControl.DisplayConfig[] configs;
- public int activeConfig;
+ public SurfaceControl.DisplayMode[] modes;
+ public int activeMode;
public int[] colorModes = new int[]{ Display.COLOR_MODE_DEFAULT };
public Display.HdrCapabilities hdrCapabilities = new Display.HdrCapabilities(new int[0],
1000, 1000, 0);
- public SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs =
- new SurfaceControl.DesiredDisplayConfigSpecs(/* defaultConfig */ 0,
+ public SurfaceControl.DesiredDisplayModeSpecs desiredDisplayModeSpecs =
+ new SurfaceControl.DesiredDisplayModeSpecs(/* defaultMode */ 0,
/* allowGroupSwitching */ false,
/* primaryRefreshRateMin */ 60.f,
/* primaryRefreshRateMax */ 60.f,
@@ -604,17 +605,17 @@ public class LocalDisplayAdapterTest {
private FakeDisplay(int port) {
this.address = createDisplayAddress(port);
this.info = createFakeDisplayInfo();
- this.configs = new SurfaceControl.DisplayConfig[]{
- createFakeDisplayConfig(800, 600, 60f)
+ this.modes = new SurfaceControl.DisplayMode[]{
+ createFakeDisplayMode(800, 600, 60f)
};
- this.activeConfig = 0;
+ this.activeMode = 0;
}
- private FakeDisplay(int port, SurfaceControl.DisplayConfig[] configs, int activeConfig) {
+ private FakeDisplay(int port, SurfaceControl.DisplayMode[] modes, int activeMode) {
this.address = createDisplayAddress(port);
this.info = createFakeDisplayInfo();
- this.configs = configs;
- this.activeConfig = activeConfig;
+ this.modes = modes;
+ this.activeMode = activeMode;
}
}
@@ -623,16 +624,16 @@ public class LocalDisplayAdapterTest {
doReturn(display.token).when(() ->
SurfaceControl.getPhysicalDisplayToken(display.address.getPhysicalDisplayId()));
doReturn(display.info).when(() -> SurfaceControl.getDisplayInfo(display.token));
- doReturn(display.configs).when(
- () -> SurfaceControl.getDisplayConfigs(display.token));
- doReturn(display.activeConfig).when(() -> SurfaceControl.getActiveConfig(display.token));
+ doReturn(display.modes).when(
+ () -> SurfaceControl.getDisplayModes(display.token));
+ doReturn(display.activeMode).when(() -> SurfaceControl.getActiveDisplayMode(display.token));
doReturn(0).when(() -> SurfaceControl.getActiveColorMode(display.token));
doReturn(display.colorModes).when(
() -> SurfaceControl.getDisplayColorModes(display.token));
doReturn(display.hdrCapabilities).when(
() -> SurfaceControl.getHdrCapabilities(display.token));
- doReturn(display.desiredDisplayConfigSpecs)
- .when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token));
+ doReturn(display.desiredDisplayModeSpecs)
+ .when(() -> SurfaceControl.getDesiredDisplayModeSpecs(display.token));
}
private void updateAvailableDisplays() {
@@ -655,21 +656,21 @@ public class LocalDisplayAdapterTest {
return info;
}
- private static SurfaceControl.DisplayConfig createFakeDisplayConfig(int width, int height,
+ private static SurfaceControl.DisplayMode createFakeDisplayMode(int width, int height,
float refreshRate) {
- return createFakeDisplayConfig(width, height, refreshRate, 0);
- }
-
- private static SurfaceControl.DisplayConfig createFakeDisplayConfig(int width, int height,
- float refreshRate, int configGroup) {
- final SurfaceControl.DisplayConfig config = new SurfaceControl.DisplayConfig();
- config.width = width;
- config.height = height;
- config.refreshRate = refreshRate;
- config.xDpi = 100;
- config.yDpi = 100;
- config.configGroup = configGroup;
- return config;
+ return createFakeDisplayMode(width, height, refreshRate, 0);
+ }
+
+ private static SurfaceControl.DisplayMode createFakeDisplayMode(int width, int height,
+ float refreshRate, int group) {
+ final SurfaceControl.DisplayMode mode = new SurfaceControl.DisplayMode();
+ mode.width = width;
+ mode.height = height;
+ mode.refreshRate = refreshRate;
+ mode.xDpi = 100;
+ mode.yDpi = 100;
+ mode.group = group;
+ return mode;
}
private static void waitForHandlerToComplete(Handler handler, long waitTimeMs)
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
new file mode 100644
index 000000000000..35ac8979d46a
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManagerInternal;
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.os.UserHandle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+import com.android.server.LocalServices;
+import com.android.server.job.JobConcurrencyManager.GracePeriodObserver;
+import com.android.server.job.controllers.JobStatus;
+import com.android.server.pm.UserManagerInternal;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class JobConcurrencyManagerTest {
+ private static final int UNAVAILABLE_USER = 0;
+ private JobConcurrencyManager mJobConcurrencyManager;
+ private UserManagerInternal mUserManagerInternal;
+ private ActivityManagerInternal mActivityManagerInternal;
+ private int mNextUserId;
+ private GracePeriodObserver mGracePeriodObserver;
+ private Context mContext;
+ private Resources mResources;
+
+ @BeforeClass
+ public static void setUpOnce() {
+ LocalServices.addService(UserManagerInternal.class, mock(UserManagerInternal.class));
+ LocalServices.addService(
+ ActivityManagerInternal.class, mock(ActivityManagerInternal.class));
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ }
+
+ @Before
+ public void setUp() {
+ final JobSchedulerService jobSchedulerService = mock(JobSchedulerService.class);
+ mContext = mock(Context.class);
+ mResources = mock(Resources.class);
+ doReturn(true).when(mResources).getBoolean(
+ R.bool.config_jobSchedulerRestrictBackgroundUser);
+ when(mContext.getResources()).thenReturn(mResources);
+ doReturn(mContext).when(jobSchedulerService).getTestableContext();
+ mJobConcurrencyManager = new JobConcurrencyManager(jobSchedulerService);
+ mGracePeriodObserver = mock(GracePeriodObserver.class);
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+ mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mNextUserId = 10;
+ mJobConcurrencyManager.mGracePeriodObserver = mGracePeriodObserver;
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_currentUser() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createCurrentUser(false))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_currentProfile() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createCurrentUser(true))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_primaryUser() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createPrimaryUser(false))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_primaryProfile() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createPrimaryUser(true))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_UnexpiredUser() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createUnexpiredUser(false))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_UnexpiredProfile() {
+ assertTrue(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createUnexpiredUser(true))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_restrictedUser() {
+ assertFalse(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createRestrictedUser(false))));
+ }
+
+ @Test
+ public void testShouldRunAsFgUserJob_restrictedProfile() {
+ assertFalse(mJobConcurrencyManager.shouldRunAsFgUserJob(
+ createJob(createRestrictedUser(true))));
+ }
+
+ private UserInfo createCurrentUser(boolean isProfile) {
+ final UserInfo ui = createNewUser();
+ doReturn(ui.id).when(mActivityManagerInternal).getCurrentUserId();
+ return isProfile ? createNewProfile(ui) : ui;
+ }
+
+ private UserInfo createPrimaryUser(boolean isProfile) {
+ final UserInfo ui = createNewUser();
+ doReturn(true).when(ui).isPrimary();
+ return isProfile ? createNewProfile(ui) : ui;
+ }
+
+ private UserInfo createUnexpiredUser(boolean isProfile) {
+ final UserInfo ui = createNewUser();
+ doReturn(true).when(mGracePeriodObserver).isWithinGracePeriodForUser(ui.id);
+ return isProfile ? createNewProfile(ui) : ui;
+ }
+
+ private UserInfo createRestrictedUser(boolean isProfile) {
+ final UserInfo ui = createNewUser();
+ doReturn(UNAVAILABLE_USER).when(mActivityManagerInternal).getCurrentUserId();
+ doReturn(false).when(ui).isPrimary();
+ doReturn(false).when(mGracePeriodObserver).isWithinGracePeriodForUser(ui.id);
+ return isProfile ? createNewProfile(ui) : ui;
+ }
+
+ private UserInfo createNewProfile(UserInfo parent) {
+ final UserInfo ui = createNewUser();
+ parent.profileGroupId = parent.id;
+ ui.profileGroupId = parent.id;
+ doReturn(true).when(ui).isProfile();
+ return ui;
+ }
+
+ private UserInfo createNewUser() {
+ final UserInfo ui = mock(UserInfo.class);
+ ui.id = mNextUserId++;
+ doReturn(ui).when(mUserManagerInternal).getUserInfo(ui.id);
+ ui.profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
+ return ui;
+ }
+
+ private static JobStatus createJob(UserInfo userInfo) {
+ JobStatus jobStatus = JobStatus.createFromJobInfo(
+ new JobInfo.Builder(1, new ComponentName("foo", "bar")).build(),
+ userInfo.id * UserHandle.PER_USER_RANGE,
+ null, userInfo.id, "JobConcurrencyManagerTest");
+ return jobStatus;
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 4effa4d445bb..f2bb47bfb8ad 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -62,6 +62,7 @@ import com.android.server.LocalServices;
import com.android.server.PowerAllowlistInternal;
import com.android.server.SystemServiceManager;
import com.android.server.job.controllers.JobStatus;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.usage.AppStandbyInternal;
import org.junit.After;
@@ -128,6 +129,9 @@ public class JobSchedulerServiceTest {
// Called in DeviceIdleJobsController constructor.
doReturn(mock(DeviceIdleInternal.class))
.when(() -> LocalServices.getService(DeviceIdleInternal.class));
+ // Used in JobConcurrencyManager.
+ doReturn(mock(UserManagerInternal.class))
+ .when(() -> LocalServices.getService(UserManagerInternal.class));
// Used in JobStatus.
doReturn(mock(PackageManagerInternal.class))
.when(() -> LocalServices.getService(PackageManagerInternal.class));
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 3b5cc887c798..54fa89a1e24b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -64,6 +64,7 @@ import android.location.LocationManagerInternal;
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.LocationRequest;
import android.location.LocationResult;
+import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
import android.location.provider.ProviderRequest;
import android.location.util.identity.CallerIdentity;
@@ -662,6 +663,23 @@ public class LocationProviderManagerTest {
}
@Test
+ public void testProviderRequestListener() throws Exception {
+ IProviderRequestListener requestListener = mock(IProviderRequestListener.class);
+ mManager.addProviderRequestListener(requestListener);
+
+ ILocationListener locationListener = createMockLocationListener();
+ LocationRequest request = new LocationRequest.Builder(1).setWorkSource(
+ WORK_SOURCE).build();
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, locationListener);
+
+ verify(requestListener, timeout(TIMEOUT_MS).times(1)).onProviderRequestChanged(anyString(),
+ any(ProviderRequest.class));
+
+ mManager.unregisterLocationRequest(locationListener);
+ mManager.removeProviderRequestListener(requestListener);
+ }
+
+ @Test
public void testGetCurrentLocation() throws Exception {
ILocationCallback listener = createMockGetCurrentLocationListener();
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml b/services/tests/servicestests/res/layout/widget_preview.xml
index e09bf7e37ed0..137ff46663d5 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp-land/bools.xml
+++ b/services/tests/servicestests/res/layout/widget_preview.xml
@@ -14,7 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<resources>
- <bool name="can_use_one_handed_bouncer">true</bool>
-</resources>
+<TextView android:id="@+id/widget_preview"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="Widget preview" /> \ No newline at end of file
diff --git a/services/tests/servicestests/res/xml/dummy_appwidget_info.xml b/services/tests/servicestests/res/xml/dummy_appwidget_info.xml
index 65462168c5d8..72f025dbabe9 100644
--- a/services/tests/servicestests/res/xml/dummy_appwidget_info.xml
+++ b/services/tests/servicestests/res/xml/dummy_appwidget_info.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 The Android Open Source Project
~
@@ -19,6 +20,7 @@
android:minHeight="40dp"
android:updatePeriodMillis="86400000"
android:previewImage="@drawable/icon1"
+ android:previewLayout="@layout/widget_preview"
android:resizeMode="horizontal|vertical"
android:description="@string/widget_description"
android:widgetCategory="home_screen">
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index 2a7905a451b9..633957a8b13a 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -50,6 +50,7 @@ import android.os.Looper;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Process;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
@@ -81,6 +82,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -92,6 +94,7 @@ import java.util.stream.Collectors;
@Presubmit
public class VibratorServiceTest {
+ private static final int TEST_TIMEOUT_MILLIS = 1_000;
private static final int UID = Process.ROOT_UID;
private static final int VIBRATOR_ID = 1;
private static final String PACKAGE_NAME = "package";
@@ -342,8 +345,8 @@ public class VibratorServiceTest {
verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
// VibrationThread will start this vibration async, so wait before checking it never played.
- Thread.sleep(10);
- assertTrue(mVibratorProvider.getEffects().isEmpty());
+ assertFalse(waitUntil(s -> !mVibratorProvider.getEffects().isEmpty(), service,
+ /* timeout= */ 20));
}
@Test
@@ -399,8 +402,8 @@ public class VibratorServiceTest {
verify(mIInputManagerMock).vibrate(eq(1), any(), any());
// VibrationThread will start this vibration async, so wait before checking it never played.
- Thread.sleep(10);
- assertTrue(mVibratorProvider.getEffects().isEmpty());
+ assertFalse(waitUntil(s -> !mVibratorProvider.getEffects().isEmpty(), service,
+ /* timeout= */ 20));
}
@Test
@@ -409,16 +412,10 @@ public class VibratorServiceTest {
mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
vibrate(service, VibrationEffect.createOneShot(1000, 100), HAPTIC_FEEDBACK_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before triggering callbacks.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
-
- // Wait for callback to cancel vibration.
- Thread.sleep(10);
- assertFalse(service.isVibrating());
+ assertTrue(waitUntil(s -> !s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
}
@Test
@@ -427,26 +424,18 @@ public class VibratorServiceTest {
mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
vibrate(service, VibrationEffect.createOneShot(1000, 100), RINGTONE_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before triggering callbacks.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
-
- // Wait for callback to cancel vibration.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ // Settings callback is async, so wait before checking it never got cancelled.
+ assertFalse(waitUntil(s -> !s.isVibrating(), service, /* timeout= */ 20));
}
@Test
public void vibrate_withSettingsChanged_doNotCancelVibration() throws Exception {
VibratorService service = createService();
vibrate(service, VibrationEffect.createOneShot(1000, 100), HAPTIC_FEEDBACK_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before triggering callbacks.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
Vibrator.VIBRATION_INTENSITY_MEDIUM);
@@ -454,9 +443,8 @@ public class VibratorServiceTest {
// FakeSettingsProvider don't support testing triggering ContentObserver yet.
service.updateVibrators();
- // Wait for callback to cancel vibration.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ // Settings callback is async, so wait before checking it never got cancelled.
+ assertFalse(waitUntil(s -> !s.isVibrating(), service, /* timeout= */ 20));
}
@Test
@@ -488,8 +476,8 @@ public class VibratorServiceTest {
inOrderVerifier.verify(mIInputManagerMock).vibrate(eq(2), eq(effect), any());
// VibrationThread will start this vibration async, so wait before checking it never played.
- Thread.sleep(10);
- assertTrue(mVibratorProvider.getEffects().isEmpty());
+ assertFalse(waitUntil(s -> !mVibratorProvider.getEffects().isEmpty(), service,
+ /* timeout= */ 20));
}
@Test
@@ -521,8 +509,8 @@ public class VibratorServiceTest {
verify(mIInputManagerMock).vibrate(eq(1), eq(effect), any());
// VibrationThread will start this vibration async, so wait before checking it never played.
- Thread.sleep(10);
- assertTrue(mVibratorProvider.getEffects().isEmpty());
+ assertFalse(waitUntil(s -> !mVibratorProvider.getEffects().isEmpty(), service,
+ /* timeout= */ 20));
}
@Test
@@ -531,18 +519,12 @@ public class VibratorServiceTest {
VibratorService service = createService();
vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before triggering callbacks.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
// Trigger callbacks from controller.
mTestLooper.moveTimeForward(50);
mTestLooper.dispatchAll();
-
- // VibrationThread needs some time to react to native callbacks and stop the vibrator.
- Thread.sleep(10);
- assertFalse(service.isVibrating());
+ assertTrue(waitUntil(s -> !s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
}
@Test
@@ -550,16 +532,10 @@ public class VibratorServiceTest {
VibratorService service = createService();
vibrate(service, VibrationEffect.createOneShot(100, 100), ALARM_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before checking.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
service.cancelVibrate(service);
-
- // VibrationThread will stop this vibration async, so wait before checking.
- Thread.sleep(10);
- assertFalse(service.isVibrating());
+ assertTrue(waitUntil(s -> !s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
}
@Test
@@ -584,17 +560,13 @@ public class VibratorServiceTest {
service.registerVibratorStateListener(mVibratorStateListenerMock);
vibrate(service, VibrationEffect.createOneShot(30, 100), ALARM_ATTRS);
-
- // VibrationThread will start this vibration async, so wait before triggering callbacks.
- Thread.sleep(10);
- assertTrue(service.isVibrating());
+ assertTrue(waitUntil(s -> s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
service.unregisterVibratorStateListener(mVibratorStateListenerMock);
// Trigger callbacks from controller.
mTestLooper.moveTimeForward(50);
mTestLooper.dispatchAll();
- Thread.sleep(20);
- assertFalse(service.isVibrating());
+ assertTrue(waitUntil(s -> !s.isVibrating(), service, TEST_TIMEOUT_MILLIS));
InOrder inOrderVerifier = inOrder(mVibratorStateListenerMock);
// First notification done when listener is registered.
@@ -771,4 +743,15 @@ public class VibratorServiceTest {
private void setGlobalSetting(String settingName, int value) {
Settings.Global.putInt(mContextSpy.getContentResolver(), settingName, value);
}
+
+ private boolean waitUntil(Predicate<VibratorService> predicate,
+ VibratorService service, long timeout) throws InterruptedException {
+ long timeoutTimestamp = SystemClock.uptimeMillis() + timeout;
+ boolean predicateResult = false;
+ while (!predicateResult && SystemClock.uptimeMillis() < timeoutTimestamp) {
+ Thread.sleep(10);
+ predicateResult = predicate.test(service);
+ }
+ return predicateResult;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 27edfd4ef1d2..6963a1ab1538 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -110,8 +110,6 @@ public class AccessibilityServiceConnectionTest {
mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
when(mMockIBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
- when(mMockWindowManagerInternal.isTouchableDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
- true);
mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
@@ -197,8 +195,9 @@ public class AccessibilityServiceConnectionTest {
}
@Test
- public void sendGesture_touchableDisplay_injectEvents()
+ public void sendGesture_touchableDevice_injectEvents()
throws RemoteException {
+ when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(true);
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
@@ -213,10 +212,9 @@ public class AccessibilityServiceConnectionTest {
}
@Test
- public void sendGesture_untouchableDisplay_performGestureResultFailed()
+ public void sendGesture_untouchableDevice_performGestureResultFailed()
throws RemoteException {
- when(mMockWindowManagerInternal.isTouchableDisplay(Display.DEFAULT_DISPLAY)).thenReturn(
- false);
+ when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(false);
setServiceBinding(COMPONENT_NAME);
mConnection.bindLocked();
mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index 96f434405199..78eb2df58925 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -16,6 +16,8 @@
package com.android.server.appwidget;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -44,6 +46,7 @@ import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.widget.RemoteViews;
+import com.android.frameworks.servicestests.R;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.server.LocalServices;
@@ -293,6 +296,13 @@ public class AppWidgetServiceImplTest extends InstrumentationTestCase {
}
}
+ public void testGetPreviewLayout() {
+ AppWidgetProviderInfo info =
+ mManager.getInstalledProvidersForPackage(mPkgName, null).get(0);
+
+ assertThat(info.previewLayout).isEqualTo(R.layout.widget_preview);
+ }
+
private int setupHostAndWidget() {
List<PendingHostUpdate> updates = mService.startListening(
mMockHost, mPkgName, HOST_ID, new int[0]).getList();
diff --git a/services/tests/servicestests/src/com/android/server/job/GracePeriodObserverTest.java b/services/tests/servicestests/src/com/android/server/job/GracePeriodObserverTest.java
new file mode 100644
index 000000000000..1915b8c36892
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/GracePeriodObserverTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.job;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.app.ActivityManagerInternal;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.SystemClock;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.job.JobConcurrencyManager.GracePeriodObserver;
+import com.android.server.pm.UserManagerInternal;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.time.ZoneOffset;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class GracePeriodObserverTest {
+ private GracePeriodObserver mGracePeriodObserver;
+ private UserManagerInternal mUserManagerInternal;
+ private static final int FIRST_USER = 0;
+
+ @BeforeClass
+ public static void setUpOnce() {
+ UserManagerInternal userManagerInternal = mock(UserManagerInternal.class);
+ LocalServices.addService(UserManagerInternal.class, userManagerInternal);
+ ActivityManagerInternal activityManagerInternal = mock(ActivityManagerInternal.class);
+ LocalServices.addService(ActivityManagerInternal.class, activityManagerInternal);
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+ }
+
+ @Before
+ public void setUp() {
+ final Context context = ApplicationProvider.getApplicationContext();
+ JobSchedulerService.sElapsedRealtimeClock =
+ Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
+ doReturn(FIRST_USER)
+ .when(LocalServices.getService(ActivityManagerInternal.class)).getCurrentUserId();
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+ doReturn(true).when(mUserManagerInternal).exists(FIRST_USER);
+ mGracePeriodObserver = new GracePeriodObserver(context);
+ }
+
+ @Test
+ public void testGracePeriod() throws RemoteException {
+ final int oldUser = FIRST_USER;
+ final int newUser = 10;
+ doReturn(true).when(mUserManagerInternal).exists(newUser);
+ mGracePeriodObserver.onUserSwitchComplete(newUser);
+ assertTrue(mGracePeriodObserver.isWithinGracePeriodForUser(oldUser));
+ JobSchedulerService.sElapsedRealtimeClock =
+ Clock.offset(JobSchedulerService.sElapsedRealtimeClock,
+ Duration.ofMillis(mGracePeriodObserver.mGracePeriod));
+ assertFalse(mGracePeriodObserver.isWithinGracePeriodForUser(oldUser));
+ }
+
+ @Test
+ public void testCleanUp() throws RemoteException {
+ final int removedUser = FIRST_USER;
+ final int newUser = 10;
+ mGracePeriodObserver.onUserSwitchComplete(newUser);
+
+ final int sizeBefore = mGracePeriodObserver.mGracePeriodExpiration.size();
+ doReturn(false).when(mUserManagerInternal).exists(removedUser);
+
+ mGracePeriodObserver.onUserRemoved(removedUser);
+ assertEquals(sizeBefore - 1, mGracePeriodObserver.mGracePeriodExpiration.size());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
index 263cf48a8a18..353ac4bd2129 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
@@ -16,7 +16,10 @@
package com.android.server.job;
+import static com.android.server.job.JobConcurrencyManager.NUM_WORK_TYPES;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
@@ -47,6 +50,10 @@ import java.util.Random;
public class WorkCountTrackerTest {
private static final String TAG = "WorkerCountTrackerTest";
+ private static final double[] EQUAL_PROBABILITY_CDF =
+ buildCdf(1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES, 1.0 / NUM_WORK_TYPES,
+ 1.0 / NUM_WORK_TYPES);
+
private Random mRandom;
private WorkCountTracker mWorkCountTracker;
@@ -56,6 +63,47 @@ public class WorkCountTrackerTest {
mWorkCountTracker = new WorkCountTracker();
}
+ @NonNull
+ private static double[] buildCdf(double pTop, double pEj, double pBg, double pBgUser) {
+ double[] cdf = new double[JobConcurrencyManager.NUM_WORK_TYPES];
+ double sum = 0;
+
+ sum += pTop;
+ cdf[0] = sum;
+ sum += pEj;
+ cdf[1] = sum;
+ sum += pBg;
+ cdf[2] = sum;
+ sum += pBgUser;
+ cdf[3] = sum;
+
+ if (Double.compare(1, sum) != 0) {
+ throw new IllegalArgumentException("probabilities don't sum to one: " + sum);
+ }
+ return cdf;
+ }
+
+ @JobConcurrencyManager.WorkType
+ static int getRandomWorkType(double[] cdf, double rand) {
+ for (int i = cdf.length - 1; i >= 0; --i) {
+ if (rand < cdf[i] && (i == 0 || rand > cdf[i - 1])) {
+ switch (i) {
+ case 0:
+ return WORK_TYPE_TOP;
+ case 1:
+ return WORK_TYPE_EJ;
+ case 2:
+ return WORK_TYPE_BG;
+ case 3:
+ return WORK_TYPE_BGUSER;
+ default:
+ throw new IllegalStateException("Unknown work type");
+ }
+ }
+ }
+ throw new IllegalStateException("Couldn't pick random work type");
+ }
+
/**
* Represents running and pending jobs.
*/
@@ -63,25 +111,22 @@ public class WorkCountTrackerTest {
public final SparseIntArray running = new SparseIntArray();
public final SparseIntArray pending = new SparseIntArray();
- public void maybeEnqueueJobs(double startRatio, double fgJobRatio) {
- while (mRandom.nextDouble() < startRatio) {
- if (mRandom.nextDouble() < fgJobRatio) {
- pending.put(WORK_TYPE_TOP, pending.get(WORK_TYPE_TOP) + 1);
- } else {
- pending.put(WORK_TYPE_BG, pending.get(WORK_TYPE_BG) + 1);
- }
+ public void maybeEnqueueJobs(double probStart, double[] typeCdf) {
+ while (mRandom.nextDouble() < probStart) {
+ final int workType = getRandomWorkType(typeCdf, mRandom.nextDouble());
+ pending.put(workType, pending.get(workType) + 1);
}
}
- public void maybeFinishJobs(double stopRatio) {
+ public void maybeFinishJobs(double probStop) {
for (int i = running.get(WORK_TYPE_BG); i > 0; i--) {
- if (mRandom.nextDouble() < stopRatio) {
+ if (mRandom.nextDouble() < probStop) {
running.put(WORK_TYPE_BG, running.get(WORK_TYPE_BG) - 1);
mWorkCountTracker.onJobFinished(WORK_TYPE_BG);
}
}
for (int i = running.get(WORK_TYPE_TOP); i > 0; i--) {
- if (mRandom.nextDouble() < stopRatio) {
+ if (mRandom.nextDouble() < probStop) {
running.put(WORK_TYPE_TOP, running.get(WORK_TYPE_TOP) - 1);
mWorkCountTracker.onJobFinished(WORK_TYPE_TOP);
}
@@ -116,29 +161,27 @@ public class WorkCountTrackerTest {
mWorkCountTracker.onCountDone();
}
+ private boolean hasStartablePendingJob(Jobs jobs) {
+ for (int i = 0; i < jobs.pending.size(); ++i) {
+ if (jobs.pending.valueAt(i) > 0
+ && mWorkCountTracker.canJobStart(jobs.pending.keyAt(i)) != WORK_TYPE_NONE) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void startPendingJobs(Jobs jobs) {
- while ((jobs.pending.get(WORK_TYPE_TOP) > 0
- && mWorkCountTracker.canJobStart(WORK_TYPE_TOP) != WORK_TYPE_NONE)
- || (jobs.pending.get(WORK_TYPE_BG) > 0
- && mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE)) {
- final boolean isStartingFg = mRandom.nextBoolean();
-
- if (isStartingFg) {
- if (jobs.pending.get(WORK_TYPE_TOP) > 0
- && mWorkCountTracker.canJobStart(WORK_TYPE_TOP) != WORK_TYPE_NONE) {
- jobs.pending.put(WORK_TYPE_TOP, jobs.pending.get(WORK_TYPE_TOP) - 1);
- jobs.running.put(WORK_TYPE_TOP, jobs.running.get(WORK_TYPE_TOP) + 1);
- mWorkCountTracker.stageJob(WORK_TYPE_TOP);
- mWorkCountTracker.onJobStarted(WORK_TYPE_TOP);
- }
- } else {
- if (jobs.pending.get(WORK_TYPE_BG) > 0
- && mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE) {
- jobs.pending.put(WORK_TYPE_BG, jobs.pending.get(WORK_TYPE_BG) - 1);
- jobs.running.put(WORK_TYPE_BG, jobs.running.get(WORK_TYPE_BG) + 1);
- mWorkCountTracker.stageJob(WORK_TYPE_BG);
- mWorkCountTracker.onJobStarted(WORK_TYPE_BG);
- }
+ while (hasStartablePendingJob(jobs)) {
+ final int startingWorkType =
+ getRandomWorkType(EQUAL_PROBABILITY_CDF, mRandom.nextDouble());
+
+ if (jobs.pending.get(startingWorkType) > 0
+ && mWorkCountTracker.canJobStart(startingWorkType) != WORK_TYPE_NONE) {
+ jobs.pending.put(startingWorkType, jobs.pending.get(startingWorkType) - 1);
+ jobs.running.put(startingWorkType, jobs.running.get(startingWorkType) + 1);
+ mWorkCountTracker.stageJob(startingWorkType);
+ mWorkCountTracker.onJobStarted(startingWorkType);
}
}
}
@@ -149,10 +192,10 @@ public class WorkCountTrackerTest {
private void checkRandom(Jobs jobs, int numTests, int totalMax,
@NonNull List<Pair<Integer, Integer>> minLimits,
@NonNull List<Pair<Integer, Integer>> maxLimits,
- double startRatio, double fgJobRatio, double stopRatio) {
+ double probStart, double[] typeCdf, double probStop) {
for (int i = 0; i < numTests; i++) {
- jobs.maybeFinishJobs(stopRatio);
- jobs.maybeEnqueueJobs(startRatio, fgJobRatio);
+ jobs.maybeFinishJobs(probStop);
+ jobs.maybeEnqueueJobs(probStart, typeCdf);
recount(jobs, totalMax, minLimits, maxLimits);
startPendingJobs(jobs);
@@ -178,18 +221,19 @@ public class WorkCountTrackerTest {
*/
@Test
public void testRandom1() {
+ assertThat(EQUAL_PROBABILITY_CDF.length).isEqualTo(NUM_WORK_TYPES);
+
final Jobs jobs = new Jobs();
final int numTests = 5000;
final int totalMax = 6;
final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
- final double stopRatio = 0.1;
- final double fgJobRatio = 0.5;
- final double startRatio = 0.1;
+ final double probStop = 0.1;
+ final double probStart = 0.1;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ EQUAL_PROBABILITY_CDF, probStop);
}
@Test
@@ -198,14 +242,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 2;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of();
- final double stopRatio = 0.5;
- final double fgJobRatio = 0.5;
- final double startRatio = 0.5;
+ final double probStop = 0.5;
+ final double[] cdf = buildCdf(0.5, 0, 0.5, 0);
+ final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
}
@Test
@@ -214,14 +258,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 2;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
- final double stopRatio = 0.5;
- final double fgJobRatio = 0.5;
- final double startRatio = 0.5;
+ final double probStop = 0.5;
+ final double[] cdf = buildCdf(1.0 / 3, 0, 1.0 / 3, 1.0 / 3);
+ final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
}
@Test
@@ -230,14 +274,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 10;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
final List<Pair<Integer, Integer>> minLimits = List.of();
- final double stopRatio = 0.5;
- final double fgJobRatio = 0.5;
- final double startRatio = 0.5;
+ final double probStop = 0.5;
+ final double[] cdf = buildCdf(1.0 / 3, 0, 1.0 / 3, 1.0 / 3);
+ final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
}
@Test
@@ -246,14 +290,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
- final double stopRatio = 0.5;
- final double fgJobRatio = 0.1;
- final double startRatio = 0.5;
+ final double probStop = 0.5;
+ final double[] cdf = buildCdf(0.1, 0, 0.8, .1);
+ final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
}
@Test
@@ -262,14 +306,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
- final double stopRatio = 0.5;
- final double fgJobRatio = 0.9;
- final double startRatio = 0.5;
+ final double probStop = 0.5;
+ final double[] cdf = buildCdf(0.9, 0, 0.1, 0);
+ final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
}
@Test
@@ -278,14 +322,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 6;
- final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
- final double stopRatio = 0.4;
- final double fgJobRatio = 0.1;
- final double startRatio = 0.5;
+ final double probStop = 0.4;
+ final double[] cdf = buildCdf(0.1, 0, 0.1, .8);
+ final double probStart = 0.5;
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
}
@Test
@@ -294,14 +338,136 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 6;
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final double probStop = 0.4;
+ final double[] cdf = buildCdf(0.9, 0, 0.05, 0.05);
+ final double probStart = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ }
+
+ @Test
+ public void testRandom9() {
+ final Jobs jobs = new Jobs();
+
+ final int numTests = 5000;
+ final int totalMax = 6;
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final double probStop = 0.5;
+ final double[] cdf = buildCdf(0, 0, 0.5, 0.5);
+ final double probStart = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ }
+
+ @Test
+ public void testRandom10() {
+ final Jobs jobs = new Jobs();
+
+ final int numTests = 5000;
+ final int totalMax = 6;
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final double probStop = 0.5;
+ final double[] cdf = buildCdf(0, 0, 0.1, 0.9);
+ final double probStart = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ }
+
+ @Test
+ public void testRandom11() {
+ final Jobs jobs = new Jobs();
+
+ final int numTests = 5000;
+ final int totalMax = 6;
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1));
+ final double probStop = 0.5;
+ final double[] cdf = buildCdf(0, 0, 0.9, 0.1);
+ final double probStart = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ }
+
+ @Test
+ public void testRandom12() {
+ final Jobs jobs = new Jobs();
+
+ final int numTests = 5000;
+ final int totalMax = 6;
final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2));
+ final double probStop = 0.4;
+ final double[] cdf = buildCdf(0.5, 0.5, 0, 0);
+ final double probStart = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ }
+
+ @Test
+ public void testRandom13() {
+ assertThat(EQUAL_PROBABILITY_CDF.length).isEqualTo(NUM_WORK_TYPES);
+
+ final Jobs jobs = new Jobs();
+
+ final int numTests = 5000;
+ final int totalMax = 13;
+ final List<Pair<Integer, Integer>> maxLimits = List.of(
+ Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4),
+ Pair.create(WORK_TYPE_BGUSER, 3));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1));
+ final double probStop = 0.01;
+ final double probStart = 0.99;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart,
+ EQUAL_PROBABILITY_CDF, probStop);
+ }
+
+ @Test
+ public void testRandom14() {
+ final Jobs jobs = new Jobs();
+
+ final int numTests = 5000;
+ final int totalMax = 6;
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4));
final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
- final double stopRatio = 0.4;
- final double fgJobRatio = 0.9;
- final double startRatio = 0.5;
+ final double probStop = 0.4;
+ final double[] cdf = buildCdf(.1, 0.5, 0.35, 0.05);
+ final double probStart = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
+ }
+
+ @Test
+ public void testRandom15() {
+ final Jobs jobs = new Jobs();
- checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
- startRatio, fgJobRatio, stopRatio);
+ final int numTests = 5000;
+ final int totalMax = 6;
+ final List<Pair<Integer, Integer>> maxLimits =
+ List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4),
+ Pair.create(WORK_TYPE_BGUSER, 1));
+ final List<Pair<Integer, Integer>> minLimits =
+ List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2));
+ final double probStop = 0.4;
+ final double[] cdf = buildCdf(0.01, 0.49, 0.1, 0.4);
+ final double probStart = 0.5;
+
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, cdf, probStop);
}
/** Used by the following tests */
@@ -337,7 +503,7 @@ public class WorkCountTrackerTest {
public void testBasic() {
checkSimple(6,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
@@ -345,7 +511,7 @@ public class WorkCountTrackerTest {
checkSimple(6,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
@@ -354,7 +520,7 @@ public class WorkCountTrackerTest {
// When there are BG jobs pending, 2 (min-BG) jobs should run.
checkSimple(6,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
- /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
/* run */ List.of(),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1)),
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1)),
@@ -385,6 +551,16 @@ public class WorkCountTrackerTest {
checkSimple(8,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 49), Pair.create(WORK_TYPE_BG, 49)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 4)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 47), Pair.create(WORK_TYPE_BG, 49))
+ );
+
+
+ checkSimple(8,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
/* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 6)),
/* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)),
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
@@ -407,6 +583,14 @@ public class WorkCountTrackerTest {
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
+ checkSimple(8,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
+ /* run */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
+
checkSimple(6,
/* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
/* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
@@ -415,6 +599,16 @@ public class WorkCountTrackerTest {
/* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)));
+ checkSimple(8,
+ /* min */ List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* run */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_EJ, 5),
+ Pair.create(WORK_TYPE_BG, 3)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_EJ, 2)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3),
+ Pair.create(WORK_TYPE_BG, 3)));
+
// This could happen if we lower the effective config due to higher memory pressure after
// we've already started running jobs. We shouldn't stop already running jobs, but also
// shouldn't start new ones.
@@ -425,6 +619,38 @@ public class WorkCountTrackerTest {
/* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)),
/* resRun */ List.of(Pair.create(WORK_TYPE_BG, 6)),
/* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)));
+
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
+ /* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10),
+ Pair.create(WORK_TYPE_BG, 3),
+ Pair.create(WORK_TYPE_BGUSER, 3)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 6),
+ Pair.create(WORK_TYPE_BG, 3),
+ Pair.create(WORK_TYPE_BGUSER, 3)));
+
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 3)),
+ /* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 3)),
+ /* resRun */ List.of(
+ Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)),
+ /* resPen */ List.of(
+ Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)));
+
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)),
+ /* run */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 3)),
+ /* resRun */ List.of(
+ Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)),
+ /* resPen */ List.of(
+ Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 2)));
}
/** Tests that the counter updates properly when jobs are stopped. */
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
index c28292f03357..2288a8925561 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java
@@ -16,8 +16,11 @@
package com.android.server.job;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER;
+import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_EJ;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import android.annotation.NonNull;
@@ -31,11 +34,9 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.server.job.JobConcurrencyManager.WorkTypeConfig;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.ArrayList;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@@ -43,9 +44,13 @@ import java.util.List;
public class WorkTypeConfigTest {
private static final String KEY_MAX_TOTAL = "concurrency_max_total_test";
private static final String KEY_MAX_TOP = "concurrency_max_top_test";
+ private static final String KEY_MAX_EJ = "concurrency_max_ej_test";
private static final String KEY_MAX_BG = "concurrency_max_bg_test";
+ private static final String KEY_MAX_BGUSER = "concurrency_max_bguser_test";
private static final String KEY_MIN_TOP = "concurrency_min_top_test";
+ private static final String KEY_MIN_EJ = "concurrency_min_ej_test";
private static final String KEY_MIN_BG = "concurrency_min_bg_test";
+ private static final String KEY_MIN_BGUSER = "concurrency_min_bguser_test";
@After
public void tearDown() throws Exception {
@@ -56,43 +61,27 @@ public class WorkTypeConfigTest {
// DeviceConfig.resetToDefaults() doesn't work here. Need to reset constants manually.
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOTAL, "", false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_TOP, "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_EJ, "", false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BG, "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MAX_BGUSER, "", false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_TOP, "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_EJ, "", false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BG, "", false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_JOB_SCHEDULER, KEY_MIN_BGUSER, "", false);
}
private void check(@Nullable DeviceConfig.Properties config,
int defaultTotal,
- @Nullable Pair<Integer, Integer> defaultTopLimits,
- @Nullable Pair<Integer, Integer> defaultBgLimits,
+ @NonNull List<Pair<Integer, Integer>> defaultMin,
+ @NonNull List<Pair<Integer, Integer>> defaultMax,
boolean expectedValid, int expectedTotal,
- @NonNull Pair<Integer, Integer> expectedTopLimits,
- @NonNull Pair<Integer, Integer> expectedBgLimits) throws Exception {
+ @NonNull List<Pair<Integer, Integer>> expectedMinLimits,
+ @NonNull List<Pair<Integer, Integer>> expectedMaxLimits) throws Exception {
resetConfig();
if (config != null) {
DeviceConfig.setProperties(config);
}
- List<Pair<Integer, Integer>> defaultMin = new ArrayList<>();
- List<Pair<Integer, Integer>> defaultMax = new ArrayList<>();
- Integer val;
- if (defaultTopLimits != null) {
- if ((val = defaultTopLimits.first) != null) {
- defaultMin.add(Pair.create(WORK_TYPE_TOP, val));
- }
- if ((val = defaultTopLimits.second) != null) {
- defaultMax.add(Pair.create(WORK_TYPE_TOP, val));
- }
- }
- if (defaultBgLimits != null) {
- if ((val = defaultBgLimits.first) != null) {
- defaultMin.add(Pair.create(WORK_TYPE_BG, val));
- }
- if ((val = defaultBgLimits.second) != null) {
- defaultMax.add(Pair.create(WORK_TYPE_BG, val));
- }
- }
-
final WorkTypeConfig counts;
try {
counts = new WorkTypeConfig("test",
@@ -112,40 +101,126 @@ public class WorkTypeConfigTest {
counts.update(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
- Assert.assertEquals(expectedTotal, counts.getMaxTotal());
- Assert.assertEquals((int) expectedTopLimits.first, counts.getMinReserved(WORK_TYPE_TOP));
- Assert.assertEquals((int) expectedTopLimits.second, counts.getMax(WORK_TYPE_TOP));
- Assert.assertEquals((int) expectedBgLimits.first, counts.getMinReserved(WORK_TYPE_BG));
- Assert.assertEquals((int) expectedBgLimits.second, counts.getMax(WORK_TYPE_BG));
+ assertEquals(expectedTotal, counts.getMaxTotal());
+ for (Pair<Integer, Integer> min : expectedMinLimits) {
+ assertEquals((int) min.second, counts.getMinReserved(min.first));
+ }
+ for (Pair<Integer, Integer> max : expectedMaxLimits) {
+ assertEquals((int) max.second, counts.getMax(max.first));
+ }
}
@Test
public void test() throws Exception {
// Tests with various combinations.
- check(null, /*default*/ 5, Pair.create(4, null), Pair.create(0, 1),
- /*expected*/ true, 5, Pair.create(4, 5), Pair.create(0, 1));
- check(null, /*default*/ 5, Pair.create(5, null), Pair.create(0, 0),
- /*expected*/ true, 5, Pair.create(5, 5), Pair.create(0, 1));
- check(null, /*default*/ 0, Pair.create(5, null), Pair.create(0, 0),
- /*expected*/ false, 1, Pair.create(1, 1), Pair.create(0, 1));
- check(null, /*default*/ -1, null, Pair.create(-1, -1),
- /*expected*/ false, 1, Pair.create(1, 1), Pair.create(0, 1));
- check(null, /*default*/ 5, null, Pair.create(5, 5),
- /*expected*/ true, 5, Pair.create(1, 5), Pair.create(4, 5));
- check(null, /*default*/ 6, Pair.create(1, null), Pair.create(6, 5),
- /*expected*/ false, 6, Pair.create(1, 6), Pair.create(5, 5));
- check(null, /*default*/ 4, null, Pair.create(6, 5),
- /*expected*/ false, 4, Pair.create(1, 4), Pair.create(3, 4));
- check(null, /*default*/ 5, Pair.create(4, null), Pair.create(1, 1),
- /*expected*/ true, 5, Pair.create(4, 5), Pair.create(1, 1));
- check(null, /*default*/ 15, null, Pair.create(15, 15),
- /*expected*/ true, 15, Pair.create(1, 15), Pair.create(14, 15));
- check(null, /*default*/ 16, null, Pair.create(16, 16),
- /*expected*/ true, 16, Pair.create(1, 16), Pair.create(15, 16));
- check(null, /*default*/ 20, null, Pair.create(20, 20),
- /*expected*/ false, 16, Pair.create(1, 16), Pair.create(15, 16));
- check(null, /*default*/ 20, null, Pair.create(16, 16),
- /*expected*/ true, 16, Pair.create(1, 16), Pair.create(15, 16));
+ check(null, /*default*/ 13,
+ /* min */ List.of(),
+ /* max */ List.of(),
+ /*expected*/ true, 13,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_EJ, 0),
+ Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 13), Pair.create(WORK_TYPE_EJ, 13),
+ Pair.create(WORK_TYPE_BG, 13), Pair.create(WORK_TYPE_BGUSER, 13)));
+ check(null, /*default*/ 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ /*expected*/ true, 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1)));
+ check(null, /*default*/ 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 5),
+ Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 1)),
+ /*expected*/ true, 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 5),
+ Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5),
+ Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1)));
+ check(null, /*default*/ 0,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 0)),
+ /*expected*/ false, 1,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 1)));
+ check(null, /*default*/ -1,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, -1)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, -1)),
+ /*expected*/ false, 1,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 1)));
+ check(null, /*default*/ 5,
+ /* min */ List.of(
+ Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5)),
+ /*expected*/ true, 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
+ Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5),
+ Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5)));
+ check(null, /*default*/ 6,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
+ Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 2)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 1)),
+ /*expected*/ false, 6,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
+ Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6),
+ Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 1)));
+ check(null, /*default*/ 4,
+ /* min */ List.of(
+ Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 6)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5)),
+ /*expected*/ false, 4,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
+ Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 4),
+ Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 4)));
+ check(null, /*default*/ 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ /*expected*/ true, 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1)));
+ check(null, /*default*/ 10,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3),
+ Pair.create(WORK_TYPE_BG, 1)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ /*expected*/ true, 10,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3),
+ Pair.create(WORK_TYPE_BG, 1)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1)));
+ check(null, /*default*/ 15,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 15)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 15)),
+ /*expected*/ true, 15,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 14)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 15), Pair.create(WORK_TYPE_BG, 15)));
+ check(null, /*default*/ 16,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 16)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 16)),
+ /*expected*/ true, 16,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 15)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16)));
+ check(null, /*default*/ 20,
+ /* min */ List.of(
+ Pair.create(WORK_TYPE_BG, 20), Pair.create(WORK_TYPE_BGUSER, 10)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 20), Pair.create(WORK_TYPE_BGUSER, 20)),
+ /*expected*/ false, 16,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1),
+ Pair.create(WORK_TYPE_BG, 15), Pair.create(WORK_TYPE_BGUSER, 0)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16),
+ Pair.create(WORK_TYPE_BG, 16), Pair.create(WORK_TYPE_BGUSER, 16)));
+ check(null, /*default*/ 20,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 16)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 16)),
+ /*expected*/ true, 16,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 15)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16)));
// Test for overriding with a setting string.
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
@@ -153,26 +228,66 @@ public class WorkTypeConfigTest {
.setInt(KEY_MAX_BG, 4)
.setInt(KEY_MIN_BG, 3)
.build(),
- /*default*/ 9, null, Pair.create(9, 9),
- /*expected*/ true, 5, Pair.create(1, 5), Pair.create(3, 4));
+ /*default*/ 9,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* max */ List.of(
+ Pair.create(WORK_TYPE_BG, 9), Pair.create(WORK_TYPE_BGUSER, 2)),
+ /*expected*/ true, 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 3)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5),
+ Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_TOTAL, 5).build(),
- /*default*/ 9, null, Pair.create(9, 9),
- /*expected*/ true, 5, Pair.create(1, 5), Pair.create(4, 5));
+ /*default*/ 9,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /*expected*/ true, 5,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 4)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 5)));
+
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_BG, 4).build(),
- /*default*/ 9, null, Pair.create(9, 9),
- /*expected*/ true, 9, Pair.create(1, 9), Pair.create(4, 4));
+ /*default*/ 9,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /*expected*/ true, 9,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 4)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 9), Pair.create(WORK_TYPE_BG, 4)));
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MIN_BG, 3).build(),
- /*default*/ 9, null, Pair.create(9, 9),
- /*expected*/ true, 9, Pair.create(1, 9), Pair.create(3, 9));
+ /*default*/ 9,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /*expected*/ true, 9,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 3)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 9), Pair.create(WORK_TYPE_BG, 9)));
+ check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
+ .setInt(KEY_MAX_TOTAL, 20)
+ .setInt(KEY_MAX_EJ, 5)
+ .setInt(KEY_MIN_EJ, 2)
+ .setInt(KEY_MAX_BG, 16)
+ .setInt(KEY_MIN_BG, 8)
+ .build(),
+ /*default*/ 9,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /*expected*/ true, 16,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_EJ, 2),
+ Pair.create(WORK_TYPE_BG, 8)),
+ /* max */
+ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_EJ, 5),
+ Pair.create(WORK_TYPE_BG, 16)));
+
check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER)
.setInt(KEY_MAX_TOTAL, 20)
.setInt(KEY_MAX_BG, 20)
.setInt(KEY_MIN_BG, 8)
.build(),
- /*default*/ 9, null, Pair.create(9, 9),
- /*expected*/ true, 16, Pair.create(1, 16), Pair.create(8, 16));
+ /*default*/ 9,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)),
+ /*expected*/ true, 16,
+ /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 8)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16)));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 58ba90726b80..3ebe4efee013 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -19,11 +19,13 @@ package com.android.server.net;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.NETWORK_STACK;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED;
import static android.net.INetd.FIREWALL_RULE_ALLOW;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -112,8 +114,6 @@ import android.net.INetworkPolicyListener;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkState;
@@ -1985,13 +1985,6 @@ public class NetworkPolicyManagerServiceTest {
return users;
}
- private NetworkInfo buildNetworkInfo() {
- final NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_MOBILE,
- TelephonyManager.NETWORK_TYPE_LTE, null, null);
- ni.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
- return ni;
- }
-
private LinkProperties buildLinkProperties(String iface) {
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(iface);
@@ -2045,13 +2038,12 @@ public class NetworkPolicyManagerServiceTest {
}
private static NetworkState buildWifi() {
- final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
- info.setDetailedState(DetailedState.CONNECTED, null, null);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+ networkCapabilities.addTransportType(TRANSPORT_WIFI);
networkCapabilities.setSSID(TEST_SSID);
- return new NetworkState(info, prop, networkCapabilities, null, null, TEST_SSID);
+ return new NetworkState(TYPE_WIFI, prop, networkCapabilities, null, null, TEST_SSID);
}
private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception {
@@ -2072,7 +2064,7 @@ public class NetworkPolicyManagerServiceTest {
when(mCarrierConfigManager.getConfigForSubId(eq(TEST_SUB_ID)))
.thenReturn(mCarrierConfig);
when(mConnManager.getAllNetworkState()).thenReturn(new NetworkState[] {
- new NetworkState(buildNetworkInfo(),
+ new NetworkState(TYPE_MOBILE,
buildLinkProperties(TEST_IFACE),
buildNetworkCapabilities(TEST_SUB_ID, roaming),
new Network(TEST_NET_ID), TEST_IMSI, null)
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index d876b05af3d5..7d208799ee88 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -229,9 +229,9 @@ public class VibrationThreadTest {
.compose();
VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- Thread.sleep(20);
+ assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), vibrationThread,
+ TEST_TIMEOUT_MILLIS));
assertTrue(vibrationThread.isAlive());
- assertTrue(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
// Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
@@ -254,9 +254,9 @@ public class VibrationThreadTest {
VibrationEffect effect = VibrationEffect.createWaveform(new long[]{100}, new int[]{100}, 0);
VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- Thread.sleep(20);
+ assertTrue(waitUntil(t -> t.getVibrators().get(VIBRATOR_ID).isVibrating(), vibrationThread,
+ TEST_TIMEOUT_MILLIS));
assertTrue(vibrationThread.isAlive());
- assertTrue(vibrationThread.getVibrators().get(VIBRATOR_ID).isVibrating());
// Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
@@ -621,10 +621,8 @@ public class VibrationThreadTest {
.combine();
VibrationThread vibrationThread = startThreadAndDispatcher(vibrationId, effect);
- Thread.sleep(10);
- assertTrue(vibrationThread.isAlive());
- assertTrue(vibrationThread.getVibrators().get(1).isVibrating());
- assertTrue(vibrationThread.getVibrators().get(2).isVibrating());
+ assertTrue(waitUntil(t -> t.getVibrators().get(2).isVibrating(), vibrationThread,
+ TEST_TIMEOUT_MILLIS));
// Run cancel in a separate thread so if VibrationThread.cancel blocks then this test should
// fail at waitForCompletion(vibrationThread) if the vibration not cancelled immediately.
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
new file mode 100644
index 000000000000..f5d0ca7c5f9f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorManager;
+import android.hardware.input.InputSensorInfo;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.rotationresolver.RotationResolverInternal;
+import android.view.Surface;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.server.wm.WindowOrientationListener}
+ */
+public class WindowOrientationListenerTest {
+
+ @Mock
+ private Context mMockContext;
+ @Mock
+ private Handler mMockHandler;
+ @Mock
+ private InputSensorInfo mMockInputSensorInfo;
+ @Mock
+ private SensorManager mMockSensorManager;
+ @Mock
+ private WindowManagerService mMockWindowManagerService;
+
+ private TestableRotationResolver mFakeRotationResolverInternal;
+ private com.android.server.wm.WindowOrientationListener mWindowOrientationListener;
+ private int mFinalizedRotation;
+ private boolean mRotationResolverEnabled;
+ private boolean mCanUseRotationResolver;
+ private SensorEvent mFakeSensorEvent;
+ private Sensor mFakeSensor;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mRotationResolverEnabled = true;
+ mCanUseRotationResolver = true;
+
+ mFakeRotationResolverInternal = new TestableRotationResolver();
+ doReturn(mMockSensorManager).when(mMockContext).getSystemService(Context.SENSOR_SERVICE);
+ mWindowOrientationListener = new TestableWindowOrientationListener(mMockContext,
+ mMockHandler, mMockWindowManagerService);
+ mWindowOrientationListener.mRotationResolverService = mFakeRotationResolverInternal;
+
+ mFakeSensor = new Sensor(mMockInputSensorInfo);
+ mFakeSensorEvent = new SensorEvent(mFakeSensor, /* accuracy */ 1, /* timestamp */ 1L,
+ new float[]{(float) Surface.ROTATION_90});
+ }
+
+ @Test
+ public void testOnSensorChanged_rotationResolverDisabled_useSensorResult() {
+ mRotationResolverEnabled = false;
+
+ mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent);
+
+ assertThat(mFinalizedRotation).isEqualTo(Surface.ROTATION_90);
+ }
+
+ @Test
+ public void testOnSensorChanged_cannotUseRotationResolver_useSensorResult() {
+ mCanUseRotationResolver = false;
+
+ mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent);
+
+ assertThat(mFinalizedRotation).isEqualTo(Surface.ROTATION_90);
+
+ }
+
+ @Test
+ public void testOnSensorChanged_normalCase() {
+ mFakeRotationResolverInternal.mResult = Surface.ROTATION_180;
+
+ mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent);
+
+ assertThat(mFinalizedRotation).isEqualTo(Surface.ROTATION_180);
+ }
+
+ final class TestableRotationResolver extends RotationResolverInternal {
+ @Surface.Rotation
+ int mResult;
+
+ @Override
+ public boolean isRotationResolverSupported() {
+ return true;
+ }
+
+ @Override
+ public void resolveRotation(@NonNull RotationResolverCallbackInternal callback,
+ @Surface.Rotation int proposedRotation, @Surface.Rotation int currentRotation,
+ @DurationMillisLong long timeoutMillis,
+ @NonNull CancellationSignal cancellationSignal) {
+ callback.onSuccess(mResult);
+ }
+ }
+
+ final class TestableWindowOrientationListener extends WindowOrientationListener {
+
+ TestableWindowOrientationListener(Context context, Handler handler,
+ WindowManagerService service) {
+ super(context, handler, service);
+ this.mOrientationJudge = new OrientationSensorJudge();
+ }
+
+ @Override
+ public void onProposedRotationChanged(int rotation) {
+ mFinalizedRotation = rotation;
+ }
+
+ @Override
+ public boolean canUseRotationResolver() {
+ return mCanUseRotationResolver;
+ }
+
+ @Override
+ public boolean isRotationResolverEnabled() {
+ return mRotationResolverEnabled;
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 4c2d12436858..b4fd3024a634 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1379,7 +1379,7 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
- public void testNoFixedRotationWithPip() {
+ public void testFixedRotationWithPip() {
final DisplayContent displayContent = mDefaultDisplay;
unblockDisplayRotation(displayContent);
// Make resume-top really update the activity state.
@@ -1406,15 +1406,20 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(homeConfigOrientation, displayConfig.orientation);
clearInvocations(mWm);
- // Leave PiP to fullscreen. The orientation can be updated from
- // ActivityRecord#reportDescendantOrientationChangeIfNeeded.
- pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ // Leave PiP to fullscreen. Simulate the step of PipTaskOrganizer that sets the activity
+ // to fullscreen, so fixed rotation will apply on it.
+ pinnedActivity.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
homeActivity.setState(Task.ActivityState.STOPPED, "test");
- assertFalse(displayContent.hasTopFixedRotationLaunchingApp());
- verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
- assertEquals(pinnedConfigOrientation, displayConfig.orientation);
+ assertTrue(displayContent.hasTopFixedRotationLaunchingApp());
+ verify(mWm, never()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
+ assertNotEquals(pinnedConfigOrientation, displayConfig.orientation);
+
+ // Assume the animation of PipTaskOrganizer is done and then commit fullscreen to task.
+ pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ displayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
assertFalse(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
+ assertEquals(pinnedConfigOrientation, displayConfig.orientation);
clearInvocations(mWm);
// Enter PiP from fullscreen. The orientation can be updated from
diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java
index 0059ad6c2426..ae7d20929d58 100644
--- a/telephony/java/android/telephony/SignalThresholdInfo.java
+++ b/telephony/java/android/telephony/SignalThresholdInfo.java
@@ -402,29 +402,27 @@ public final class SignalThresholdInfo implements Parcelable {
* @see #getThresholds() for more details on signal strength thresholds
*/
public @NonNull Builder setThresholds(@NonNull int[] thresholds) {
- Objects.requireNonNull(thresholds, "thresholds must not be null");
- if (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
- || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED) {
- throw new IllegalArgumentException(
- "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
- + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED);
- }
- mThresholds = thresholds.clone();
- Arrays.sort(mThresholds);
- return this;
+ return setThresholds(thresholds, false /*isSystem*/);
}
/**
- * Set the signal strength thresholds for the corresponding signal measurement type without
- * the length limitation.
+ * Set the signal strength thresholds for the corresponding signal measurement type.
*
* @param thresholds array of integer as the signal threshold values
+ * @param isSystem true is the caller is system which does not have restrictions on
+ * the length of thresholds array.
* @return the builder to facilitate the chaining
*
* @hide
*/
- public @NonNull Builder setThresholdsUnlimited(@NonNull int[] thresholds) {
+ public @NonNull Builder setThresholds(@NonNull int[] thresholds, boolean isSystem) {
Objects.requireNonNull(thresholds, "thresholds must not be null");
+ if (!isSystem && (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+ || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED)) {
+ throw new IllegalArgumentException(
+ "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED
+ + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED);
+ }
mThresholds = thresholds.clone();
Arrays.sort(mThresholds);
return this;
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index f39e30b6d61f..814ce18c51e3 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -21,6 +21,7 @@ import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
@@ -39,6 +40,8 @@ import android.util.Log;
import com.android.internal.telephony.IIntegerConsumer;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -77,31 +80,49 @@ public class ImsRcsManager {
"android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
/**
- * Receives RCS Feature availability status updates from the ImsService.
- *
- * @see #isAvailable(int)
- * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
- * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback)
+ * An application can use {@link #addOnAvailabilityChangedListener} to register a
+ * {@link OnAvailabilityChangedListener}, which will notify the user when the RCS feature
+ * availability status updates from the ImsService.
* @hide
*/
- public static class AvailabilityCallback {
+ @SystemApi
+ public interface OnAvailabilityChangedListener {
+ /**
+ * The availability of the feature's capabilities has changed to either available or
+ * unavailable.
+ * <p>
+ * If unavailable, the feature does not support the capability at the current time. This may
+ * be due to network or subscription provisioning changes, such as the IMS registration
+ * being lost, network type changing, or OMA-DM provisioning updates.
+ *
+ * @param capabilities The new availability of the capabilities.
+ */
+ void onAvailabilityChanged(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities);
+ }
- private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
+ /**
+ * Receive the availability status changed from the ImsService and pass the status change to
+ * the associated {@link OnAvailabilityChangedListener}
+ */
+ private static class AvailabilityCallbackAdapter {
- private final AvailabilityCallback mLocalCallback;
- private Executor mExecutor;
+ private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
+ private final OnAvailabilityChangedListener mOnAvailabilityChangedListener;
+ private final Executor mExecutor;
- CapabilityBinder(AvailabilityCallback c) {
- mLocalCallback = c;
+ CapabilityBinder(OnAvailabilityChangedListener listener, Executor executor) {
+ mExecutor = executor;
+ mOnAvailabilityChangedListener = listener;
}
@Override
public void onCapabilitiesStatusChanged(int config) {
- if (mLocalCallback == null) return;
+ if (mOnAvailabilityChangedListener == null) return;
final long callingIdentity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(config));
+ mExecutor.execute(() ->
+ mOnAvailabilityChangedListener.onAvailabilityChanged(config));
} finally {
restoreCallingIdentity(callingIdentity);
}
@@ -110,48 +131,34 @@ public class ImsRcsManager {
@Override
public void onQueryCapabilityConfiguration(int capability, int radioTech,
boolean isEnabled) {
- // This is not used for public interfaces.
+ // This is not used.
}
@Override
public void onChangeCapabilityConfigurationError(int capability, int radioTech,
@ImsFeature.ImsCapabilityError int reason) {
- // This is not used for public interfaces
- }
-
- private void setExecutor(Executor executor) {
- mExecutor = executor;
+ // This is not used.
}
}
- private final CapabilityBinder mBinder = new CapabilityBinder(this);
+ private final CapabilityBinder mBinder;
- /**
- * The availability of the feature's capabilities has changed to either available or
- * unavailable.
- * <p>
- * If unavailable, the feature does not support the capability at the current time. This may
- * be due to network or subscription provisioning changes, such as the IMS registration
- * being lost, network type changing, or OMA-DM provisioning updates.
- *
- * @param capabilities The new availability of the capabilities.
- */
- public void onAvailabilityChanged(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+ AvailabilityCallbackAdapter(@NonNull Executor executor,
+ @NonNull OnAvailabilityChangedListener listener) {
+ mBinder = new CapabilityBinder(listener, executor);
}
/**@hide*/
public final IImsCapabilityCallback getBinder() {
return mBinder;
}
-
- private void setExecutor(Executor executor) {
- mBinder.setExecutor(executor);
- }
}
private final int mSubId;
private final Context mContext;
private final BinderCacheManager<IImsRcsController> mBinderCache;
+ private final Map<OnAvailabilityChangedListener, AvailabilityCallbackAdapter>
+ mAvailabilityChangedCallbacks;
/**
* Use {@link ImsManager#getImsRcsManager(int)} to create an instance of this class.
@@ -162,6 +169,7 @@ public class ImsRcsManager {
mSubId = subId;
mContext = context;
mBinderCache = binderCache;
+ mAvailabilityChangedCallbacks = new HashMap<>();
}
/**
@@ -174,10 +182,23 @@ public class ImsRcsManager {
}
/**
- * @hide
+ * Registers a {@link RegistrationManager.RegistrationCallback} with the system. When the
+ * callback is registered, it will initiate the callback c to be called with the current
+ * registration state.
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor The executor the callback events should be run on.
+ * @param c The {@link RegistrationManager.RegistrationCallback} to be added.
+ * @see #unregisterImsRegistrationCallback(RegistrationManager.RegistrationCallback)
+ * @throws ImsException if the subscription associated with this callback is valid, but
+ * the {@link ImsService} associated with the subscription is not available. This can happen if
+ * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
+ * reason.
*/
- // @Override add back to RegistrationManager interface once public.
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public void registerImsRegistrationCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull RegistrationManager.RegistrationCallback c)
@@ -191,7 +212,7 @@ public class ImsRcsManager {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Register registration callback: IImsRcsController is null");
+ Log.w(TAG, "Register registration callback: IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -207,10 +228,21 @@ public class ImsRcsManager {
}
/**
- * @hide
+ * Removes an existing {@link RegistrationManager.RegistrationCallback}.
+ *
+ * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+ * etc...), this callback will automatically be removed. If this method is called for an
+ * inactive subscription, it will result in a no-op.
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param c The {@link RegistrationManager.RegistrationCallback} to be removed.
+ * @see android.telephony.SubscriptionManager.OnSubscriptionsChangedListener
+ * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
*/
- // @Override add back to RegistrationManager interface once public.
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public void unregisterImsRegistrationCallback(
@NonNull RegistrationManager.RegistrationCallback c) {
if (c == null) {
@@ -219,7 +251,7 @@ public class ImsRcsManager {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Unregister registration callback: IImsRcsController is null");
+ Log.w(TAG, "Unregister registration callback: IImsRcsController is null");
throw new IllegalStateException("Cannot find remote IMS service");
}
@@ -231,10 +263,21 @@ public class ImsRcsManager {
}
/**
- * @hide
+ * Gets the registration state of the IMS service.
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor The {@link Executor} that will be used to call the IMS registration state
+ * callback.
+ * @param stateCallback A callback called on the supplied {@link Executor} that will contain the
+ * registration state of the IMS service, which will be one of the
+ * following: {@link RegistrationManager#REGISTRATION_STATE_NOT_REGISTERED},
+ * {@link RegistrationManager#REGISTRATION_STATE_REGISTERING}, or
+ * {@link RegistrationManager#REGISTRATION_STATE_REGISTERED}.
*/
- // @Override add back to RegistrationManager interface once public.
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
@NonNull @RegistrationManager.ImsRegistrationState Consumer<Integer> stateCallback) {
if (stateCallback == null) {
@@ -246,7 +289,7 @@ public class ImsRcsManager {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Get registration state error: IImsRcsController is null");
+ Log.w(TAG, "Get registration state error: IImsRcsController is null");
throw new IllegalStateException("Cannot find remote IMS service");
}
@@ -263,9 +306,20 @@ public class ImsRcsManager {
}
/**
- * @hide
+ * Gets the Transport Type associated with the current IMS registration.
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor The {@link Executor} that will be used to call the transportTypeCallback.
+ * @param transportTypeCallback The transport type associated with the current IMS registration,
+ * which will be one of following:
+ * {@see AccessNetworkConstants#TRANSPORT_TYPE_WWAN},
+ * {@see AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or
+ * {@see AccessNetworkConstants#TRANSPORT_TYPE_INVALID}.
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
@NonNull @AccessNetworkConstants.TransportType
Consumer<Integer> transportTypeCallback) {
@@ -278,7 +332,7 @@ public class ImsRcsManager {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Get registration transport type error: IImsRcsController is null");
+ Log.w(TAG, "Get registration transport type error: IImsRcsController is null");
throw new IllegalStateException("Cannot find remote IMS service");
}
@@ -296,31 +350,33 @@ public class ImsRcsManager {
}
/**
- * Registers an {@link AvailabilityCallback} with the system, which will provide RCS
+ * Add an {@link OnAvailabilityChangedListener} with the system, which will provide RCS
* availability updates for the subscription specified.
*
* Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
* subscription changed events and call
- * {@link #unregisterRcsAvailabilityCallback(AvailabilityCallback)} to clean up after a
- * subscription is removed.
+ * {@link #removeOnAvailabilityChangedListener(OnAvailabilityChangedListener)} to clean up
+ * after a subscription is removed.
* <p>
- * When the callback is registered, it will initiate the callback c to be called with the
- * current capabilities.
+ * When the listener is registered, it will initiate the callback listener to be called with
+ * the current capabilities.
*
* @param executor The executor the callback events should be run on.
- * @param c The RCS {@link AvailabilityCallback} to be registered.
- * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback)
+ * @param listener The RCS {@link OnAvailabilityChangedListener} to be registered.
+ * @see #removeOnAvailabilityChangedListener(OnAvailabilityChangedListener)
* @throws ImsException if the subscription associated with this instance of
* {@link ImsRcsManager} is valid, but the ImsService associated with the subscription is not
* available. This can happen if the ImsService has crashed, for example, or if the subscription
* becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void registerRcsAvailabilityCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull AvailabilityCallback c) throws ImsException {
- if (c == null) {
- throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+ public void addOnAvailabilityChangedListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OnAvailabilityChangedListener listener) throws ImsException {
+ if (listener == null) {
+ throw new IllegalArgumentException("Must include a non-null"
+ + "OnAvailabilityChangedListener.");
}
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
@@ -328,56 +384,61 @@ public class ImsRcsManager {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Register availability callback: IImsRcsController is null");
+ Log.w(TAG, "Add availability changed listener: IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
- c.setExecutor(executor);
+ AvailabilityCallbackAdapter adapter =
+ addAvailabilityChangedListenerToCollection(executor, listener);
try {
- imsRcsController.registerRcsAvailabilityCallback(mSubId, c.getBinder());
-
+ imsRcsController.registerRcsAvailabilityCallback(mSubId, adapter.getBinder());
} catch (ServiceSpecificException e) {
throw new ImsException(e.toString(), e.errorCode);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling IImsRcsController#registerRcsAvailabilityCallback", e);
+ Log.w(TAG, "Error calling IImsRcsController#registerRcsAvailabilityCallback", e);
throw new ImsException("Remote IMS Service is not available",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
- /**
- * Removes an existing RCS {@link AvailabilityCallback}.
+ /**
+ * Removes an existing RCS {@link OnAvailabilityChangedListener}.
* <p>
* When the subscription associated with this callback is removed (SIM removed, ESIM swap,
* etc...), this callback will automatically be unregistered. If this method is called for an
* inactive subscription, it will result in a no-op.
- * @param c The RCS {@link AvailabilityCallback} to be removed.
- * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
+ * @param listener The RCS {@link OnAvailabilityChangedListener} to be removed.
+ * @see #addOnAvailabilityChangedListener(Executor, OnAvailabilityChangedListener)
* @throws ImsException if the IMS service is not available when calling this method.
* See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void unregisterRcsAvailabilityCallback(@NonNull AvailabilityCallback c)
- throws ImsException {
- if (c == null) {
- throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+ public void removeOnAvailabilityChangedListener(
+ @NonNull OnAvailabilityChangedListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Must include a non-null"
+ + "OnAvailabilityChangedListener.");
}
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Unregister availability callback: IImsRcsController is null");
- throw new ImsException("Cannot find remote IMS service",
- ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ Log.w(TAG, "Remove availability changed listener: IImsRcsController is null");
+ return;
+ }
+
+ AvailabilityCallbackAdapter callback =
+ removeAvailabilityChangedListenerFromCollection(listener);
+ if (callback == null) {
+ return;
}
try {
- imsRcsController.unregisterRcsAvailabilityCallback(mSubId, c.getBinder());
+ imsRcsController.unregisterRcsAvailabilityCallback(mSubId, callback.getBinder());
} catch (RemoteException e) {
- Log.e(TAG, "Error calling IImsRcsController#unregisterRcsAvailabilityCallback", e);
- throw new ImsException("Remote IMS Service is not available",
- ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ Log.w(TAG, "Error calling IImsRcsController#unregisterRcsAvailabilityCallback", e);
}
}
@@ -388,26 +449,24 @@ public class ImsRcsManager {
* RCS capabilities provided over-the-top by applications.
*
* @param capability The RCS capability to query.
- * @param radioTech The radio tech that this capability failed for, defined as
- * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} or
- * {@link ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM} or
- * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}.
+ * @param radioTech The radio technology type that we are querying.
* @return true if the RCS capability is capable for this subscription, false otherwise. This
* does not necessarily mean that we are registered for IMS and the capability is available, but
* rather the subscription is capable of this service over IMS.
- * @see #isAvailable(int)
+ * @see #isAvailable(int, int)
* @see android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL
* @see android.telephony.CarrierConfigManager.Ims#KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL
* @throws ImsException if the IMS service is not available when calling this method.
* See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isCapable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) throws ImsException {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "isCapable: IImsRcsController is null");
+ Log.w(TAG, "isCapable: IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -415,7 +474,7 @@ public class ImsRcsManager {
try {
return imsRcsController.isCapable(mSubId, capability, radioTech);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling IImsRcsController#isCapable", e);
+ Log.w(TAG, "Error calling IImsRcsController#isCapable", e);
throw new ImsException("Remote IMS Service is not available",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -428,6 +487,7 @@ public class ImsRcsManager {
* RCS capabilities provided by over-the-top by applications.
*
* @param capability the RCS capability to query.
+ * @param radioTech The radio technology type that we are querying.
* @return true if the RCS capability is currently available for the associated subscription,
* false otherwise. If the capability is available, IMS is registered and the service is
* currently available over IMS.
@@ -436,25 +496,57 @@ public class ImsRcsManager {
* See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public boolean isAvailable(@RcsUceAdapter.RcsImsCapabilityFlag int capability)
+ public boolean isAvailable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
+ @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)
throws ImsException {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "isAvailable: IImsRcsController is null");
+ Log.w(TAG, "isAvailable: IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
try {
- return imsRcsController.isAvailable(mSubId, capability);
+ return imsRcsController.isAvailable(mSubId, capability, radioTech);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling IImsRcsController#isAvailable", e);
+ Log.w(TAG, "Error calling IImsRcsController#isAvailable", e);
throw new ImsException("Remote IMS Service is not available",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
+ /**
+ * Add the {@link OnAvailabilityChangedListener} to collection for tracking.
+ * @param executor The executor that will be used when the publish state is changed and the
+ * {@link OnAvailabilityChangedListener} is called.
+ * @param listener The {@link OnAvailabilityChangedListener} to call the publish state changed.
+ * @return The {@link AvailabilityCallbackAdapter} to wrapper the
+ * {@link OnAvailabilityChangedListener}
+ */
+ private AvailabilityCallbackAdapter addAvailabilityChangedListenerToCollection(
+ @NonNull Executor executor, @NonNull OnAvailabilityChangedListener listener) {
+ AvailabilityCallbackAdapter adapter = new AvailabilityCallbackAdapter(executor, listener);
+ synchronized (mAvailabilityChangedCallbacks) {
+ mAvailabilityChangedCallbacks.put(listener, adapter);
+ }
+ return adapter;
+ }
+
+ /**
+ * Remove the existing {@link OnAvailabilityChangedListener} from the collection.
+ * @param listener The {@link OnAvailabilityChangedListener} to remove from the collection.
+ * @return The wrapper class {@link AvailabilityCallbackAdapter} associated with the
+ * {@link OnAvailabilityChangedListener}.
+ */
+ private AvailabilityCallbackAdapter removeAvailabilityChangedListenerFromCollection(
+ @NonNull OnAvailabilityChangedListener listener) {
+ synchronized (mAvailabilityChangedCallbacks) {
+ return mAvailabilityChangedCallbacks.remove(listener);
+ }
+ }
+
private IImsRcsController getIImsRcsController() {
IBinder binder = TelephonyFrameworkInitializer
.getTelephonyServiceManager()
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 7a6c28bddd09..8931a78709ed 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -47,7 +47,7 @@ interface IImsRcsController {
void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback c);
void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback c);
boolean isCapable(int subId, int capability, int radioTech);
- boolean isAvailable(int subId, int capability);
+ boolean isAvailable(int subId, int capability, int radioTech);
// ImsUceAdapter specific
void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
diff --git a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
index c5b1c90ced12..f3791d1c6f96 100644
--- a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
+++ b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
@@ -36,12 +36,9 @@ import java.util.Set;
public final class CapabilityChangeRequest implements Parcelable {
/**
- * Contains a feature capability, defined as
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, or
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS},
- * along with an associated technology, defined as
+ * Contains a MMTEL feature capability {@link MmTelFeature.MmTelCapabilities} and RCS feature
+ * capability {@link RcsFeature.RcsImsCapabilities}, along with an associated technology,
+ * defined as
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} or
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_CROSS_SIM}
@@ -50,7 +47,7 @@ public final class CapabilityChangeRequest implements Parcelable {
private final int mCapability;
private final int radioTech;
- public CapabilityPair(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+ public CapabilityPair(int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
this.mCapability = capability;
this.radioTech = radioTech;
@@ -81,13 +78,10 @@ public final class CapabilityChangeRequest implements Parcelable {
}
/**
- * @return The stored capability, defined as
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, or
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
+ * @return The stored capability, defined as {@link MmTelFeature.MmTelCapabilities} and
+ * {@link RcsFeature.RcsImsCapabilities}
*/
- public @MmTelFeature.MmTelCapabilities.MmTelCapability int getCapability() {
+ public int getCapability() {
return mCapability;
}
@@ -125,12 +119,11 @@ public final class CapabilityChangeRequest implements Parcelable {
* Add one or many capabilities to the request to be enabled.
*
* @param capabilities A bitfield of capabilities to enable, valid values are defined in
- * {@link MmTelFeature.MmTelCapabilities.MmTelCapability}.
+ * {@link MmTelFeature.MmTelCapabilities} and {@link RcsFeature.RcsImsCapabilities}.
* @param radioTech the radio tech that these capabilities should be enabled for, valid
* values are in {@link ImsRegistrationImplBase.ImsRegistrationTech}.
*/
- public void addCapabilitiesToEnableForTech(
- @MmTelFeature.MmTelCapabilities.MmTelCapability int capabilities,
+ public void addCapabilitiesToEnableForTech(int capabilities,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
addAllCapabilities(mCapabilitiesToEnable, capabilities, radioTech);
}
@@ -138,12 +131,11 @@ public final class CapabilityChangeRequest implements Parcelable {
/**
* Add one or many capabilities to the request to be disabled.
* @param capabilities A bitfield of capabilities to diable, valid values are defined in
- * {@link MmTelFeature.MmTelCapabilities.MmTelCapability}.
+ * {@link MmTelFeature.MmTelCapabilities} and {@link RcsFeature.RcsImsCapabilities}.
* @param radioTech the radio tech that these capabilities should be disabled for, valid
* values are in {@link ImsRegistrationImplBase.ImsRegistrationTech}.
*/
- public void addCapabilitiesToDisableForTech(
- @MmTelFeature.MmTelCapabilities.MmTelCapability int capabilities,
+ public void addCapabilitiesToDisableForTech(int capabilities,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
addAllCapabilities(mCapabilitiesToDisable, capabilities, radioTech);
}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 22df921c4214..85703f8de5e5 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -194,7 +194,6 @@ public class RcsFeature extends ImsFeature {
* of the capability and notify the capability status as true using
* {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the
* framework that the capability is available for usage.
- * @hide
*/
public static class RcsImsCapabilities extends Capabilities {
/** @hide*/
@@ -226,12 +225,21 @@ public class RcsFeature extends ImsFeature {
*/
public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
+ /**
+ * Create a new {@link RcsImsCapabilities} instance with the provided capabilities.
+ * @param capabilities The capabilities that are supported for RCS in the form of a
+ * bitfield.
+ */
public RcsImsCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
super(capabilities);
}
- private RcsImsCapabilities(Capabilities c) {
- super(c.getMask());
+ /**
+ * Create a new {@link RcsImsCapabilities} instance with the provided capabilities.
+ * @param capabilities The capabilities instance that are supported for RCS
+ */
+ private RcsImsCapabilities(Capabilities capabilities) {
+ super(capabilities.getMask());
}
@Override
@@ -307,7 +315,7 @@ public class RcsFeature extends ImsFeature {
* set, the {@link RcsFeature} has brought up the capability and is ready for framework
* requests. To change the status of the capabilities
* {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)} should be called.
- * @hide
+ * @return A copy of the current RcsFeature capability status.
*/
@Override
public @NonNull final RcsImsCapabilities queryCapabilityStatus() {
@@ -318,13 +326,13 @@ public class RcsFeature extends ImsFeature {
* Notify the framework that the capabilities status has changed. If a capability is enabled,
* this signals to the framework that the capability has been initialized and is ready.
* Call {@link #queryCapabilityStatus()} to return the current capability status.
- * @hide
+ * @param capabilities The current capability status of the RcsFeature.
*/
- public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities c) {
- if (c == null) {
+ public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities capabilities) {
+ if (capabilities == null) {
throw new IllegalArgumentException("RcsImsCapabilities must be non-null!");
}
- super.notifyCapabilitiesStatusChanged(c);
+ super.notifyCapabilitiesStatusChanged(capabilities);
}
/**
@@ -333,7 +341,9 @@ public class RcsFeature extends ImsFeature {
* {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)} to
* enable or disable capability A, this method should return the correct configuration for
* capability A afterwards (until it has changed).
- * @hide
+ * @param capability The capability that we are querying the configuration for.
+ * @param radioTech The radio technology type that we are querying.
+ * @return true if the capability is enabled, false otherwise.
*/
public boolean queryCapabilityConfiguration(
@RcsUceAdapter.RcsImsCapabilityFlag int capability,
@@ -355,11 +365,12 @@ public class RcsFeature extends ImsFeature {
* If for some reason one or more of these capabilities can not be enabled/disabled,
* {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError(int, int, int)} should
* be called for each capability change that resulted in an error.
- * @hide
+ * @param request The request to change the capability.
+ * @param callback To notify the framework that the result of the capability changes.
*/
@Override
public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request,
- @NonNull CapabilityCallbackProxy c) {
+ @NonNull CapabilityCallbackProxy callback) {
// Base Implementation - Override to provide functionality
}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index e68fbd8724de..b2719fbcac82 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -25,7 +25,6 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.server.wm.flicker"/>
- <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6600s" />
<option name="hidden-api-checks" value="false" />
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 89c6663df343..c5447c1ccf71 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -17,8 +17,11 @@
package com.android.server.wm.flicker
import android.platform.helpers.IAppHelper
+import com.android.server.wm.flicker.dsl.EventLogAssertionBuilder
import com.android.server.wm.flicker.dsl.EventLogAssertionBuilderLegacy
+import com.android.server.wm.flicker.dsl.LayersAssertionBuilder
import com.android.server.wm.flicker.dsl.LayersAssertionBuilderLegacy
+import com.android.server.wm.flicker.dsl.WmAssertionBuilder
import com.android.server.wm.flicker.dsl.WmAssertionBuilderLegacy
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.NAV_BAR_LAYER_NAME
@@ -31,6 +34,247 @@ const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
const val WALLPAPER_TITLE = "Wallpaper"
@JvmOverloads
+fun WmAssertionBuilder.statusBarWindowIsAlwaysVisible(bugId: Int = 0) {
+ all("statusBarWindowIsAlwaysVisible", bugId) {
+ this.showsAboveAppWindow(NAV_BAR_LAYER_NAME)
+ }
+}
+
+@JvmOverloads
+fun WmAssertionBuilder.navBarWindowIsAlwaysVisible(bugId: Int = 0) {
+ all("navBarWindowIsAlwaysVisible", bugId) {
+ this.showsAboveAppWindow(NAV_BAR_LAYER_NAME)
+ }
+}
+
+fun WmAssertionBuilder.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ ignoreWindows: List<String> = emptyList(),
+ bugId: Int = 0
+) {
+ all("visibleWindowsShownMoreThanOneConsecutiveEntry", bugId) {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry(ignoreWindows)
+ }
+}
+
+fun WmAssertionBuilder.launcherReplacesAppWindowAsTopWindow(testApp: IAppHelper, bugId: Int = 0) {
+ all("launcherReplacesAppWindowAsTopWindow", bugId) {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ .then()
+ .showsAppWindowOnTop("Launcher")
+ }
+}
+
+fun WmAssertionBuilder.wallpaperWindowBecomesVisible(bugId: Int = 0) {
+ all("wallpaperWindowBecomesVisible", bugId) {
+ this.hidesBelowAppWindow(WALLPAPER_TITLE)
+ .then()
+ .showsBelowAppWindow(WALLPAPER_TITLE)
+ }
+}
+
+fun WmAssertionBuilder.wallpaperWindowBecomesInvisible(bugId: Int = 0) {
+ all("wallpaperWindowBecomesInvisible", bugId) {
+ this.showsBelowAppWindow("Wallpaper")
+ .then()
+ .hidesBelowAppWindow("Wallpaper")
+ }
+}
+
+fun WmAssertionBuilder.appWindowAlwaysVisibleOnTop(
+ packageName: String,
+ bugId: Int = 0
+) {
+ all("appWindowAlwaysVisibleOnTop", bugId) {
+ this.showsAppWindowOnTop(packageName)
+ }
+}
+
+fun WmAssertionBuilder.appWindowBecomesVisible(appName: String, bugId: Int = 0) {
+ all("appWindowBecomesVisible", bugId) {
+ this.hidesAppWindow(appName)
+ .then()
+ .showsAppWindow(appName)
+ }
+}
+
+fun WmAssertionBuilder.appWindowBecomesInVisible(appName: String, bugId: Int = 0) {
+ all("appWindowBecomesInVisible", bugId) {
+ this.showsAppWindow(appName)
+ .then()
+ .hidesAppWindow(appName)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.noUncoveredRegions(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ allStates: Boolean = true,
+ bugId: Int = 0
+) {
+ val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+ if (allStates) {
+ all("noUncoveredRegions", bugId) {
+ if (startingBounds == endingBounds) {
+ this.coversAtLeastRegion(startingBounds)
+ } else {
+ this.coversAtLeastRegion(startingBounds)
+ .then()
+ .coversAtLeastRegion(endingBounds)
+ }
+ }
+ } else {
+ start("noUncoveredRegions_StartingPos") {
+ this.coversAtLeastRegion(startingBounds)
+ }
+ end("noUncoveredRegions_EndingPos") {
+ this.coversAtLeastRegion(endingBounds)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.navBarLayerIsAlwaysVisible(
+ rotatesScreen: Boolean = false,
+ bugId: Int = 0
+) {
+ if (rotatesScreen) {
+ all("navBarLayerIsAlwaysVisible", bugId) {
+ this.showsLayer(NAV_BAR_LAYER_NAME)
+ .then()
+ .hidesLayer(NAV_BAR_LAYER_NAME)
+ .then()
+ .showsLayer(NAV_BAR_LAYER_NAME)
+ }
+ } else {
+ all("navBarLayerIsAlwaysVisible", bugId) {
+ this.showsLayer(NAV_BAR_LAYER_NAME)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.statusBarLayerIsAlwaysVisible(
+ rotatesScreen: Boolean = false,
+ bugId: Int = 0
+) {
+ if (rotatesScreen) {
+ all("statusBarLayerIsAlwaysVisible", bugId) {
+ this.showsLayer(STATUS_BAR_WINDOW_NAME)
+ .then()
+ hidesLayer(STATUS_BAR_WINDOW_NAME)
+ .then()
+ .showsLayer(STATUS_BAR_WINDOW_NAME)
+ }
+ } else {
+ all("statusBarLayerIsAlwaysVisible", bugId) {
+ this.showsLayer(STATUS_BAR_WINDOW_NAME)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.navBarLayerRotatesAndScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0
+) {
+ val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
+ val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
+
+ start("navBarLayerRotatesAndScales_StartingPos", bugId) {
+ this.hasVisibleRegion(NAV_BAR_LAYER_NAME, startingPos)
+ }
+ end("navBarLayerRotatesAndScales_EndingPost", bugId) {
+ this.hasVisibleRegion(NAV_BAR_LAYER_NAME, endingPos)
+ }
+
+ /*if (startingPos == endingPos) {
+ all("navBarLayerRotatesAndScales", enabled = false, bugId = 167747321) {
+ this.hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ }*/
+}
+
+@JvmOverloads
+fun LayersAssertionBuilder.statusBarLayerRotatesScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0
+) {
+ val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
+ val endingPos = WindowUtils.getStatusBarPosition(endRotation)
+
+ start("statusBarLayerRotatesScales_StartingPos", bugId) {
+ this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, startingPos)
+ }
+ end("statusBarLayerRotatesScales_EndingPos", bugId) {
+ this.hasVisibleRegion(STATUS_BAR_WINDOW_NAME, endingPos)
+ }
+}
+
+fun LayersAssertionBuilder.visibleLayersShownMoreThanOneConsecutiveEntry(
+ ignoreLayers: List<String> = emptyList(),
+ bugId: Int = 0
+) {
+ all("visibleLayersShownMoreThanOneConsecutiveEntry", bugId) {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry(ignoreLayers)
+ }
+}
+
+fun LayersAssertionBuilder.appLayerReplacesWallpaperLayer(appName: String, bugId: Int = 0) {
+ all("appLayerReplacesWallpaperLayer", bugId) {
+ this.showsLayer("Wallpaper")
+ .then()
+ .replaceVisibleLayer("Wallpaper", appName)
+ }
+}
+
+fun LayersAssertionBuilder.wallpaperLayerReplacesAppLayer(testApp: IAppHelper, bugId: Int = 0) {
+ all("appLayerReplacesWallpaperLayer", bugId) {
+ this.showsLayer(testApp.getPackage())
+ .then()
+ .replaceVisibleLayer(testApp.getPackage(), WALLPAPER_TITLE)
+ }
+}
+
+fun LayersAssertionBuilder.layerAlwaysVisible(packageName: String, bugId: Int = 0) {
+ all("layerAlwaysVisible", bugId) {
+ this.showsLayer(packageName)
+ }
+}
+
+fun LayersAssertionBuilder.layerBecomesVisible(packageName: String, bugId: Int = 0) {
+ all("layerBecomesVisible", bugId) {
+ this.hidesLayer(packageName)
+ .then()
+ .showsLayer(packageName)
+ }
+}
+
+fun LayersAssertionBuilder.layerBecomesInvisible(packageName: String, bugId: Int = 0) {
+ all("layerBecomesInvisible", bugId) {
+ this.showsLayer(packageName)
+ .then()
+ .hidesLayer(packageName)
+ }
+}
+
+fun EventLogAssertionBuilder.focusChanges(vararg windows: String, bugId: Int = 0) {
+ all("focusChanges", bugId) {
+ this.focusChanges(windows)
+ }
+}
+
+fun EventLogAssertionBuilder.focusDoesNotChange(bugId: Int = 0) {
+ all("focusDoesNotChange", bugId) {
+ this.focusDoesNotChange()
+ }
+}
+
+@JvmOverloads
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun WmAssertionBuilderLegacy.statusBarWindowIsAlwaysVisible(
bugId: Int = 0,
enabled: Boolean = bugId == 0
@@ -41,6 +285,7 @@ fun WmAssertionBuilderLegacy.statusBarWindowIsAlwaysVisible(
}
@JvmOverloads
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun WmAssertionBuilderLegacy.navBarWindowIsAlwaysVisible(
bugId: Int = 0,
enabled: Boolean = bugId == 0
@@ -50,6 +295,7 @@ fun WmAssertionBuilderLegacy.navBarWindowIsAlwaysVisible(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun WmAssertionBuilderLegacy.visibleWindowsShownMoreThanOneConsecutiveEntry(
ignoreWindows: List<String> = emptyList(),
bugId: Int = 0,
@@ -60,6 +306,7 @@ fun WmAssertionBuilderLegacy.visibleWindowsShownMoreThanOneConsecutiveEntry(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun WmAssertionBuilderLegacy.launcherReplacesAppWindowAsTopWindow(
testApp: IAppHelper,
bugId: Int = 0,
@@ -67,33 +314,36 @@ fun WmAssertionBuilderLegacy.launcherReplacesAppWindowAsTopWindow(
) {
all("launcherReplacesAppWindowAsTopWindow", bugId, enabled) {
this.showsAppWindowOnTop(testApp.getPackage())
- .then()
- .showsAppWindowOnTop("Launcher")
+ .then()
+ .showsAppWindowOnTop("Launcher")
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun WmAssertionBuilderLegacy.wallpaperWindowBecomesVisible(
bugId: Int = 0,
enabled: Boolean = bugId == 0
) {
all("wallpaperWindowBecomesVisible", bugId, enabled) {
this.hidesBelowAppWindow(WALLPAPER_TITLE)
- .then()
- .showsBelowAppWindow(WALLPAPER_TITLE)
+ .then()
+ .showsBelowAppWindow(WALLPAPER_TITLE)
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun WmAssertionBuilderLegacy.wallpaperWindowBecomesInvisible(
bugId: Int = 0,
enabled: Boolean = bugId == 0
) {
all("wallpaperWindowBecomesInvisible", bugId, enabled) {
this.showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
+ .then()
+ .hidesBelowAppWindow("Wallpaper")
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun WmAssertionBuilderLegacy.appWindowAlwaysVisibleOnTop(
packageName: String,
bugId: Int = 0,
@@ -104,6 +354,7 @@ fun WmAssertionBuilderLegacy.appWindowAlwaysVisibleOnTop(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun WmAssertionBuilderLegacy.appWindowBecomesVisible(
appName: String,
bugId: Int = 0,
@@ -111,11 +362,12 @@ fun WmAssertionBuilderLegacy.appWindowBecomesVisible(
) {
all("appWindowBecomesVisible", bugId, enabled) {
this.hidesAppWindow(appName)
- .then()
- .showsAppWindow(appName)
+ .then()
+ .showsAppWindow(appName)
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun WmAssertionBuilderLegacy.appWindowBecomesInVisible(
appName: String,
bugId: Int = 0,
@@ -123,11 +375,12 @@ fun WmAssertionBuilderLegacy.appWindowBecomesInVisible(
) {
all("appWindowBecomesInVisible", bugId, enabled) {
this.showsAppWindow(appName)
- .then()
- .hidesAppWindow(appName)
+ .then()
+ .hidesAppWindow(appName)
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
@JvmOverloads
fun LayersAssertionBuilderLegacy.noUncoveredRegions(
beginRotation: Int,
@@ -144,8 +397,8 @@ fun LayersAssertionBuilderLegacy.noUncoveredRegions(
this.coversAtLeastRegion(startingBounds)
} else {
this.coversAtLeastRegion(startingBounds)
- .then()
- .coversAtLeastRegion(endingBounds)
+ .then()
+ .coversAtLeastRegion(endingBounds)
}
}
} else {
@@ -158,6 +411,7 @@ fun LayersAssertionBuilderLegacy.noUncoveredRegions(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
@JvmOverloads
fun LayersAssertionBuilderLegacy.navBarLayerIsAlwaysVisible(
rotatesScreen: Boolean = false,
@@ -167,10 +421,10 @@ fun LayersAssertionBuilderLegacy.navBarLayerIsAlwaysVisible(
if (rotatesScreen) {
all("navBarLayerIsAlwaysVisible", bugId, enabled) {
this.showsLayer(NAV_BAR_LAYER_NAME)
- .then()
- .hidesLayer(NAV_BAR_LAYER_NAME)
- .then()
- .showsLayer(NAV_BAR_LAYER_NAME)
+ .then()
+ .hidesLayer(NAV_BAR_LAYER_NAME)
+ .then()
+ .showsLayer(NAV_BAR_LAYER_NAME)
}
} else {
all("navBarLayerIsAlwaysVisible", bugId, enabled) {
@@ -179,6 +433,7 @@ fun LayersAssertionBuilderLegacy.navBarLayerIsAlwaysVisible(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
@JvmOverloads
fun LayersAssertionBuilderLegacy.statusBarLayerIsAlwaysVisible(
rotatesScreen: Boolean = false,
@@ -188,10 +443,10 @@ fun LayersAssertionBuilderLegacy.statusBarLayerIsAlwaysVisible(
if (rotatesScreen) {
all("statusBarLayerIsAlwaysVisible", bugId, enabled) {
this.showsLayer(STATUS_BAR_LAYER_NAME)
- .then()
- hidesLayer(STATUS_BAR_LAYER_NAME)
- .then()
- .showsLayer(STATUS_BAR_LAYER_NAME)
+ .then()
+ .hidesLayer(STATUS_BAR_LAYER_NAME)
+ .then()
+ .showsLayer(STATUS_BAR_LAYER_NAME)
}
} else {
all("statusBarLayerIsAlwaysVisible", bugId, enabled) {
@@ -200,6 +455,7 @@ fun LayersAssertionBuilderLegacy.statusBarLayerIsAlwaysVisible(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
@JvmOverloads
fun LayersAssertionBuilderLegacy.navBarLayerRotatesAndScales(
beginRotation: Int,
@@ -224,6 +480,7 @@ fun LayersAssertionBuilderLegacy.navBarLayerRotatesAndScales(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
@JvmOverloads
fun LayersAssertionBuilderLegacy.statusBarLayerRotatesScales(
beginRotation: Int,
@@ -242,8 +499,9 @@ fun LayersAssertionBuilderLegacy.statusBarLayerRotatesScales(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun LayersAssertionBuilderLegacy.visibleLayersShownMoreThanOneConsecutiveEntry(
- ignoreLayers: List<String> = emptyList(),
+ ignoreLayers: List<String> = kotlin.collections.emptyList(),
bugId: Int = 0,
enabled: Boolean = bugId == 0
) {
@@ -252,6 +510,7 @@ fun LayersAssertionBuilderLegacy.visibleLayersShownMoreThanOneConsecutiveEntry(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun LayersAssertionBuilderLegacy.appLayerReplacesWallpaperLayer(
appName: String,
bugId: Int = 0,
@@ -259,11 +518,12 @@ fun LayersAssertionBuilderLegacy.appLayerReplacesWallpaperLayer(
) {
all("appLayerReplacesWallpaperLayer", bugId, enabled) {
this.showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", appName)
+ .then()
+ .replaceVisibleLayer("Wallpaper", appName)
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun LayersAssertionBuilderLegacy.wallpaperLayerReplacesAppLayer(
testApp: IAppHelper,
bugId: Int = 0,
@@ -271,11 +531,12 @@ fun LayersAssertionBuilderLegacy.wallpaperLayerReplacesAppLayer(
) {
all("appLayerReplacesWallpaperLayer", bugId, enabled) {
this.showsLayer(testApp.getPackage())
- .then()
- .replaceVisibleLayer(testApp.getPackage(), WALLPAPER_TITLE)
+ .then()
+ .replaceVisibleLayer(testApp.getPackage(), WALLPAPER_TITLE)
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun LayersAssertionBuilderLegacy.layerAlwaysVisible(
packageName: String,
bugId: Int = 0,
@@ -286,6 +547,7 @@ fun LayersAssertionBuilderLegacy.layerAlwaysVisible(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun LayersAssertionBuilderLegacy.layerBecomesVisible(
packageName: String,
bugId: Int = 0,
@@ -293,11 +555,12 @@ fun LayersAssertionBuilderLegacy.layerBecomesVisible(
) {
all("layerBecomesVisible", bugId, enabled) {
this.hidesLayer(packageName)
- .then()
- .showsLayer(packageName)
+ .then()
+ .showsLayer(packageName)
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun LayersAssertionBuilderLegacy.layerBecomesInvisible(
packageName: String,
bugId: Int = 0,
@@ -305,11 +568,12 @@ fun LayersAssertionBuilderLegacy.layerBecomesInvisible(
) {
all("layerBecomesInvisible", bugId, enabled) {
this.showsLayer(packageName)
- .then()
- .hidesLayer(packageName)
+ .then()
+ .hidesLayer(packageName)
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun EventLogAssertionBuilderLegacy.focusChanges(
vararg windows: String,
bugId: Int = 0,
@@ -320,6 +584,7 @@ fun EventLogAssertionBuilderLegacy.focusChanges(
}
}
+@Deprecated("Move the assertion into one of the specific blocks (presubmit, postsubmit, flaky)")
fun EventLogAssertionBuilderLegacy.focusDoesNotChange(
bugId: Int = 0,
enabled: Boolean = bugId == 0
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index b5fd4a50ae66..c507841ffb71 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.close
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -50,7 +49,6 @@ import org.junit.runners.Parameterized
* Test app closes by pressing back button
* To run this test: `atest FlickerTests:CloseAppBackButtonTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -65,7 +63,7 @@ class CloseAppBackButtonTest(
val testApp = SimpleAppHelper(instrumentation)
return FlickerTestRunnerFactory.getInstance()
.buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag("closeAppBackButton", configuration) }
+ withTestName { buildTestTag(configuration) }
repeat { configuration.repetitions }
setup {
test {
@@ -89,29 +87,47 @@ class CloseAppBackButtonTest(
}
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(bugId = 173684672)
+ val isRotated = configuration.startRotation.isRotated()
- launcherReplacesAppWindowAsTopWindow(testApp)
- wallpaperWindowBecomesVisible()
+ presubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ launcherReplacesAppWindowAsTopWindow(testApp)
+ wallpaperWindowBecomesVisible()
+ }
+
+ layersTrace {
+ noUncoveredRegions(configuration.startRotation,
+ Surface.ROTATION_0)
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ wallpaperLayerReplacesAppLayer(testApp)
+
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ }
+ }
}
- layersTrace {
- noUncoveredRegions(configuration.startRotation,
- Surface.ROTATION_0)
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0,
- enabled = !configuration.startRotation.isRotated())
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 173684672)
+ flaky {
+ windowManagerTrace {
+ visibleWindowsShownMoreThanOneConsecutiveEntry(bugId = 173684672)
+ }
+
+ layersTrace {
+ visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 173684672)
- wallpaperLayerReplacesAppLayer(testApp)
+ if (isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 584e4b16fab7..d1c3efe35c54 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -37,6 +37,7 @@ import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEn
import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.isRotated
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
@@ -64,7 +65,7 @@ class CloseAppHomeButtonTest(
val testApp = SimpleAppHelper(instrumentation)
return FlickerTestRunnerFactory.getInstance()
.buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag("closeAppHomeButton", configuration) }
+ withTestName { buildTestTag(configuration) }
repeat { configuration.repetitions }
setup {
test {
@@ -88,28 +89,46 @@ class CloseAppHomeButtonTest(
}
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(bugId = 173689015)
+ val isRotated = configuration.startRotation.isRotated()
- launcherReplacesAppWindowAsTopWindow(testApp)
- wallpaperWindowBecomesVisible()
+ presubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ launcherReplacesAppWindowAsTopWindow(testApp)
+ wallpaperWindowBecomesVisible()
+ }
+
+ layersTrace {
+ noUncoveredRegions(configuration.startRotation,
+ Surface.ROTATION_0)
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ wallpaperLayerReplacesAppLayer(testApp)
+
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ }
+ }
}
- layersTrace {
- val isRotation0 = configuration.startRotation == Surface.ROTATION_0
- noUncoveredRegions(configuration.startRotation,
- Surface.ROTATION_0)
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0, enabled = isRotation0)
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0, enabled = isRotation0)
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 173689015)
+ flaky {
+ windowManagerTrace {
+ visibleWindowsShownMoreThanOneConsecutiveEntry(bugId = 173689015)
+ }
+ layersTrace {
+ visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 173689015)
- wallpaperLayerReplacesAppLayer(testApp)
+ if (isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
index 1a4744980b1e..323236ed9962 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
@@ -43,7 +43,7 @@ fun Flicker.setRotation(rotation: Int) {
wmHelper.waitForAppTransitionIdle()
// Ensure WindowManagerService wait until all animations have completed
- instrumentation.getUiAutomation().syncInputTransactions()
+ instrumentation.uiAutomation.syncInputTransactions()
} catch (e: RemoteException) {
throw RuntimeException(e)
}
@@ -71,8 +71,8 @@ fun buildTestTag(
/**
* Build a test tag for the test
* @param testName Name of the transition(s) being tested
- * @param app App being launcher
* @param configuration Configuration for the test
+ * @param extraInfo Additional information to append to the tag
*
* @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
</END_ROTATION></BEGIN_ROTATION></APP></NAME> */
@@ -92,9 +92,30 @@ fun buildTestTag(
/**
* Build a test tag for the test
+ * @param configuration Configuration for the test
+ * @param extraInfo Additional information to append to the tag
+ *
+ * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
+</END_ROTATION></BEGIN_ROTATION></APP></NAME> */
+@JvmOverloads
+fun buildTestTag(
+ configuration: Bundle,
+ extraInfo: String = ""
+): String {
+ return buildTestTag(testName = null,
+ app = null,
+ beginRotation = configuration.startRotation,
+ endRotation = configuration.endRotation,
+ app2 = null,
+ extraInfo = extraInfo)
+}
+
+/**
+ * Build a test tag for the test
* @param testName Name of the transition(s) being tested
* @param app App being launcher
* @param configuration Configuration for the test
+ * @param extraInfo Additional information to append to the tag
*
* @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
</END_ROTATION></BEGIN_ROTATION></APP></NAME> */
@@ -121,14 +142,17 @@ fun buildTestTag(
* @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
</EXTRA></NAME> */
fun buildTestTag(
- testName: String,
+ testName: String?,
app: String?,
beginRotation: Int,
endRotation: Int,
app2: String?,
extraInfo: String
): String {
- var testTag = testName
+ var testTag = ""
+ if (testName != null) {
+ testTag += testName
+ }
if (app != null) {
testTag += "__$app"
}
@@ -142,5 +166,9 @@ fun buildTestTag(
if (extraInfo.isNotEmpty()) {
testTag += "__$extraInfo"
}
+
+ if (testTag.startsWith("__")) {
+ testTag = testTag.drop(2)
+ }
return testTag
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index fde97ba8b4df..c7736f825e27 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -16,8 +16,6 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -48,11 +46,9 @@ import org.junit.runners.Parameterized
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToAppTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 178015460)
class CloseImeAutoOpenWindowToAppTest(
testSpec: FlickerTestRunnerFactory.TestSpec
) : FlickerTestRunner(testSpec) {
@@ -66,7 +62,7 @@ class CloseImeAutoOpenWindowToAppTest(
.buildTest(instrumentation, repetitions = 5) { configuration ->
val testApp = ImeAppAutoFocusHelper(instrumentation,
configuration.startRotation)
- withTestName { buildTestTag("imeToAppAutoOpen", configuration) }
+ withTestName { buildTestTag(configuration) }
repeat { configuration.repetitions }
setup {
test {
@@ -89,26 +85,39 @@ class CloseImeAutoOpenWindowToAppTest(
testApp.closeIME(device, wmHelper)
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(listOf("InputMethod"))
+ val isRotated = configuration.startRotation.isRotated()
- imeAppWindowIsAlwaysVisible(testApp)
+ postsubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE))
+ imeAppWindowIsAlwaysVisible(testApp)
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.startRotation)
+ imeLayerBecomesInvisible()
+ imeAppLayerIsAlwaysVisible(testApp)
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation)
+ statusBarLayerRotatesScales(configuration.startRotation)
+ }
+ }
}
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(configuration.startRotation)
- navBarLayerRotatesAndScales(configuration.startRotation,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerRotatesScales(configuration.startRotation,
- enabled = !configuration.startRotation.isRotated())
- visibleLayersShownMoreThanOneConsecutiveEntry()
+ flaky {
+ layersTrace {
+ visibleLayersShownMoreThanOneConsecutiveEntry()
- imeLayerBecomesInvisible()
- imeAppLayerIsAlwaysVisible(testApp)
+ if (isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation)
+ statusBarLayerRotatesScales(configuration.startRotation)
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index ab7c08f7902b..aa24456c652f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.ime
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -47,7 +46,6 @@ import org.junit.runners.Parameterized
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToHomeTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -65,7 +63,7 @@ class CloseImeAutoOpenWindowToHomeTest(
val testApp = ImeAppAutoFocusHelper(instrumentation,
configuration.startRotation)
withTestName {
- buildTestTag("imeToHomeAutoOpen", configuration)
+ buildTestTag(configuration)
}
repeat { configuration.repetitions }
setup {
@@ -90,32 +88,50 @@ class CloseImeAutoOpenWindowToHomeTest(
wmHelper.waitImeWindowGone()
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+ val isRotated = configuration.startRotation.isRotated()
- imeWindowBecomesInvisible()
- imeAppWindowBecomesInvisible(testApp)
- }
+ presubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE))
+
+ imeWindowBecomesInvisible()
+ imeAppWindowBecomesInvisible(testApp)
+ }
- layersTrace {
- noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0)
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0,
- enabled = !configuration.startRotation.isRotated())
- navBarLayerIsAlwaysVisible(
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerIsAlwaysVisible(
- enabled = !configuration.startRotation.isRotated())
- visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE),
- enabled = !configuration.startRotation.isRotated())
+ layersTrace {
+ noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0)
+ imeLayerBecomesInvisible()
+ imeAppLayerBecomesInvisible(testApp)
+
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE))
+ }
+ }
+ }
- imeLayerBecomesInvisible()
- imeAppLayerBecomesInvisible(testApp)
+ flaky {
+ layersTrace {
+ if (isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE))
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 0503cce0fbb1..2bd5abb640e5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -16,8 +16,6 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -47,11 +45,9 @@ import org.junit.runners.Parameterized
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 178015460)
class CloseImeWindowToAppTest(
testSpec: FlickerTestRunnerFactory.TestSpec
) : FlickerTestRunner(testSpec) {
@@ -64,7 +60,7 @@ class CloseImeWindowToAppTest(
val testApp = ImeAppHelper(instrumentation)
return FlickerTestRunnerFactory.getInstance()
.buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag("imeToApp", configuration) }
+ withTestName { buildTestTag(configuration) }
repeat { configuration.repetitions }
setup {
test {
@@ -86,24 +82,25 @@ class CloseImeWindowToAppTest(
testApp.closeIME(device, wmHelper)
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(listOf("InputMethod"))
+ postsubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE))
+ imeAppWindowIsAlwaysVisible(testApp)
+ }
- imeAppWindowIsAlwaysVisible(testApp)
- }
-
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(configuration.startRotation)
- navBarLayerRotatesAndScales(configuration.startRotation)
- statusBarLayerRotatesScales(configuration.startRotation)
- visibleLayersShownMoreThanOneConsecutiveEntry()
-
- imeLayerBecomesInvisible()
- imeAppLayerIsAlwaysVisible(testApp)
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.startRotation)
+ navBarLayerRotatesAndScales(configuration.startRotation)
+ statusBarLayerRotatesScales(configuration.startRotation)
+ visibleLayersShownMoreThanOneConsecutiveEntry()
+ imeLayerBecomesInvisible()
+ imeAppLayerIsAlwaysVisible(testApp)
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 9cb075b8a0bd..7b61bb58446c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -16,8 +16,6 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -47,11 +45,9 @@ import org.junit.runners.Parameterized
* Test IME window closing to home transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToHomeTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 178015460)
class CloseImeWindowToHomeTest(
testSpec: FlickerTestRunnerFactory.TestSpec
) : FlickerTestRunner(testSpec) {
@@ -63,7 +59,7 @@ class CloseImeWindowToHomeTest(
val testApp = ImeAppHelper(instrumentation)
return FlickerTestRunnerFactory.getInstance()
.buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag("imeToHome", configuration) }
+ withTestName { buildTestTag(configuration) }
repeat { configuration.repetitions }
setup {
test {
@@ -91,31 +87,47 @@ class CloseImeWindowToHomeTest(
}
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE))
+ val isRotated = configuration.startRotation.isRotated()
- imeWindowBecomesInvisible()
- imeAppWindowBecomesInvisible(testApp)
+ postsubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE))
+ imeWindowBecomesInvisible()
+ imeAppWindowBecomesInvisible(testApp)
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ imeLayerBecomesInvisible()
+ imeAppLayerBecomesInvisible(testApp)
+ noUncoveredRegions(configuration.startRotation,
+ Surface.ROTATION_0)
+
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ }
+ }
}
- layersTrace {
- noUncoveredRegions(configuration.startRotation,
- Surface.ROTATION_0)
- navBarLayerRotatesAndScales(configuration.startRotation,
- Surface.ROTATION_0,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerRotatesScales(configuration.startRotation,
- Surface.ROTATION_0,
- enabled = !configuration.startRotation.isRotated())
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(listOf(IME_WINDOW_TITLE),
- enabled = false)
+ flaky {
+ layersTrace {
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ listOf(IME_WINDOW_TITLE))
- imeLayerBecomesInvisible()
- imeAppLayerBecomesInvisible(testApp)
+ if (isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
index c775cb855ff4..cfdd8564128f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -17,106 +17,82 @@
package com.android.server.wm.flicker.ime
import android.platform.helpers.IAppHelper
-import com.android.server.wm.flicker.dsl.LayersAssertionBuilderLegacy
-import com.android.server.wm.flicker.dsl.WmAssertionBuilderLegacy
+import com.android.server.wm.flicker.dsl.LayersAssertionBuilder
+import com.android.server.wm.flicker.dsl.WmAssertionBuilder
const val IME_WINDOW_TITLE = "InputMethod"
@JvmOverloads
-fun LayersAssertionBuilderLegacy.imeLayerBecomesVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("imeLayerBecomesVisible", bugId, enabled) {
+fun LayersAssertionBuilder.imeLayerBecomesVisible(bugId: Int = 0) {
+ all("imeLayerBecomesVisible", bugId) {
this.hidesLayer(IME_WINDOW_TITLE)
.then()
.showsLayer(IME_WINDOW_TITLE)
}
}
-fun LayersAssertionBuilderLegacy.imeLayerBecomesInvisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("imeLayerBecomesInvisible", bugId, enabled) {
+@JvmOverloads
+fun LayersAssertionBuilder.imeLayerBecomesInvisible(bugId: Int = 0) {
+ all("imeLayerBecomesInvisible", bugId) {
this.showsLayer(IME_WINDOW_TITLE)
.then()
.hidesLayer(IME_WINDOW_TITLE)
}
}
-fun LayersAssertionBuilderLegacy.imeAppLayerIsAlwaysVisible(
- testApp: IAppHelper,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("imeAppLayerIsAlwaysVisible", bugId, enabled) {
+@JvmOverloads
+fun LayersAssertionBuilder.imeAppLayerIsAlwaysVisible(testApp: IAppHelper, bugId: Int = 0) {
+ all("imeAppLayerIsAlwaysVisible", bugId) {
this.showsLayer(testApp.getPackage())
}
}
-fun WmAssertionBuilderLegacy.imeAppWindowIsAlwaysVisible(
- testApp: IAppHelper,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("imeAppWindowIsAlwaysVisible", bugId, enabled) {
+@JvmOverloads
+fun WmAssertionBuilder.imeAppWindowIsAlwaysVisible(testApp: IAppHelper, bugId: Int = 0) {
+ all("imeAppWindowIsAlwaysVisible", bugId) {
this.showsAppWindowOnTop(testApp.getPackage())
}
}
-fun WmAssertionBuilderLegacy.imeWindowBecomesVisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("imeWindowBecomesVisible", bugId, enabled) {
+@JvmOverloads
+fun WmAssertionBuilder.imeWindowBecomesVisible(bugId: Int = 0) {
+ all("imeWindowBecomesVisible", bugId) {
this.hidesNonAppWindow(IME_WINDOW_TITLE)
.then()
.showsNonAppWindow(IME_WINDOW_TITLE)
}
}
-fun WmAssertionBuilderLegacy.imeWindowBecomesInvisible(
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("imeWindowBecomesInvisible", bugId, enabled) {
+@JvmOverloads
+fun WmAssertionBuilder.imeWindowBecomesInvisible(bugId: Int = 0) {
+ all("imeWindowBecomesInvisible", bugId) {
this.showsNonAppWindow(IME_WINDOW_TITLE)
.then()
.hidesNonAppWindow(IME_WINDOW_TITLE)
}
}
-fun WmAssertionBuilderLegacy.imeAppWindowBecomesVisible(
- windowName: String,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("imeAppWindowBecomesVisible", bugId, enabled) {
+@JvmOverloads
+fun WmAssertionBuilder.imeAppWindowBecomesVisible(windowName: String, bugId: Int = 0) {
+ all("imeAppWindowBecomesVisible", bugId) {
this.hidesAppWindow(windowName)
.then()
.showsAppWindow(windowName)
}
}
-fun WmAssertionBuilderLegacy.imeAppWindowBecomesInvisible(
- testApp: IAppHelper,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("imeAppWindowBecomesInvisible", bugId, enabled) {
+@JvmOverloads
+fun WmAssertionBuilder.imeAppWindowBecomesInvisible(testApp: IAppHelper, bugId: Int = 0) {
+ all("imeAppWindowBecomesInvisible", bugId) {
this.showsAppWindowOnTop(testApp.getPackage())
.then()
.appWindowNotOnTop(testApp.getPackage())
}
}
-fun LayersAssertionBuilderLegacy.imeAppLayerBecomesInvisible(
- testApp: IAppHelper,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("imeAppLayerBecomesInvisible", bugId, enabled) {
+@JvmOverloads
+fun LayersAssertionBuilder.imeAppLayerBecomesInvisible(testApp: IAppHelper, bugId: Int = 0) {
+ all("imeAppLayerBecomesInvisible", bugId) {
this.skipUntilFirstAssertion()
.showsLayer(testApp.getPackage())
.then()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 13c6cd7e6e18..9e94d6e49527 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -16,8 +16,6 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -50,11 +48,9 @@ import org.junit.runners.Parameterized
* Test IME window opening transitions.
* To run this test: `atest FlickerTests:OpenImeWindowTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 178015460)
class OpenImeWindowTest(
testSpec: FlickerTestRunnerFactory.TestSpec
) : FlickerTestRunner(testSpec) {
@@ -66,7 +62,7 @@ class OpenImeWindowTest(
val testApp = ImeAppHelper(instrumentation)
return FlickerTestRunnerFactory.getInstance()
.buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag("openIme", configuration) }
+ withTestName { buildTestTag(configuration) }
repeat { configuration.repetitions }
setup {
test {
@@ -88,27 +84,43 @@ class OpenImeWindowTest(
}
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
+ val isRotated = configuration.startRotation.isRotated()
- imeWindowBecomesVisible()
- appWindowAlwaysVisibleOnTop(testApp.`package`)
+ postsubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+
+ imeWindowBecomesVisible()
+ appWindowAlwaysVisibleOnTop(testApp.`package`)
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(configuration.startRotation)
+ imeLayerBecomesVisible()
+ layerAlwaysVisible(testApp.`package`)
+
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation)
+ statusBarLayerRotatesScales(configuration.startRotation)
+ }
+ }
}
- layersTrace {
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- noUncoveredRegions(configuration.startRotation)
- navBarLayerRotatesAndScales(configuration.startRotation,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerRotatesScales(configuration.startRotation,
- enabled = !configuration.startRotation.isRotated())
- visibleLayersShownMoreThanOneConsecutiveEntry()
+ flaky {
+ windowManagerTrace {
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ layersTrace {
+ visibleLayersShownMoreThanOneConsecutiveEntry()
- imeLayerBecomesVisible()
- layerAlwaysVisible(testApp.`package`)
+ if (isRotated) {
+ navBarLayerRotatesAndScales(configuration.startRotation)
+ statusBarLayerRotatesScales(configuration.startRotation)
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 6cc64dfd8836..2fe49af26cc1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.ime
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -52,7 +51,6 @@ import org.junit.runners.Parameterized
* Test IME window opening transitions.
* To run this test: `atest FlickerTests:ReOpenImeWindowTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -67,34 +65,37 @@ class ReOpenImeWindowTest(
val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
return FlickerTestRunnerFactory.getInstance()
.buildTest(instrumentation, repetitions = 1) { configuration ->
- val testApp = ImeAppAutoFocusHelper(instrumentation,
- configuration.startRotation)
- withTestName { buildTestTag("reOpenImeAutoFocus", configuration) }
- repeat { configuration.repetitions }
- setup {
- test {
- device.wakeUpAndGoToHomeScreen()
- testApp.launchViaIntent(wmHelper)
- testApp.openIME(device, wmHelper)
- }
- eachRun {
- device.pressRecentApps()
- wmHelper.waitImeWindowGone()
- wmHelper.waitForAppTransitionIdle()
- this.setRotation(configuration.startRotation)
- }
+ val testApp = ImeAppAutoFocusHelper(instrumentation,
+ configuration.startRotation)
+ withTestName { buildTestTag(configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent(wmHelper)
+ testApp.openIME(device, wmHelper)
}
- transitions {
- device.reopenAppFromOverview()
- wmHelper.waitImeWindowShown()
+ eachRun {
+ device.pressRecentApps()
+ wmHelper.waitImeWindowGone()
+ wmHelper.waitForAppTransitionIdle()
+ this.setRotation(configuration.startRotation)
}
- teardown {
- test {
- this.setRotation(Surface.ROTATION_0)
- testApp.exit()
- }
+ }
+ transitions {
+ device.reopenAppFromOverview()
+ wmHelper.waitImeWindowShown()
+ }
+ teardown {
+ test {
+ this.setRotation(Surface.ROTATION_0)
+ testApp.exit()
}
- assertions {
+ }
+ assertions {
+ val isRotated = configuration.startRotation.isRotated()
+
+ presubmit {
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
@@ -107,21 +108,34 @@ class ReOpenImeWindowTest(
layersTrace {
noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation)
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation,
- enabled = !configuration.startRotation.isRotated())
statusBarLayerIsAlwaysVisible()
navBarLayerIsAlwaysVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(enabled = false)
-
imeLayerBecomesVisible()
appLayerReplacesWallpaperLayer(testAppComponentName.className)
+
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ }
+ }
+ }
+
+ flaky {
+ layersTrace {
+ visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ if (isRotated) {
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ }
}
}
}
+ }
}
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
index 1bd1190313d8..be3fa5fa3cdf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -17,14 +17,10 @@
package com.android.server.wm.flicker.launch
import android.platform.helpers.IAppHelper
-import com.android.server.wm.flicker.dsl.WmAssertionBuilderLegacy
+import com.android.server.wm.flicker.dsl.WmAssertionBuilder
-fun WmAssertionBuilderLegacy.appWindowReplacesLauncherAsTopWindow(
- testApp: IAppHelper,
- bugId: Int = 0,
- enabled: Boolean = bugId == 0
-) {
- all("appWindowReplacesLauncherAsTopWindow", bugId, enabled) {
+fun WmAssertionBuilder.appWindowReplacesLauncherAsTopWindow(testApp: IAppHelper, bugId: Int = 0) {
+ all("appWindowReplacesLauncherAsTopWindow", bugId) {
this.showsAppWindowOnTop("Launcher")
.then()
.showsAppWindowOnTop("Snapshot", testApp.getPackage())
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 010ebf2c2788..0ec0b04339cd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -51,7 +50,6 @@ import org.junit.runners.Parameterized
* Test cold launch app from launcher.
* To run this test: `atest FlickerTests:OpenAppColdTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -66,7 +64,7 @@ class OpenAppColdTest(
val testApp = SimpleAppHelper(instrumentation)
return FlickerTestRunnerFactory.getInstance()
.buildTest(instrumentation) { configuration ->
- withTestName { buildTestTag("openAppCold", testApp, configuration) }
+ withTestName { buildTestTag(configuration) }
repeat { configuration.repetitions }
setup {
test {
@@ -88,33 +86,48 @@ class OpenAppColdTest(
}
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
+ val isRotated = configuration.startRotation.isRotated()
- appWindowReplacesLauncherAsTopWindow(testApp)
- wallpaperWindowBecomesInvisible()
- }
+ presubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+ appWindowReplacesLauncherAsTopWindow(testApp)
+ wallpaperWindowBecomesInvisible()
+ }
+
+ layersTrace {
+ // During testing the launcher is always in portrait mode
+ noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation)
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ appLayerReplacesWallpaperLayer(testApp.`package`)
- layersTrace {
- // During testing the launcher is always in portrait mode
- noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation)
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation,
- enabled = !configuration.startRotation.isRotated())
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(enabled = false)
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ }
+ }
- appLayerReplacesWallpaperLayer(testApp.`package`)
+ eventLog {
+ focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
}
- eventLog {
- focusChanges("NexusLauncherActivity", testApp.`package`)
+ flaky {
+ layersTrace {
+ visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ if (isRotated) {
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 5e08921c2253..84cc8e3ab058 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -52,7 +51,6 @@ import org.junit.runners.Parameterized
* Launch an app from the recents app view (the overview)
* To run this test: `atest FlickerTests:OpenAppFromOverviewTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -67,7 +65,7 @@ class OpenAppFromOverviewTest(
val testApp = SimpleAppHelper(instrumentation)
return FlickerTestRunnerFactory.getInstance()
.buildTest(instrumentation, repetitions = 5) { configuration ->
- withTestName { buildTestTag("openAppFromOverview", configuration) }
+ withTestName { buildTestTag(configuration) }
repeat { configuration.repetitions }
setup {
test {
@@ -92,36 +90,57 @@ class OpenAppFromOverviewTest(
}
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
+ val isRotated = configuration.startRotation.isRotated()
- appWindowReplacesLauncherAsTopWindow(testApp)
- wallpaperWindowBecomesInvisible()
- }
+ presubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ appWindowReplacesLauncherAsTopWindow(testApp)
+ wallpaperWindowBecomesInvisible()
+ }
+
+ layersTrace {
+ appLayerReplacesWallpaperLayer(testApp.`package`)
- layersTrace {
- noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation,
- bugId = 141361128)
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerIsAlwaysVisible(
- enabled = Surface.ROTATION_0 == configuration.endRotation)
- navBarLayerIsAlwaysVisible(
- enabled = Surface.ROTATION_0 == configuration.endRotation)
- visibleLayersShownMoreThanOneConsecutiveEntry(
- enabled = false)
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ } else {
+ statusBarLayerIsAlwaysVisible()
+ navBarLayerIsAlwaysVisible()
+ }
+ }
- appLayerReplacesWallpaperLayer(testApp.`package`)
+ eventLog {
+ focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
}
- eventLog {
- focusChanges("NexusLauncherActivity", testApp.`package`)
+ postsubmit {
+ windowManagerTrace {
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+ }
+
+ flaky {
+ layersTrace {
+ visibleLayersShownMoreThanOneConsecutiveEntry()
+ noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation,
+ bugId = 141361128)
+
+ if (isRotated) {
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ } else {
+ statusBarLayerIsAlwaysVisible()
+ navBarLayerIsAlwaysVisible()
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 092cd4d2dad6..1f375a5cdea8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.launch
-import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -51,7 +50,6 @@ import org.junit.runners.Parameterized
* Test warm launch app.
* To run this test: `atest FlickerTests:OpenAppWarmTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -64,7 +62,7 @@ class OpenAppWarmTest(testSpec: FlickerTestRunnerFactory.TestSpec) : FlickerTest
val testApp = SimpleAppHelper(instrumentation)
return FlickerTestRunnerFactory.getInstance()
.buildTest(instrumentation) { configuration ->
- withTestName { buildTestTag("openAppWarm", testApp, configuration) }
+ withTestName { buildTestTag(configuration) }
repeat { configuration.repetitions }
setup {
test {
@@ -91,33 +89,49 @@ class OpenAppWarmTest(testSpec: FlickerTestRunnerFactory.TestSpec) : FlickerTest
}
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
+ val isRotated = configuration.startRotation.isRotated()
- appWindowReplacesLauncherAsTopWindow(testApp)
- wallpaperWindowBecomesInvisible()
- }
+ presubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ appWindowReplacesLauncherAsTopWindow(testApp)
+ wallpaperWindowBecomesInvisible()
+ }
- layersTrace {
- // During testing the launcher is always in portrait mode
- noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation)
- navBarLayerRotatesAndScales(Surface.ROTATION_0,
- configuration.endRotation,
- enabled = !configuration.startRotation.isRotated())
- statusBarLayerRotatesScales(Surface.ROTATION_0,
- configuration.endRotation,
- enabled = !configuration.startRotation.isRotated())
- navBarLayerIsAlwaysVisible()
- statusBarLayerIsAlwaysVisible()
- visibleLayersShownMoreThanOneConsecutiveEntry(enabled = false)
+ layersTrace {
+ // During testing the launcher is always in portrait mode
+ noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation)
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ appLayerReplacesWallpaperLayer(testApp.`package`)
- appLayerReplacesWallpaperLayer(testApp.`package`)
+ if (!isRotated) {
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ }
+ }
+
+ eventLog {
+ focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
}
- eventLog {
- focusChanges("NexusLauncherActivity", testApp.`package`)
+ flaky {
+ layersTrace {
+ visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ if (isRotated) {
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 1c44b21c0f9a..7bfdd96b9af8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.rotation
import android.os.Bundle
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerTestRunner
@@ -48,7 +47,6 @@ import org.junit.runners.Parameterized
* Cycle through supported app rotations.
* To run this test: `atest FlickerTests:ChangeAppRotationTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -67,51 +65,56 @@ class ChangeAppRotationTest(
@JvmStatic
fun getParams(): Collection<Array<Any>> {
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
- withTestName { buildTestTag("changeAppRotation", configuration) }
+ withTestName { buildTestTag(configuration) }
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible()
- statusBarWindowIsAlwaysVisible()
- visibleWindowsShownMoreThanOneConsecutiveEntry()
- }
+ presubmit {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- noUncoveredRegions(configuration.startRotation,
- configuration.endRotation, allStates = false)
- navBarLayerRotatesAndScales(configuration.startRotation,
- configuration.endRotation, bugId = 140855415)
- statusBarLayerRotatesScales(configuration.startRotation,
- configuration.endRotation, bugId = 140855415)
- visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 140855415)
+ layersTrace {
+ noUncoveredRegions(configuration.startRotation,
+ configuration.endRotation, allStates = false)
+
+ all("screenshotLayerBecomesInvisible") {
+ this.showsLayer(testApp.getPackage())
+ .then()
+ .showsLayer(SCREENSHOT_LAYER)
+ .then()
+ .showsLayer(testApp.getPackage())
+ }
+ }
}
- layersTrace {
- val startingPos = WindowUtils.getDisplayBounds(
- configuration.startRotation)
- val endingPos = WindowUtils.getDisplayBounds(
- configuration.endRotation)
+ flaky {
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ configuration.endRotation, bugId = 140855415)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ configuration.endRotation, bugId = 140855415)
+ visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 140855415)
- start("appLayerRotates_StartingPos", bugId = 140855415) {
- this.hasVisibleRegion(testApp.getPackage(), startingPos)
- }
+ val startingPos = WindowUtils.getDisplayBounds(
+ configuration.startRotation)
+ val endingPos = WindowUtils.getDisplayBounds(
+ configuration.endRotation)
- end("appLayerRotates_EndingPos", bugId = 140855415) {
- this.hasVisibleRegion(testApp.getPackage(), endingPos)
- }
+ start("appLayerRotates_StartingPos", bugId = 140855415) {
+ this.hasVisibleRegion(testApp.getPackage(), startingPos)
+ }
- all("screenshotLayerBecomesInvisible") {
- this.showsLayer(testApp.getPackage())
- .then()
- .showsLayer(SCREENSHOT_LAYER)
- .then()
- .showsLayer(testApp.getPackage())
+ end("appLayerRotates_EndingPos", bugId = 140855415) {
+ this.hasVisibleRegion(testApp.getPackage(), endingPos)
+ }
}
- }
- eventLog {
- focusDoesNotChange(bugId = 151179149)
+ eventLog {
+ focusDoesNotChange(bugId = 151179149)
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index f04131b64cd4..78614640a372 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -17,7 +17,6 @@
package com.android.server.wm.flicker.rotation
import android.os.Bundle
-import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerTestRunner
@@ -51,7 +50,6 @@ import org.junit.runners.Parameterized
* Cycle through supported app rotations using seamless rotations.
* To run this test: `atest FlickerTests:SeamlessAppRotationTest`
*/
-@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -97,63 +95,67 @@ class SeamlessAppRotationTest(
} else {
""
}
- buildTestTag("seamlessRotation", configuration, extraInfo = extra)
+ buildTestTag(configuration, extraInfo = extra)
}
assertions {
- windowManagerTrace {
- navBarWindowIsAlwaysVisible(bugId = 140855415)
- statusBarWindowIsAlwaysVisible(bugId = 140855415)
- visibleWindowsShownMoreThanOneConsecutiveEntry()
- appWindowAlwaysVisibleOnTop(testApp.`package`)
- }
+ val startingBounds = WindowUtils.getDisplayBounds(configuration.startRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(configuration.endRotation)
+
+ presubmit {
+ windowManagerTrace {
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+ appWindowAlwaysVisibleOnTop(testApp.`package`)
+ }
- layersTrace {
- navBarLayerIsAlwaysVisible(bugId = 140855415)
- statusBarLayerIsAlwaysVisible(bugId = 140855415)
- noUncoveredRegions(configuration.startRotation,
- configuration.endRotation, allStates = false, bugId = 147659548)
- navBarLayerRotatesAndScales(configuration.startRotation,
- configuration.endRotation,
- enabled = false)
- statusBarLayerRotatesScales(configuration.startRotation,
- configuration.endRotation, enabled = false)
- visibleLayersShownMoreThanOneConsecutiveEntry(
- enabled = configuration.startRotation == configuration.endRotation)
- layerAlwaysVisible(testApp.`package`)
+ layersTrace {
+ layerAlwaysVisible(testApp.`package`)
+ }
}
- layersTrace {
- val startingBounds = WindowUtils
- .getDisplayBounds(configuration.startRotation)
- val endingBounds = WindowUtils
- .getDisplayBounds(configuration.endRotation)
-
- all("appLayerRotates", bugId = 147659548) {
- if (startingBounds == endingBounds) {
- this.hasVisibleRegion(
- testApp.`package`, startingBounds)
- } else {
- this.hasVisibleRegion(testApp.`package`,
- startingBounds)
- .then()
- .hasVisibleRegion(testApp.`package`,
- endingBounds)
- }
+ flaky {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible(bugId = 140855415)
+ statusBarWindowIsAlwaysVisible(bugId = 140855415)
}
- all("noUncoveredRegions", bugId = 147659548) {
- if (startingBounds == endingBounds) {
- this.coversAtLeastRegion(startingBounds)
- } else {
- this.coversAtLeastRegion(startingBounds)
- .then()
- .coversAtLeastRegion(endingBounds)
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ noUncoveredRegions(configuration.startRotation,
+ configuration.endRotation, allStates = false, bugId = 147659548)
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ configuration.endRotation)
+ visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ all("appLayerRotates", bugId = 147659548) {
+ if (startingBounds == endingBounds) {
+ this.hasVisibleRegion(
+ testApp.`package`, startingBounds)
+ } else {
+ this.hasVisibleRegion(testApp.`package`,
+ startingBounds)
+ .then()
+ .hasVisibleRegion(testApp.`package`,
+ endingBounds)
+ }
+ }
+
+ all("noUncoveredRegions", bugId = 147659548) {
+ if (startingBounds == endingBounds) {
+ this.coversAtLeastRegion(startingBounds)
+ } else {
+ this.coversAtLeastRegion(startingBounds)
+ .then()
+ .coversAtLeastRegion(endingBounds)
+ }
}
}
- }
- eventLog {
- focusDoesNotChange(bugId = 151179149)
+ eventLog {
+ focusDoesNotChange(bugId = 151179149)
+ }
}
}
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 1a940c75cfa4..c6c67feeed72 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -753,6 +753,15 @@
</intent-filter>
</activity>
+ <activity android:name="RenderEffectShaderActivity"
+ android:label="RenderEffect/Shader"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.android.test.hwui.TEST"/>
+ </intent-filter>
+ </activity>
+
<activity android:name="TextActivity"
android:label="Text/Simple Text"
android:theme="@android:style/Theme.NoTitleBar"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java
new file mode 100644
index 000000000000..661d48a84768
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectShaderActivity.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.RenderEffect;
+import android.graphics.RenderNode;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class RenderEffectShaderActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setClipChildren(false);
+ layout.setGravity(Gravity.CENTER);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500, 500);
+ params.bottomMargin = 100;
+
+ layout.addView(new ShaderRenderEffectView(this), params);
+
+ setContentView(layout);
+ }
+
+ public static class ShaderRenderEffectView extends View {
+
+ private final Paint mPaint;
+ private final RenderNode mRenderNode;
+
+ public ShaderRenderEffectView(Context c) {
+ super(c);
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mRenderNode = new RenderNode("blurNode");
+
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed) {
+ LinearGradient gradient = new LinearGradient(
+ 0f, 0f,
+ 0f, bottom - top,
+ new int[]{Color.CYAN, Color.MAGENTA},
+ null,
+ Shader.TileMode.CLAMP
+ );
+ mRenderNode.setRenderEffect(
+ RenderEffect.createShaderEffect(gradient)
+ );
+
+ int width = right - left;
+ int height = bottom - top;
+ mRenderNode.setPosition(0, 0, width, height);
+ Canvas canvas = mRenderNode.beginRecording(width, height);
+ mPaint.setColor(Color.BLUE);
+
+ canvas.drawRect(
+ 0,
+ 0,
+ width,
+ height,
+ mPaint
+ );
+
+ mPaint.setColor(Color.RED);
+ canvas.drawCircle((right - left) / 2f, (bottom - top) / 2f, 50f, mPaint);
+
+ mRenderNode.endRecording();
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRenderNode(mRenderNode);
+ }
+ }
+}
diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
index 9b15b0445642..5c2644844e14 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt
@@ -34,12 +34,14 @@ class ColorModeControls : LinearLayout, WindowObserver {
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
displayManager = context.getSystemService(DisplayManager::class.java)!!
+ displayId = context.getDisplayId()
}
private var window: Window? = null
private var currentModeDisplay: TextView? = null
private val displayManager: DisplayManager
private var targetSdrWhitePointIndex = 0
+ private var displayId: Int
private val whitePoint get() = SDR_WHITE_POINTS[targetSdrWhitePointIndex]
@@ -107,7 +109,7 @@ class ColorModeControls : LinearLayout, WindowObserver {
// Imperfect, but close enough, synchronization by waiting for frame commit to set the value
viewTreeObserver.registerFrameCommitCallback {
try {
- displayManager.setTemporaryBrightness(level)
+ displayManager.setTemporaryBrightness(displayId, level)
} catch (ex: Exception) {
// Ignore a permission denied rejection - it doesn't meaningfully change much
}
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index dc9e587332cb..e1da3d0ae2b3 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -84,6 +85,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
mNetworkCapabilities.addTransportType(transport);
switch (transport) {
case TRANSPORT_ETHERNET:
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index c2fddf3d9e82..fcfb4aa9b864 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -345,15 +345,17 @@ public class ConnectivityManagerTest {
@Test
public void testRequestType() throws Exception {
final String testPkgName = "MyPackage";
+ final String testAttributionTag = "MyTag";
final ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
when(mCtx.getOpPackageName()).thenReturn(testPkgName);
+ when(mCtx.getAttributionTag()).thenReturn(testAttributionTag);
final NetworkRequest request = makeRequest(1);
final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
manager.requestNetwork(request, callback);
verify(mService).requestNetwork(eq(request.networkCapabilities),
eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
- eq(testPkgName), eq(null));
+ eq(testPkgName), eq(testAttributionTag));
reset(mService);
// Verify that register network callback does not calls requestNetwork at all.
@@ -361,19 +363,19 @@ public class ConnectivityManagerTest {
verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(),
anyInt(), any(), any());
verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(),
- eq(testPkgName));
+ eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.registerDefaultNetworkCallback(callback);
verify(mService).requestNetwork(eq(null),
eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
- eq(testPkgName), eq(null));
+ eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.requestBackgroundNetwork(request, null, callback);
verify(mService).requestNetwork(eq(request.networkCapabilities),
eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
- eq(testPkgName), eq(null));
+ eq(testPkgName), eq(testAttributionTag));
reset(mService);
}
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 91fcbc0fd5d7..1f8f6f311069 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -35,7 +35,6 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
import kotlin.test.assertFalse
@@ -60,16 +59,13 @@ class NetworkTemplateTest {
subscriberId: String? = null,
ssid: String? = null
): NetworkState {
- val info = mock(NetworkInfo::class.java)
- doReturn(type).`when`(info).type
- doReturn(NetworkInfo.State.CONNECTED).`when`(info).state
val lp = LinkProperties()
val caps = NetworkCapabilities().apply {
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
setSSID(ssid)
}
- return NetworkState(info, lp, caps, mock(Network::class.java), subscriberId, ssid)
+ return NetworkState(type, lp, caps, mock(Network::class.java), subscriberId, ssid)
}
private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index bcbc9e0d6007..bf6163438ba2 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -2707,6 +2707,10 @@ public class ConnectivityServiceTest {
NetworkCapabilities filter = new NetworkCapabilities();
filter.addCapability(capability);
+ // Add NOT_VCN_MANAGED capability into filter unconditionally since some request will add
+ // NOT_VCN_MANAGED automatically but not for NetworkCapabilities,
+ // see {@code NetworkCapabilities#deduceNotVcnManagedCapability} for more details.
+ filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
handlerThread.start();
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
@@ -3958,6 +3962,7 @@ public class ConnectivityServiceTest {
handlerThread.start();
NetworkCapabilities filter = new NetworkCapabilities()
.addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.addCapability(NET_CAPABILITY_INTERNET);
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
mServiceContext, "testFactory", filter);
@@ -5861,6 +5866,7 @@ public class ConnectivityServiceTest {
.addTransportType(TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkDownstreamBandwidthKbps(10);
final NetworkCapabilities wifiNc = new NetworkCapabilities()
.addTransportType(TRANSPORT_WIFI)
@@ -5869,6 +5875,7 @@ public class ConnectivityServiceTest {
.addCapability(NET_CAPABILITY_NOT_ROAMING)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
.addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkUpstreamBandwidthKbps(20);
mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
@@ -6365,7 +6372,7 @@ public class ConnectivityServiceTest {
private void assertDefaultNetworkCapabilities(int userId, NetworkAgentWrapper... networks) {
final NetworkCapabilities[] defaultCaps = mService.getDefaultNetworkCapabilitiesForUser(
- userId, "com.android.calling.package");
+ userId, "com.android.calling.package", "com.test");
final String defaultCapsString = Arrays.toString(defaultCaps);
assertEquals(defaultCapsString, defaultCaps.length, networks.length);
final Set<NetworkCapabilities> defaultCapsSet = new ArraySet<>(defaultCaps);
@@ -7514,19 +7521,13 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.removeCapability(testCap);
callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
- // TODO: Test default network changes for NOT_VCN_MANAGED once the default request has
- // it.
- if (testCap == NET_CAPABILITY_TRUSTED) {
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
- }
+ verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
mCellNetworkAgent.removeCapability(testCap);
callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
callbackWithoutCap.assertNoCallback();
- if (testCap == NET_CAPABILITY_TRUSTED) {
- verify(mMockNetd).networkClearDefault();
- }
+ verify(mMockNetd).networkClearDefault();
mCm.unregisterNetworkCallback(callbackWithCap);
mCm.unregisterNetworkCallback(callbackWithoutCap);
@@ -8377,7 +8378,8 @@ public class ConnectivityServiceTest {
when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
if (op != null) {
- when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
+ when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()),
+ eq(mContext.getPackageName()), eq(getAttributionTag()), anyString()))
.thenReturn(AppOpsManager.MODE_ALLOWED);
}
@@ -8390,7 +8392,7 @@ public class ConnectivityServiceTest {
final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, callerUid, mContext.getPackageName()).getOwnerUid();
+ netCap, callerUid, mContext.getPackageName(), getAttributionTag()).getOwnerUid();
}
private void verifyWifiInfoCopyNetCapsForCallerPermission(
@@ -8400,7 +8402,7 @@ public class ConnectivityServiceTest {
final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, callerUid, mContext.getPackageName());
+ netCap, callerUid, mContext.getPackageName(), getAttributionTag());
verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index dde78aa54199..214c82da17dc 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -80,8 +80,6 @@ import android.net.INetworkStatsSession;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
@@ -1456,8 +1454,6 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
}
private static NetworkState buildWifiState(boolean isMetered, @NonNull String iface) {
- final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
- info.setDetailedState(DetailedState.CONNECTED, null, null);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(iface);
final NetworkCapabilities capabilities = new NetworkCapabilities();
@@ -1465,7 +1461,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
capabilities.setSSID(TEST_SSID);
- return new NetworkState(info, prop, capabilities, WIFI_NETWORK, null, TEST_SSID);
+ return new NetworkState(TYPE_WIFI, prop, capabilities, WIFI_NETWORK, null, TEST_SSID);
}
private static NetworkState buildMobile3gState(String subscriberId) {
@@ -1473,17 +1469,14 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
}
private static NetworkState buildMobile3gState(String subscriberId, boolean isRoaming) {
- final NetworkInfo info = new NetworkInfo(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UMTS, null, null);
- info.setDetailedState(DetailedState.CONNECTED, null, null);
- info.setRoaming(isRoaming);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities capabilities = new NetworkCapabilities();
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, subscriberId, null);
+ return new NetworkState(
+ TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId, null);
}
private NetworkStats buildEmptyStats() {
@@ -1491,11 +1484,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
}
private static NetworkState buildVpnState() {
- final NetworkInfo info = new NetworkInfo(TYPE_VPN, 0, null, null);
- info.setDetailedState(DetailedState.CONNECTED, null, null);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TUN_IFACE);
- return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null);
+ return new NetworkState(TYPE_VPN, prop, new NetworkCapabilities(), VPN_NETWORK, null, null);
}
private long getElapsedRealtime() {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index e20070ee4f07..278d93a1b17b 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -18,22 +18,35 @@ package com.android.server.vcn;
import static android.net.IpSecManager.DIRECTION_IN;
import static android.net.IpSecManager.DIRECTION_OUT;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Collections;
/** Tests for VcnGatewayConnection.ConnectedState */
@RunWith(AndroidJUnit4.class)
@@ -107,6 +120,51 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
}
@Test
+ public void testChildOpenedRegistersNetwork() throws Exception {
+ final VcnChildSessionConfiguration mMockChildSessionConfig =
+ mock(VcnChildSessionConfiguration.class);
+ doReturn(Collections.singletonList(TEST_INTERNAL_ADDR))
+ .when(mMockChildSessionConfig)
+ .getInternalAddresses();
+ doReturn(Collections.singletonList(TEST_DNS_ADDR))
+ .when(mMockChildSessionConfig)
+ .getInternalDnsServers();
+
+ getChildSessionCallback().onOpened(mMockChildSessionConfig);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+
+ final ArgumentCaptor<LinkProperties> lpCaptor =
+ ArgumentCaptor.forClass(LinkProperties.class);
+ final ArgumentCaptor<NetworkCapabilities> ncCaptor =
+ ArgumentCaptor.forClass(NetworkCapabilities.class);
+ verify(mConnMgr)
+ .registerNetworkAgent(
+ any(),
+ any(),
+ lpCaptor.capture(),
+ ncCaptor.capture(),
+ anyInt(),
+ any(),
+ anyInt());
+ verify(mIpSecSvc)
+ .addAddressToTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
+
+ final LinkProperties lp = lpCaptor.getValue();
+ assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses());
+ assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers());
+
+ final NetworkCapabilities nc = ncCaptor.getValue();
+ assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(nc.hasTransport(TRANSPORT_WIFI));
+ for (int cap : mConfig.getAllExposedCapabilities()) {
+ assertTrue(nc.hasCapability(cap));
+ }
+ }
+
+ @Test
public void testChildSessionClosedTriggersDisconnect() throws Exception {
getChildSessionCallback().onClosed();
mTestLooper.dispatchAll();
@@ -122,6 +180,4 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
verify(mIkeSession).close();
}
-
- // TODO: Add tests for childOpened() when ChildSessionConfiguration can be mocked or created
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
new file mode 100644
index 000000000000..3f2b47cd58fd
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.RetryTimeoutState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mGatewayConnection.transitionTo(mGatewayConnection.mRetryTimeoutState);
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void testNewNetworkTriggerRetry() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testSameNetworkDoesNotTriggerRetry() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testNullNetworkTriggersDisconnect() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testTimeoutElapsingTriggersRetry() throws Exception {
+ mTestLooper.moveTimeForward(mConfig.getRetryIntervalsMs()[0]);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 333b5b990dde..d449eab494f6 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -27,10 +27,13 @@ import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.InetAddresses;
import android.net.IpSecConfig;
import android.net.IpSecManager;
import android.net.IpSecTransform;
import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -44,15 +47,22 @@ import android.os.test.TestLooper;
import com.android.server.IpSecService;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
+import java.net.InetAddress;
import java.util.Collections;
import java.util.UUID;
public class VcnGatewayConnectionTestBase {
protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
+ protected static final InetAddress TEST_DNS_ADDR =
+ InetAddresses.parseNumericAddress("2001:DB8:0:1::");
+ protected static final LinkAddress TEST_INTERNAL_ADDR =
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:0:2::"), 64);
+
protected static final int TEST_IPSEC_SPI_VALUE = 0x1234;
protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1;
protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2;
@@ -86,6 +96,7 @@ public class VcnGatewayConnectionTestBase {
@NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
@NonNull protected final IpSecService mIpSecSvc;
+ @NonNull protected final ConnectivityManager mConnMgr;
protected VcnIkeSession mMockIkeSession;
protected VcnGatewayConnection mGatewayConnection;
@@ -103,6 +114,10 @@ public class VcnGatewayConnectionTestBase {
mIpSecSvc = mock(IpSecService.class);
setupIpSecManager(mContext, mIpSecSvc);
+ mConnMgr = mock(ConnectivityManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
doReturn(mContext).when(mVcnContext).getContext();
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
@@ -145,10 +160,10 @@ public class VcnGatewayConnectionTestBase {
return captor.getValue();
}
- protected ChildSessionCallback getChildSessionCallback() {
+ protected VcnChildSessionCallback getChildSessionCallback() {
ArgumentCaptor<ChildSessionCallback> captor =
ArgumentCaptor.forClass(ChildSessionCallback.class);
verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture());
- return captor.getValue();
+ return (VcnChildSessionCallback) captor.getValue();
}
}