summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PREUPLOAD.cfg2
-rw-r--r--api/test-current.txt3
-rw-r--r--cmds/statsd/Android.bp4
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp2
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h4
-rw-r--r--cmds/statsd/src/StatsService.cpp24
-rw-r--r--cmds/statsd/src/atoms.proto18
-rw-r--r--core/java/android/app/ActivityTaskManager.java20
-rw-r--r--core/java/android/app/ActivityThread.java79
-rw-r--r--core/java/android/app/ApplicationExitInfo.java2
-rw-r--r--core/java/android/app/ContextImpl.java39
-rw-r--r--core/java/android/app/Notification.java1
-rw-r--r--core/java/android/app/SystemServiceRegistry.java10
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneDetector.java2
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java4
-rw-r--r--core/java/android/content/ContextWrapper.java3
-rw-r--r--core/java/android/content/IntentFilter.java7
-rw-r--r--core/java/android/content/pm/PackageManager.java3
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java2
-rw-r--r--core/java/android/hardware/face/FaceManager.java2
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl2
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java2
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl2
-rw-r--r--core/java/android/inputmethodservice/InlineSuggestionSession.java5
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java3
-rw-r--r--core/java/android/net/MacAddress.java14
-rw-r--r--core/java/android/os/Binder.java8
-rw-r--r--core/java/android/os/HwBinder.java9
-rw-r--r--core/java/android/os/incremental/V4Signature.java2
-rw-r--r--core/java/android/os/storage/StorageManager.java6
-rw-r--r--core/java/android/provider/Telephony.java3
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java11
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java17
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java33
-rw-r--r--core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java37
-rw-r--r--core/java/android/util/apk/ApkSignatureVerifier.java20
-rw-r--r--core/java/android/util/apk/ApkSigningBlockUtils.java15
-rw-r--r--core/java/android/view/IDisplayWindowInsetsController.aidl7
-rw-r--r--core/java/android/view/IWindowManager.aidl10
-rw-r--r--core/java/android/view/ImeInsetsSourceConsumer.java12
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java3
-rw-r--r--core/java/android/view/View.java19
-rw-r--r--core/java/android/view/ViewRootImpl.java10
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java30
-rw-r--r--core/java/android/widget/EditorTouchState.java9
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java26
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java2
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java40
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java16
-rw-r--r--core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl3
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl3
-rw-r--r--core/jni/android_hardware_input_InputApplicationHandle.cpp4
-rw-r--r--core/jni/android_hardware_input_InputWindowHandle.cpp4
-rw-r--r--core/jni/android_os_HwBinder.cpp7
-rw-r--r--core/jni/android_os_HwParcel.cpp16
-rw-r--r--core/jni/android_util_Binder.cpp7
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp18
-rw-r--r--core/res/res/values-ar/strings.xml2
-rw-r--r--core/res/res/values-es/strings.xml2
-rw-r--r--core/res/res/values-eu/strings.xml2
-rw-r--r--core/res/res/values-gl/strings.xml2
-rw-r--r--core/res/res/values-hi/strings.xml2
-rw-r--r--core/res/res/values-ja/strings.xml2
-rw-r--r--core/res/res/values-kk/strings.xml2
-rw-r--r--core/res/res/values-ky/strings.xml6
-rw-r--r--core/res/res/values-ml/strings.xml2
-rw-r--r--core/res/res/values-uz/strings.xml2
-rw-r--r--core/res/res/values-vi/strings.xml2
-rw-r--r--core/res/res/values-zh-rTW/strings.xml10
-rw-r--r--core/res/res/values/config.xml15
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/content/ContextTest.java23
-rw-r--r--core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java40
-rw-r--r--core/tests/coretests/src/android/widget/EditorCursorDragTest.java6
-rw-r--r--core/tests/coretests/src/android/widget/EditorTouchStateTest.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java39
-rw-r--r--data/keyboards/Vendor_1532_Product_1007.kl65
-rw-r--r--data/keyboards/Vendor_1532_Product_100a.kl65
-rw-r--r--libs/input/PointerController.cpp120
-rw-r--r--libs/input/PointerController.h72
-rw-r--r--libs/input/tests/PointerController_test.cpp16
-rw-r--r--location/java/android/location/LocationManager.java7
-rw-r--r--media/java/android/media/MediaFrameworkInitializer.java74
-rw-r--r--media/java/android/media/MediaServiceManager.java68
-rw-r--r--media/java/android/media/session/MediaSessionManager.java9
-rw-r--r--media/jni/android_media_tv_Tuner.cpp2
-rw-r--r--media/tests/MediaTranscodingTest/build_and_run_unit_tests.sh10
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java42
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java182
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java1
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestUtil.java70
-rw-r--r--packages/CarSystemUI/Android.bp10
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java250
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java168
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java173
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java27
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java195
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java111
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java8
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java5
-rw-r--r--packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java22
-rw-r--r--packages/SettingsLib/Utils/AndroidManifest.xml2
-rw-r--r--packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java2
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java26
-rw-r--r--packages/SystemUI/Android.bp8
-rw-r--r--packages/SystemUI/docs/dagger.md20
-rw-r--r--packages/SystemUI/res/layout/qs_panel.xml1
-rw-r--r--packages/SystemUI/res/layout/udfps_view.xml2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java157
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozePauser.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeUi.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/BrightnessSensor.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/dagger/WrappedService.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java229
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/Assert.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java70
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java72
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt43
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java21
-rw-r--r--packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java11
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java7
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java32
-rw-r--r--services/backup/OWNERS5
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java131
-rw-r--r--services/core/java/com/android/server/VibratorService.java154
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java5
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java15
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java13
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java19
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java128
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java38
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/EnrollClient.java44
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java19
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java58
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java12
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/LockoutResetTracker.java122
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/RemovalClient.java29
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java20
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java15
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java21
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java22
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java36
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java26
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java27
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java24
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java71
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java21
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java17
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java16
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java35
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java24
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java26
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java80
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/GestureAvailabilityTracker.java50
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java30
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java9
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java42
-rw-r--r--services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java11
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java12
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java9
-rw-r--r--services/core/java/com/android/server/location/util/SystemAppOpsHelper.java22
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java2
-rw-r--r--services/core/java/com/android/server/media/AudioPlayerStateMonitor.java8
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java49
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java7
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java4
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java33
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java9
-rw-r--r--services/core/java/com/android/server/pm/OtaDexoptService.java11
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelper.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelperImpl.java31
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java68
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java24
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java15
-rw-r--r--services/core/java/com/android/server/rollback/AppDataRollbackHelper.java10
-rw-r--r--services/core/java/com/android/server/rollback/Rollback.java10
-rw-r--r--services/core/java/com/android/server/storage/StorageSessionController.java6
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java5
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java13
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java7
-rw-r--r--services/core/java/com/android/server/timezonedetector/ArrayMapWithHistory.java2
-rw-r--r--services/core/java/com/android/server/timezonedetector/Dumpable.java13
-rw-r--r--services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java3
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java2
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java2
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java9
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java14
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java9
-rw-r--r--services/core/java/com/android/server/uri/UriGrantsManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java7
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java18
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java126
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java100
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicy.java10
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java185
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java184
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java24
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java18
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java31
-rw-r--r--services/core/java/com/android/server/wm/InsetsControlTarget.java4
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java57
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java19
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java9
-rw-r--r--services/core/java/com/android/server/wm/RemoteAnimationController.java22
-rw-r--r--services/core/java/com/android/server/wm/RootDisplayArea.java17
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java494
-rw-r--r--services/core/java/com/android/server/wm/Task.java27
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java28
-rw-r--r--services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java5
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java145
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java26
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java17
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp86
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/util/SystemAppOpsHelperTest.java13
-rw-r--r--services/tests/servicestests/Android.bp1
-rw-r--r--services/tests/servicestests/AndroidManifest.xml3
-rw-r--r--services/tests/servicestests/src/com/android/server/VibratorServiceTest.java607
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanTests.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java (renamed from services/tests/servicestests/src/com/android/server/timezonedetector/StubbedTimeZoneDetectorStrategy.java)7
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java37
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java119
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java34
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java294
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java312
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java46
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java58
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java19
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java30
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java6
-rw-r--r--telephony/java/android/telephony/CellLocation.java24
-rw-r--r--telephony/java/android/telephony/SmsMessage.java22
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java67
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl23
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyIntents.java4
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java32
-rw-r--r--test-base/src/android/test/InstrumentationTestCase.java4
-rw-r--r--tests/RollbackTest/Android.bp9
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java26
-rw-r--r--tests/StagedInstallTest/Android.bp2
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java32
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java7
-rw-r--r--tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java (renamed from tests/RollbackTest/lib/src/com/android/tests/rollback/host/AbandonSessionsRule.java)0
-rw-r--r--tools/stats_log_api_gen/Collation.cpp53
-rw-r--r--tools/stats_log_api_gen/Collation.h10
-rw-r--r--tools/stats_log_api_gen/java_writer.cpp326
-rw-r--r--tools/stats_log_api_gen/test.proto41
-rw-r--r--tools/stats_log_api_gen/test_collation.cpp64
349 files changed, 7451 insertions, 3281 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 2fd2e33bbc37..9b290c6a4760 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -12,8 +12,6 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
services/incremental/
[Hook Scripts]
-checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
-
strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT}
hidden_api_txt_checksorted_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
diff --git a/api/test-current.txt b/api/test-current.txt
index 113d585164f6..ab0761374570 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -35,6 +35,7 @@ package android {
public static final class R.bool {
field public static final int config_assistantOnTopOfDream = 17891333; // 0x1110005
field public static final int config_perDisplayFocusEnabled = 17891332; // 0x1110004
+ field public static final int config_remoteInsetsControllerControlsSystemBars = 17891334; // 0x1110006
}
public static final class R.string {
@@ -144,6 +145,7 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void stopSystemLockTaskMode();
method public static boolean supportsMultiWindow(android.content.Context);
method public static boolean supportsSplitScreenMultiWindow(android.content.Context);
+ field public static final int DEFAULT_MINIMAL_SPLIT_SCREEN_DISPLAY_SIZE_DP = 440; // 0x1b8
field public static final int INVALID_STACK_ID = -1; // 0xffffffff
field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1
field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0
@@ -5002,7 +5004,6 @@ package android.util {
field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
- field public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 0617eb6c0e66..124f815f51f0 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -216,10 +216,6 @@ cc_binary {
// address: true,
//},
},
- debuggable: {
- // Add a flag to enable stats log printing from statsd on debug builds.
- cflags: ["-DVERY_VERBOSE_PRINTING"],
- },
},
proto: {
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index e7b32c56551a..05e9ec3a1769 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -409,11 +409,9 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs) {
onWatchdogRollbackOccurredLocked(event);
}
-#ifdef VERY_VERBOSE_PRINTING
if (mPrintAllLogs) {
ALOGI("%s", event->ToString().c_str());
}
-#endif
resetIfConfigTtlExpiredLocked(eventElapsedTimeNs);
// Hard-coded logic to update the isolated uid's in the uid-map.
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 23f2584655b0..c0f54a0995ac 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -139,10 +139,8 @@ public:
int64_t getLastReportTimeNs(const ConfigKey& key);
inline void setPrintLogs(bool enabled) {
-#ifdef VERY_VERBOSE_PRINTING
std::lock_guard<std::mutex> lock(mMetricsMutex);
mPrintAllLogs = enabled;
-#endif
}
// Add a specific config key to the possible configs to dump ASAP.
@@ -276,9 +274,7 @@ private:
//Last time we wrote metadata to disk.
int64_t mLastMetadataWriteNs = 0;
-#ifdef VERY_VERBOSE_PRINTING
bool mPrintAllLogs = false;
-#endif
FRIEND_TEST(StatsLogProcessorTest, TestOutOfOrderLogs);
FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 322648229d0e..d5e331495164 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -484,7 +484,8 @@ void StatsService::print_cmd_help(int out) {
dprintf(out, " Clear cached puller data.\n");
dprintf(out, "\n");
dprintf(out, "usage: adb shell cmd stats print-logs\n");
- dprintf(out, " Only works on eng build\n");
+ dprintf(out, " Requires root privileges.\n");
+ dprintf(out, " Can be disabled by calling adb shell cmd stats print-logs 0\n");
}
status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) {
@@ -865,18 +866,19 @@ status_t StatsService::cmd_clear_puller_cache(int out) {
}
status_t StatsService::cmd_print_logs(int out, const Vector<String8>& args) {
- VLOG("StatsService::cmd_print_logs with Pid %i, Uid %i", AIBinder_getCallingPid(),
- AIBinder_getCallingUid());
- if (checkPermission(kPermissionDump)) {
- bool enabled = true;
- if (args.size() >= 2) {
- enabled = atoi(args[1].c_str()) != 0;
- }
- mProcessor->setPrintLogs(enabled);
- return NO_ERROR;
- } else {
+ Status status = checkUid(AID_ROOT);
+ if (!status.isOk()) {
return PERMISSION_DENIED;
}
+
+ VLOG("StatsService::cmd_print_logs with pid %i, uid %i", AIBinder_getCallingPid(),
+ AIBinder_getCallingUid());
+ bool enabled = true;
+ if (args.size() >= 2) {
+ enabled = atoi(args[1].c_str()) != 0;
+ }
+ mProcessor->setPrintLogs(enabled);
+ return NO_ERROR;
}
bool StatsService::getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid) {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 8c54c242e04a..02c0d933b3cd 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -4590,7 +4590,7 @@ message GeneralExternalStorageAccessStats {
// Includes file path and ContentResolver accesses
optional uint32 secondary_storage_accesses = 4;
// Comma-separated list of mime types that were accessed.
- optional MimeTypes mime_types_accessed = 5;
+ optional MimeTypes mime_types_accessed = 5 [(log_mode) = MODE_BYTES];
}
/**
@@ -6174,7 +6174,7 @@ message ProcessStatsAvailablePagesProto {
* Pulled from ProcessStatsService.java
*/
message ProcStats {
- optional ProcessStatsSectionProto proc_stats_section = 1;
+ optional ProcessStatsSectionProto proc_stats_section = 1 [(log_mode) = MODE_BYTES];
// Data pulled from device into this is sometimes sharded across multiple atoms to work around
// a size limit. When this happens, this shard ID will contain an increasing 1-indexed integer
// with the number of this shard.
@@ -6185,7 +6185,7 @@ message ProcStats {
* Pulled from ProcessStatsService.java
*/
message ProcStatsPkgProc {
- optional ProcessStatsSectionProto proc_stats_section = 1;
+ optional ProcessStatsSectionProto proc_stats_section = 1 [(log_mode) = MODE_BYTES];
}
// Next Tag: 2
@@ -6203,7 +6203,7 @@ message NotificationRemoteViewsProto {
* Pulled from NotificationManagerService.java
*/
message NotificationRemoteViews {
- optional NotificationRemoteViewsProto notification_remote_views = 1;
+ optional NotificationRemoteViewsProto notification_remote_views = 1 [(log_mode) = MODE_BYTES];
}
/**
@@ -6271,7 +6271,7 @@ message DNDModeProto {
// May also be "MANUAL_RULE" to indicate app-activation of the manual rule.
optional string id = 5;
optional int32 uid = 6 [(is_uid) = true]; // currently only SYSTEM_UID or 0 for other
- optional DNDPolicyProto policy = 7;
+ optional DNDPolicyProto policy = 7 [(log_mode) = MODE_BYTES];
}
/**
@@ -6436,7 +6436,7 @@ message PowerProfileProto {
* Pulled from PowerProfile.java
*/
message PowerProfile {
- optional PowerProfileProto power_profile = 1;
+ optional PowerProfileProto power_profile = 1 [(log_mode) = MODE_BYTES];
}
/**
@@ -8131,7 +8131,7 @@ message DeviceIdentifierAccessDenied {
message TrainInfo {
optional int64 train_version_code = 1;
- optional TrainExperimentIds train_experiment_id = 2;
+ optional TrainExperimentIds train_experiment_id = 2 [(log_mode) = MODE_BYTES];
optional string train_name = 3;
@@ -11179,8 +11179,8 @@ message BlobInfo {
optional int64 expiry_timestamp_millis = 3;
// List of committers of this Blob
- optional BlobCommitterListProto committers = 4;
+ optional BlobCommitterListProto committers = 4 [(log_mode) = MODE_BYTES];
// List of leasees of this Blob
- optional BlobLeaseeListProto leasees = 5;
+ optional BlobLeaseeListProto leasees = 5 [(log_mode) = MODE_BYTES];
}
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index 0f31529451fb..4283d7ad2a62 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -31,6 +31,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.DisplayMetrics;
import android.util.Singleton;
import java.util.List;
@@ -139,6 +140,8 @@ public class ActivityTaskManager {
public static final String EXTRA_IGNORE_TARGET_SECURITY =
"android.app.extra.EXTRA_IGNORE_TARGET_SECURITY";
+ /** The minimal size of a display's long-edge needed to support split-screen multi-window. */
+ public static final int DEFAULT_MINIMAL_SPLIT_SCREEN_DISPLAY_SIZE_DP = 440;
private static int sMaxRecentTasks = -1;
@@ -282,8 +285,23 @@ public class ActivityTaskManager {
com.android.internal.R.bool.config_supportsMultiWindow);
}
- /** Returns true if the system supports split screen multi-window. */
+ /**
+ * Returns {@code true} if the display the context is associated with supports split screen
+ * multi-window.
+ *
+ * @throws UnsupportedOperationException if the supplied {@link Context} is not associated with
+ * a display.
+ */
public static boolean supportsSplitScreenMultiWindow(Context context) {
+ DisplayMetrics dm = new DisplayMetrics();
+ context.getDisplay().getRealMetrics(dm);
+
+ int widthDp = (int) (dm.widthPixels / dm.density);
+ int heightDp = (int) (dm.heightPixels / dm.density);
+ if (Math.max(widthDp, heightDp) < DEFAULT_MINIMAL_SPLIT_SCREEN_DISPLAY_SIZE_DP) {
+ return false;
+ }
+
return supportsMultiWindow(context)
&& Resources.getSystem().getBoolean(
com.android.internal.R.bool.config_supportsSplitScreenMultiWindow);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 89e1f5a28a35..9b13d256aea6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -86,6 +86,8 @@ import android.graphics.Canvas;
import android.graphics.HardwareRenderer;
import android.hardware.display.DisplayManagerGlobal;
import android.inputmethodservice.InputMethodService;
+import android.media.MediaFrameworkInitializer;
+import android.media.MediaServiceManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.Proxy;
@@ -269,9 +271,6 @@ public final class ActivityThread extends ClientTransactionHandler {
/** Type for IActivityManager.serviceDoneExecuting: done stopping (destroying) service */
public static final int SERVICE_DONE_EXECUTING_STOP = 2;
- // Whether to invoke an activity callback after delivering new configuration.
- private static final boolean REPORT_TO_ACTIVITY = true;
-
/** Use foreground GC policy (less pause time) and higher JIT weight. */
private static final int VM_PROCESS_STATE_JANK_PERCEPTIBLE = 0;
/** Use background GC policy and default JIT threshold. */
@@ -4971,7 +4970,8 @@ public final class ActivityThread extends ClientTransactionHandler {
private void relaunchAllActivities(boolean preserveWindows) {
for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
final ActivityClientRecord r = entry.getValue();
- if (!r.activity.mFinished) {
+ // Schedule relaunch the activity if it is not a local object or finishing.
+ if (!r.activity.mFinished && !(r.token instanceof Binder)) {
if (preserveWindows && r.window != null) {
r.mPreserveWindow = true;
}
@@ -5537,18 +5537,14 @@ public final class ActivityThread extends ClientTransactionHandler {
}
/**
- * Updates the configuration for an Activity. The ActivityClientRecord's
- * {@link ActivityClientRecord#overrideConfig} is used to compute the final Configuration for
- * that Activity. {@link ActivityClientRecord#tmpConfig} is used as a temporary for delivering
- * the updated Configuration.
- * @param r ActivityClientRecord representing the Activity.
- * @param newBaseConfig The new configuration to use. This may be augmented with
- * {@link ActivityClientRecord#overrideConfig}.
+ * Updates the configuration for an Activity in its current display.
+ *
+ * @see #performConfigurationChangedForActivity(ActivityClientRecord, Configuration, int,
+ * boolean)
*/
private void performConfigurationChangedForActivity(ActivityClientRecord r,
Configuration newBaseConfig) {
- performConfigurationChangedForActivity(r, newBaseConfig, r.activity.getDisplayId(),
- false /* movedToDifferentDisplay */);
+ performConfigurationChangedForActivity(r, newBaseConfig, r.activity.getDisplayId());
}
/**
@@ -5560,17 +5556,16 @@ public final class ActivityThread extends ClientTransactionHandler {
* @param newBaseConfig The new configuration to use. This may be augmented with
* {@link ActivityClientRecord#overrideConfig}.
* @param displayId The id of the display where the Activity currently resides.
- * @param movedToDifferentDisplay Indicates if the activity was moved to different display.
* @return {@link Configuration} instance sent to client, null if not sent.
*/
private Configuration performConfigurationChangedForActivity(ActivityClientRecord r,
- Configuration newBaseConfig, int displayId, boolean movedToDifferentDisplay) {
+ Configuration newBaseConfig, int displayId) {
r.tmpConfig.setTo(newBaseConfig);
if (r.overrideConfig != null) {
r.tmpConfig.updateFrom(r.overrideConfig);
}
final Configuration reportedConfig = performActivityConfigurationChanged(r.activity,
- r.tmpConfig, r.overrideConfig, displayId, movedToDifferentDisplay);
+ r.tmpConfig, r.overrideConfig, displayId);
freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
return reportedConfig;
}
@@ -5597,10 +5592,6 @@ public final class ActivityThread extends ClientTransactionHandler {
* @param newConfig The new configuration.
*/
private void performConfigurationChanged(ComponentCallbacks2 cb, Configuration newConfig) {
- if (!REPORT_TO_ACTIVITY) {
- return;
- }
-
// ContextThemeWrappers may override the configuration for that context. We must check and
// apply any overrides defined.
Configuration contextThemeWrapperOverrideConfig = null;
@@ -5625,12 +5616,10 @@ public final class ActivityThread extends ClientTransactionHandler {
* from the base global configuration. This is supplied by
* ActivityManager.
* @param displayId Id of the display where activity currently resides.
- * @param movedToDifferentDisplay Indicates if the activity was moved to different display.
* @return Configuration sent to client, null if no changes and not moved to different display.
*/
private Configuration performActivityConfigurationChanged(Activity activity,
- Configuration newConfig, Configuration amOverrideConfig, int displayId,
- boolean movedToDifferentDisplay) {
+ Configuration newConfig, Configuration amOverrideConfig, int displayId) {
if (activity == null) {
throw new IllegalArgumentException("No activity provided.");
}
@@ -5643,6 +5632,7 @@ public final class ActivityThread extends ClientTransactionHandler {
// callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition
handleWindowingModeChangeIfNeeded(activity, newConfig);
+ final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId);
boolean shouldReportChange = false;
if (activity.mCurrentConfig == null) {
shouldReportChange = true;
@@ -5656,8 +5646,7 @@ public final class ActivityThread extends ClientTransactionHandler {
amOverrideConfig)) {
// Nothing significant, don't proceed with updating and reporting.
return null;
- } else if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0
- || !REPORT_TO_ACTIVITY) {
+ } else if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {
// If this activity doesn't handle any of the config changes, then don't bother
// calling onConfigurationChanged. Otherwise, report to the activity for the
// changes.
@@ -5691,11 +5680,6 @@ public final class ActivityThread extends ClientTransactionHandler {
final Configuration configToReport = createNewConfigAndUpdateIfNotNull(newConfig,
contextThemeWrapperOverrideConfig);
- if (!REPORT_TO_ACTIVITY) {
- // Not configured to report to activity.
- return configToReport;
- }
-
if (movedToDifferentDisplay) {
activity.dispatchMovedToDisplay(displayId, configToReport);
}
@@ -5988,8 +5972,6 @@ public final class ActivityThread extends ClientTransactionHandler {
if (DEBUG_CONFIGURATION) Slog.w(TAG, "Not found target activity to report to: " + r);
return;
}
- final boolean movedToDifferentDisplay = displayId != INVALID_DISPLAY
- && displayId != r.activity.getDisplayId();
synchronized (r) {
if (overrideConfig.isOtherSeqNewer(r.mPendingOverrideConfig)) {
@@ -6003,6 +5985,7 @@ public final class ActivityThread extends ClientTransactionHandler {
r.mPendingOverrideConfig = null;
}
+ final boolean movedToDifferentDisplay = isDifferentDisplay(r.activity, displayId);
if (r.overrideConfig != null && !r.overrideConfig.isOtherSeqNewer(overrideConfig)
&& !movedToDifferentDisplay) {
if (DEBUG_CONFIGURATION) {
@@ -6018,29 +6001,34 @@ public final class ActivityThread extends ClientTransactionHandler {
final ViewRootImpl viewRoot = r.activity.mDecor != null
? r.activity.mDecor.getViewRootImpl() : null;
- if (movedToDifferentDisplay) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity moved to display, activity:"
- + r.activityInfo.name + ", displayId=" + displayId
+ if (DEBUG_CONFIGURATION) {
+ Slog.v(TAG, "Handle activity config changed, activity:"
+ + r.activityInfo.name + ", displayId=" + r.activity.getDisplayId()
+ + (movedToDifferentDisplay ? (", newDisplayId=" + displayId) : "")
+ ", config=" + overrideConfig);
-
- final Configuration reportedConfig = performConfigurationChangedForActivity(r,
- mCompatConfiguration, displayId, true /* movedToDifferentDisplay */);
- if (viewRoot != null) {
- viewRoot.onMovedToDisplay(displayId, reportedConfig);
- }
- } else {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
- + r.activityInfo.name + ", config=" + overrideConfig);
- performConfigurationChangedForActivity(r, mCompatConfiguration);
}
+ final Configuration reportedConfig = performConfigurationChangedForActivity(r,
+ mCompatConfiguration,
+ movedToDifferentDisplay ? displayId : r.activity.getDisplayId());
// Notify the ViewRootImpl instance about configuration changes. It may have initiated this
// update to make sure that resources are updated before updating itself.
if (viewRoot != null) {
+ if (movedToDifferentDisplay) {
+ viewRoot.onMovedToDisplay(displayId, reportedConfig);
+ }
viewRoot.updateConfiguration(displayId);
}
mSomeActivitiesChanged = true;
}
+ /**
+ * Checks if the display id of activity is different from the given one. Note that
+ * {@link #INVALID_DISPLAY} means no difference.
+ */
+ private static boolean isDifferentDisplay(@NonNull Activity activity, int displayId) {
+ return displayId != INVALID_DISPLAY && displayId != activity.getDisplayId();
+ }
+
final void handleProfilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) {
if (start) {
try {
@@ -7665,6 +7653,7 @@ public final class ActivityThread extends ClientTransactionHandler {
public static void initializeMainlineModules() {
TelephonyFrameworkInitializer.setTelephonyServiceManager(new TelephonyServiceManager());
StatsFrameworkInitializer.setStatsServiceManager(new StatsServiceManager());
+ MediaFrameworkInitializer.setMediaServiceManager(new MediaServiceManager());
}
private void purgePendingResources() {
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index cfe0aff05d4a..e7b3e14bfda7 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -502,7 +502,7 @@ public final class ApplicationExitInfo implements Parcelable {
* Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
* {@link #getPackageUid}, if an external service has the
* {@link android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set
- * to <code>true<code> and was bound with the flag
+ * to <code>true</code> and was bound with the flag
* {@link android.content.Context#BIND_EXTERNAL_SERVICE} - in this case, this field here will
* be the kernel user identifier of the external service provider.
*/
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9849e590c06b..9613e58fb943 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1900,26 +1900,31 @@ class ContextImpl extends Context {
@Override
public Object getSystemService(String name) {
- // We may override this API from outer context.
- final boolean isUiContext = isUiContext() || getOuterContext().isUiContext();
- // Check incorrect Context usage.
- if (isUiComponent(name) && !isUiContext && vmIncorrectContextUseEnabled()) {
- final String errorMessage = "Tried to access visual service "
- + SystemServiceRegistry.getSystemServiceClassName(name)
- + " from a non-visual Context:" + getOuterContext();
- final String message = "Visual services, such as WindowManager, WallpaperService or "
- + "LayoutInflater should be accessed from Activity or other visual Context. "
- + "Use an Activity or a Context created with "
- + "Context#createWindowContext(int, Bundle), which are adjusted to the "
- + "configuration and visual bounds of an area on screen.";
- final Exception exception = new IllegalAccessException(errorMessage);
- StrictMode.onIncorrectContextUsed(message, exception);
- Log.e(TAG, errorMessage + message, exception);
+ if (vmIncorrectContextUseEnabled()) {
+ // We may override this API from outer context.
+ final boolean isUiContext = isUiContext() || isOuterUiContext();
+ // Check incorrect Context usage.
+ if (isUiComponent(name) && !isUiContext) {
+ final String errorMessage = "Tried to access visual service "
+ + SystemServiceRegistry.getSystemServiceClassName(name)
+ + " from a non-visual Context:" + getOuterContext();
+ final String message = "Visual services, such as WindowManager, WallpaperService "
+ + "or LayoutInflater should be accessed from Activity or other visual "
+ + "Context. Use an Activity or a Context created with "
+ + "Context#createWindowContext(int, Bundle), which are adjusted to "
+ + "the configuration and visual bounds of an area on screen.";
+ final Exception exception = new IllegalAccessException(errorMessage);
+ StrictMode.onIncorrectContextUsed(message, exception);
+ Log.e(TAG, errorMessage + " " + message, exception);
+ }
}
-
return SystemServiceRegistry.getSystemService(this, name);
}
+ private boolean isOuterUiContext() {
+ return getOuterContext() != null && getOuterContext().isUiContext();
+ }
+
@Override
public String getSystemServiceName(Class<?> serviceClass) {
return SystemServiceRegistry.getSystemServiceName(serviceClass);
@@ -2372,7 +2377,7 @@ class ContextImpl extends Context {
context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(),
mResources.getLoaders()));
- context.mIsUiContext = isUiContext() || getOuterContext().isUiContext();
+ context.mIsUiContext = isUiContext() || isOuterUiContext();
return context;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3410c92a61c4..f82ab7bcfc08 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4801,7 +4801,6 @@ public class Notification implements Parcelable
contentView.setViewVisibility(R.id.time, View.GONE);
contentView.setImageViewIcon(R.id.profile_badge, null);
contentView.setViewVisibility(R.id.profile_badge, View.GONE);
- contentView.setViewVisibility(R.id.alerted_icon, View.GONE);
mN.mUsesStandardHeader = false;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index c20c11fea1e4..59997ccab687 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -101,11 +101,11 @@ import android.location.ICountryDetector;
import android.location.ILocationManager;
import android.location.LocationManager;
import android.media.AudioManager;
+import android.media.MediaFrameworkInitializer;
import android.media.MediaRouter;
import android.media.midi.IMidiManager;
import android.media.midi.MidiManager;
import android.media.projection.MediaProjectionManager;
-import android.media.session.MediaSessionManager;
import android.media.soundtrigger.SoundTriggerManager;
import android.media.tv.ITvInputManager;
import android.media.tv.TvInputManager;
@@ -855,13 +855,6 @@ public final class SystemServiceRegistry {
return new ConsumerIrManager(ctx);
}});
- registerService(Context.MEDIA_SESSION_SERVICE, MediaSessionManager.class,
- new CachedServiceFetcher<MediaSessionManager>() {
- @Override
- public MediaSessionManager createService(ContextImpl ctx) {
- return new MediaSessionManager(ctx);
- }});
-
registerService(Context.TRUST_SERVICE, TrustManager.class,
new StaticServiceFetcher<TrustManager>() {
@Override
@@ -1335,6 +1328,7 @@ public final class SystemServiceRegistry {
WifiFrameworkInitializer.registerServiceWrappers();
StatsFrameworkInitializer.registerServiceWrappers();
RollbackManagerFrameworkInitializer.initialize();
+ MediaFrameworkInitializer.registerServiceWrappers();
} finally {
// If any of the above code throws, we're in a pretty bad shape and the process
// will likely crash, but we'll reset it just in case there's an exception handler...
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index 786acba94ef4..621ef526aacf 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -29,7 +29,7 @@ import android.content.Context;
@SystemService(Context.TIME_ZONE_DETECTOR_SERVICE)
public interface TimeZoneDetector {
- /**
+ /**
* Returns the current user's time zone capabilities. See {@link TimeZoneCapabilities}.
*/
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 8c3268c6fc14..d2a774bcb168 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1812,6 +1812,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
+ if (DBG) Log.d(TAG, "removeActiveDevice, profiles: " + profiles);
return mService.removeActiveDevice(profiles);
}
} catch (RemoteException e) {
@@ -1856,6 +1857,9 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
+ if (DBG) {
+ Log.d(TAG, "setActiveDevice, device: " + device + ", profiles: " + profiles);
+ }
return mService.setActiveDevice(device, profiles);
}
} catch (RemoteException e) {
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 565f34a149bd..5fe094d082ae 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1153,6 +1153,9 @@ public class ContextWrapper extends Context {
*/
@Override
public boolean isUiContext() {
+ if (mBase == null) {
+ return false;
+ }
return mBase.isUiContext();
}
}
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 79da1f6ab282..ee9bd3d259fb 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -1168,7 +1168,12 @@ public class IntentFilter implements Parcelable {
public int match(Uri data, boolean wildcardSupported) {
String host = data.getHost();
if (host == null) {
- return NO_MATCH_DATA;
+ if (wildcardSupported && mWild) {
+ // special case, if no host is provided, but the Authority is wildcard, match
+ return MATCH_CATEGORY_HOST;
+ } else {
+ return NO_MATCH_DATA;
+ }
}
if (false) Log.v("IntentFilter",
"Match host " + host + ": " + mHost);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 940bf26621e5..f533760de84d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4673,8 +4673,7 @@ public abstract class PackageManager {
* Marks an application exempt from having its permissions be automatically revoked when
* the app is unused for an extended period of time.
*
- * Only the installer on record that installed the given package, or a holder of
- * {@code WHITELIST_AUTO_REVOKE_PERMISSIONS} is allowed to call this.
+ * Only the installer on record that installed the given package is allowed to call this.
*
* Packages start in whitelisted state, and it is the installer's responsibility to
* un-whitelist the packages it installs, unless auto-revoking permissions from that package
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 431c5d7310f1..3688f1bda979 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -1510,7 +1510,7 @@ public class ParsingPackageUtils {
Uri data = null;
String dataType = null;
- String host = IntentFilter.WILDCARD;
+ String host = null;
final int numActions = intentInfo.countActions();
final int numSchemes = intentInfo.countDataSchemes();
final int numTypes = intentInfo.countDataTypes();
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 58cb1e135350..c7fc2ad9b29a 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -610,7 +610,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
serverCallback.sendResult(null /* data */);
}
}
- });
+ }, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index f4122fe7c625..2f8c97f8022d 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -90,7 +90,7 @@ interface IFaceService {
void resetLockout(int userId, in byte [] hardwareAuthToken);
// Add a callback which gets notified when the face lockout period expired.
- void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback);
+ void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback, String opPackageName);
void setFeature(IBinder token, int userId, int feature, boolean enabled,
in byte [] hardwareAuthToken, IFaceServiceReceiver receiver, String opPackageName);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index abe63d65102c..9dacca769229 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -768,7 +768,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
serverCallback.sendResult(null /* data */);
}
}
- });
+ }, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 5adba7595ef9..ad58fea4281c 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -94,7 +94,7 @@ interface IFingerprintService {
void resetLockout(int userId, in byte [] hardwareAuthToken);
// Add a callback which gets notified when the fingerprint lockout period expired.
- void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback);
+ void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback, String opPackageName);
// Check if a client request is currently being handled
boolean isClientActive();
diff --git a/core/java/android/inputmethodservice/InlineSuggestionSession.java b/core/java/android/inputmethodservice/InlineSuggestionSession.java
index 509cbe09df69..90d0ff0a5026 100644
--- a/core/java/android/inputmethodservice/InlineSuggestionSession.java
+++ b/core/java/android/inputmethodservice/InlineSuggestionSession.java
@@ -149,6 +149,11 @@ class InlineSuggestionSession {
*/
@MainThread
void invalidate() {
+ try {
+ mCallback.onInlineSuggestionsSessionInvalidated();
+ } catch (RemoteException e) {
+ Log.w(TAG, "onInlineSuggestionsSessionInvalidated() remote exception:" + e);
+ }
if (mResponseCallback != null) {
consumeInlineSuggestionsResponse(EMPTY_RESPONSE);
mResponseCallback.invalidate();
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 5647bf90d2fb..c5a11abe1136 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -605,9 +605,6 @@ public class InputMethodService extends AbstractInputMethodService {
if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
+ " ic=" + mInputConnection);
// Unbind input is per process per display.
- // TODO(b/150902448): free-up IME surface when target is changing.
- // e.g. DisplayContent#setInputMethodTarget()
- removeImeSurface();
onUnbindInput();
mInputBinding = null;
mInputConnection = null;
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 0e10c42e61db..0eb3c1e8ad01 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -38,7 +38,9 @@ import java.util.Arrays;
* Representation of a MAC address.
*
* This class only supports 48 bits long addresses and does not support 64 bits long addresses.
- * Instances of this class are immutable.
+ * Instances of this class are immutable. This class provides implementations of hashCode()
+ * and equals() that make it suitable for use as keys in standard implementations of
+ * {@link java.util.Map}.
*/
public final class MacAddress implements Parcelable {
@@ -122,12 +124,22 @@ public final class MacAddress implements Parcelable {
}
/**
+ * Convert this MacAddress to a byte array.
+ *
+ * The returned array is in network order. For example, if this MacAddress is 1:2:3:4:5:6,
+ * the returned array is [1, 2, 3, 4, 5, 6].
+ *
* @return a byte array representation of this MacAddress.
*/
public @NonNull byte[] toByteArray() {
return byteAddrFromLongAddr(mAddr);
}
+ /**
+ * Returns a human-readable representation of this MacAddress.
+ * The exact format is implementation-dependent and should not be assumed to have any
+ * particular format.
+ */
@Override
public @NonNull String toString() {
return stringAddrFromLongAddr(mAddr);
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ea7462bd9113..a0207c8497c8 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -122,6 +122,14 @@ public class Binder implements IBinder {
private static native long getNativeFinalizer();
+ /**
+ * Returns the TID (task ID) for the current thread. Same as {@link Thread#getNativeTid()}
+ *
+ * @hide
+ */
+ @CriticalNative
+ public static native int getNativeTid();
+
// Use a Holder to allow static initialization of Binder in the boot image, and
// possibly to avoid some initialization ordering issues.
private static class NoImagePreloadHolder {
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 7c42c36e7747..64ab1d711765 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -96,6 +96,15 @@ public abstract class HwBinder implements IHwBinder {
throws RemoteException, NoSuchElementException;
/**
+ * This allows getService to bypass the VINTF manifest for testing only.
+ *
+ * Disabled on user builds.
+ * @hide
+ */
+ public static native final void setTrebleTestingOverride(
+ boolean testingOverride);
+
+ /**
* Configures how many threads the process-wide hwbinder threadpool
* has to process incoming requests.
*
diff --git a/core/java/android/os/incremental/V4Signature.java b/core/java/android/os/incremental/V4Signature.java
index d35ce5b2c3f8..32c80e7069da 100644
--- a/core/java/android/os/incremental/V4Signature.java
+++ b/core/java/android/os/incremental/V4Signature.java
@@ -159,7 +159,7 @@ public class V4Signature {
*
* @param fileSize - size of the signed file (APK)
*/
- public static byte[] getSigningData(long fileSize, HashingInfo hashingInfo,
+ public static byte[] getSignedData(long fileSize, HashingInfo hashingInfo,
SigningInfo signingInfo) {
final int size =
4/*size*/ + 8/*fileSize*/ + 4/*hash_algorithm*/ + 1/*log2_blocksize*/ + bytesSize(
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 0abf8ae352af..6b5eb16d7bff 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -86,7 +86,6 @@ import android.system.Os;
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.DataUnit;
-import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -161,11 +160,6 @@ public class StorageManager {
/** {@hide} */
public static final String PROP_ISOLATED_STORAGE_SNAPSHOT = "sys.isolated_storage_snapshot";
/** {@hide} */
- public static final String PROP_FUSE = "persist.sys.fuse";
- /** {@hide} */
- public static final String PROP_SETTINGS_FUSE = FeatureFlagUtils.PERSIST_PREFIX
- + FeatureFlagUtils.SETTINGS_FUSE_FLAG;
- /** {@hide} */
public static final String PROP_FORCED_SCOPED_STORAGE_WHITELIST =
"forced_scoped_storage_whitelist";
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 4c9afcf5cd05..fae26cf77c16 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3946,8 +3946,7 @@ public final class Telephony {
/**
* The APN set id. When the user manually selects an APN or the framework sets an APN as
- * preferred, all APNs with the same set id as the selected APN should be prioritized over
- * APNs in other sets.
+ * preferred, the device can only use APNs with the same set id as the selected APN.
* <p>Type: INTEGER</p>
* @hide
*/
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 2677087a4c39..5d34c476a4a6 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1938,6 +1938,17 @@ public abstract class NotificationListenerService extends Service {
/**
* @hide
*/
+ public @NonNull Ranking withAudiblyAlertedInfo(@Nullable Ranking previous) {
+ if (previous != null && previous.mLastAudiblyAlertedMs > 0
+ && this.mLastAudiblyAlertedMs <= 0) {
+ this.mLastAudiblyAlertedMs = previous.mLastAudiblyAlertedMs;
+ }
+ return this;
+ }
+
+ /**
+ * @hide
+ */
public void populate(Ranking other) {
populate(other.mKey,
other.mRank,
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 537498c44d5e..e338fd977f27 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -41,7 +41,6 @@ public class FeatureFlagUtils {
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
- public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
/** @hide */
public static final String SETTINGS_DO_NOT_RESTORE_PRESERVED =
"settings_do_not_restore_preserved";
@@ -52,7 +51,6 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS = new HashMap<>();
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
- DEFAULT_FLAGS.put(SETTINGS_FUSE_FLAG, "true");
DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false");
DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 346fe293d7ae..6e34666aea84 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -24,7 +24,6 @@ import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmContent
import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorithm;
-import static android.util.apk.ApkSigningBlockUtils.pickBestDigestForV4;
import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
import android.util.ArrayMap;
@@ -213,11 +212,9 @@ public class ApkSignatureSchemeV2Verifier {
verityDigest, apk.length(), signatureInfo);
}
- byte[] digest = pickBestDigestForV4(contentDigests);
-
return new VerifiedSigner(
signerCerts.toArray(new X509Certificate[signerCerts.size()][]),
- verityRootHash, digest);
+ verityRootHash, contentDigests);
}
private static X509Certificate[] verifySigner(
@@ -339,8 +336,7 @@ public class ApkSignatureSchemeV2Verifier {
} catch (CertificateException e) {
throw new SecurityException("Failed to decode certificate #" + certificateCount, e);
}
- certificate = new VerbatimX509Certificate(
- certificate, encodedCert);
+ certificate = new VerbatimX509Certificate(certificate, encodedCert);
certs.add(certificate);
}
@@ -434,12 +430,15 @@ public class ApkSignatureSchemeV2Verifier {
public final X509Certificate[][] certs;
public final byte[] verityRootHash;
- public final byte[] digest;
+ // Algorithm -> digest map of signed digests in the signature.
+ // All these are verified if requested.
+ public final Map<Integer, byte[]> contentDigests;
- public VerifiedSigner(X509Certificate[][] certs, byte[] verityRootHash, byte[] digest) {
+ public VerifiedSigner(X509Certificate[][] certs, byte[] verityRootHash,
+ Map<Integer, byte[]> contentDigests) {
this.certs = certs;
this.verityRootHash = verityRootHash;
- this.digest = digest;
+ this.contentDigests = contentDigests;
}
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 4ab541b616ed..93572857796c 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -24,7 +24,6 @@ import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmContent
import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorithm;
-import static android.util.apk.ApkSigningBlockUtils.pickBestDigestForV4;
import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
import android.os.Build;
@@ -161,7 +160,7 @@ public class ApkSignatureSchemeV3Verifier {
boolean doVerifyIntegrity) throws SecurityException, IOException {
int signerCount = 0;
Map<Integer, byte[]> contentDigests = new ArrayMap<>();
- VerifiedSigner result = null;
+ Pair<X509Certificate[], VerifiedProofOfRotation> result = null;
CertificateFactory certFactory;
try {
certFactory = CertificateFactory.getInstance("X.509");
@@ -206,18 +205,17 @@ public class ApkSignatureSchemeV3Verifier {
ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo);
}
+ byte[] verityRootHash = null;
if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) {
byte[] verityDigest = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256);
- result.verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength(
+ verityRootHash = ApkSigningBlockUtils.parseVerityDigestAndVerifySourceLength(
verityDigest, apk.length(), signatureInfo);
}
- result.digest = pickBestDigestForV4(contentDigests);
-
- return result;
+ return new VerifiedSigner(result.first, result.second, verityRootHash, contentDigests);
}
- private static VerifiedSigner verifySigner(
+ private static Pair<X509Certificate[], VerifiedProofOfRotation> verifySigner(
ByteBuffer signerBlock,
Map<Integer, byte[]> contentDigests,
CertificateFactory certFactory)
@@ -349,8 +347,7 @@ public class ApkSignatureSchemeV3Verifier {
} catch (CertificateException e) {
throw new SecurityException("Failed to decode certificate #" + certificateCount, e);
}
- certificate = new VerbatimX509Certificate(
- certificate, encodedCert);
+ certificate = new VerbatimX509Certificate(certificate, encodedCert);
certs.add(certificate);
}
@@ -382,8 +379,9 @@ public class ApkSignatureSchemeV3Verifier {
private static final int PROOF_OF_ROTATION_ATTR_ID = 0x3ba06f8c;
- private static VerifiedSigner verifyAdditionalAttributes(ByteBuffer attrs,
- List<X509Certificate> certs, CertificateFactory certFactory) throws IOException {
+ private static Pair<X509Certificate[], VerifiedProofOfRotation> verifyAdditionalAttributes(
+ ByteBuffer attrs, List<X509Certificate> certs, CertificateFactory certFactory)
+ throws IOException {
X509Certificate[] certChain = certs.toArray(new X509Certificate[certs.size()]);
VerifiedProofOfRotation por = null;
@@ -421,7 +419,7 @@ public class ApkSignatureSchemeV3Verifier {
break;
}
}
- return new VerifiedSigner(certChain, por);
+ return Pair.create(certChain, por);
}
private static VerifiedProofOfRotation verifyProofOfRotationStruct(
@@ -570,12 +568,17 @@ public class ApkSignatureSchemeV3Verifier {
public final X509Certificate[] certs;
public final VerifiedProofOfRotation por;
- public byte[] verityRootHash;
- public byte[] digest;
+ public final byte[] verityRootHash;
+ // Algorithm -> digest map of signed digests in the signature.
+ // All these are verified if requested.
+ public final Map<Integer, byte[]> contentDigests;
- public VerifiedSigner(X509Certificate[] certs, VerifiedProofOfRotation por) {
+ public VerifiedSigner(X509Certificate[] certs, VerifiedProofOfRotation por,
+ byte[] verityRootHash, Map<Integer, byte[]> contentDigests) {
this.certs = certs;
this.por = por;
+ this.verityRootHash = verityRootHash;
+ this.contentDigests = contentDigests;
}
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
index d40efce0b3b3..844816c0d903 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
@@ -16,12 +16,14 @@
package android.util.apk;
+import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorithm;
import android.os.incremental.IncrementalManager;
import android.os.incremental.V4Signature;
+import android.util.ArrayMap;
import android.util.Pair;
import java.io.ByteArrayInputStream;
@@ -42,6 +44,7 @@ import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
+import java.util.Map;
/**
* APK Signature Scheme v4 verifier.
@@ -79,13 +82,20 @@ public class ApkSignatureSchemeV4Verifier {
throw new SignatureNotFoundException("Failed to read V4 signature.", e);
}
- final byte[] signedData = V4Signature.getSigningData(apk.length(), hashingInfo,
+ // Verify signed data and extract certificates and apk digest.
+ final byte[] signedData = V4Signature.getSignedData(apk.length(), hashingInfo,
signingInfo);
+ final Pair<Certificate, byte[]> result = verifySigner(signingInfo, signedData);
- return verifySigner(signingInfo, signedData);
+ // Populate digests enforced by IncFS driver.
+ Map<Integer, byte[]> contentDigests = new ArrayMap<>();
+ contentDigests.put(convertToContentDigestType(hashingInfo.hashAlgorithm),
+ hashingInfo.rawRootHash);
+
+ return new VerifiedSigner(new Certificate[]{result.first}, result.second, contentDigests);
}
- private static VerifiedSigner verifySigner(V4Signature.SigningInfo signingInfo,
+ private static Pair<Certificate, byte[]> verifySigner(V4Signature.SigningInfo signingInfo,
final byte[] signedData) throws SecurityException {
if (!isSupportedSignatureAlgorithm(signingInfo.signatureAlgorithmId)) {
throw new SecurityException("No supported signatures found");
@@ -145,21 +155,34 @@ public class ApkSignatureSchemeV4Verifier {
"Public key mismatch between certificate and signature record");
}
- return new VerifiedSigner(new Certificate[]{certificate}, signingInfo.apkDigest);
+ return Pair.create(certificate, signingInfo.apkDigest);
+ }
+
+ private static int convertToContentDigestType(int hashAlgorithm) throws SecurityException {
+ if (hashAlgorithm == V4Signature.HASHING_ALGORITHM_SHA256) {
+ return CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
+ }
+ throw new SecurityException("Unsupported hashAlgorithm: " + hashAlgorithm);
}
/**
- * Verified APK Signature Scheme v4 signer, including V3 digest.
+ * Verified APK Signature Scheme v4 signer, including V2/V3 digest.
*
* @hide for internal use only.
*/
public static class VerifiedSigner {
public final Certificate[] certs;
- public byte[] apkDigest;
+ public final byte[] apkDigest;
+
+ // Algorithm -> digest map of signed digests in the signature.
+ // These are continuously enforced by the IncFS driver.
+ public final Map<Integer, byte[]> contentDigests;
- public VerifiedSigner(Certificate[] certs, byte[] apkDigest) {
+ public VerifiedSigner(Certificate[] certs, byte[] apkDigest,
+ Map<Integer, byte[]> contentDigests) {
this.certs = certs;
this.apkDigest = apkDigest;
+ this.contentDigests = contentDigests;
}
}
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index ab8f80d3d1a5..e0258f7657b2 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -45,6 +45,7 @@ import java.security.cert.CertificateEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.zip.ZipEntry;
@@ -184,21 +185,21 @@ public class ApkSignatureVerifier {
Signature[] signerSigs = convertToSignatures(signerCerts);
if (verifyFull) {
- byte[] nonstreamingDigest = null;
- Certificate[][] nonstreamingCerts = null;
+ Map<Integer, byte[]> nonstreamingDigests;
+ Certificate[][] nonstreamingCerts;
try {
// v4 is an add-on and requires v2 or v3 signature to validate against its
// certificate and digest
ApkSignatureSchemeV3Verifier.VerifiedSigner v3Signer =
ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath);
- nonstreamingDigest = v3Signer.digest;
+ nonstreamingDigests = v3Signer.contentDigests;
nonstreamingCerts = new Certificate[][]{v3Signer.certs};
} catch (SignatureNotFoundException e) {
try {
ApkSignatureSchemeV2Verifier.VerifiedSigner v2Signer =
ApkSignatureSchemeV2Verifier.verify(apkPath, false);
- nonstreamingDigest = v2Signer.digest;
+ nonstreamingDigests = v2Signer.contentDigests;
nonstreamingCerts = v2Signer.certs;
} catch (SignatureNotFoundException ee) {
throw new SecurityException(
@@ -220,8 +221,15 @@ public class ApkSignatureVerifier {
}
}
- if (!ArrayUtils.equals(vSigner.apkDigest, nonstreamingDigest,
- vSigner.apkDigest.length)) {
+ boolean found = false;
+ for (byte[] nonstreamingDigest : nonstreamingDigests.values()) {
+ if (ArrayUtils.equals(vSigner.apkDigest, nonstreamingDigest,
+ vSigner.apkDigest.length)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
throw new SecurityException("APK digest in V4 signature does not match V2/V3");
}
}
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 6efe95cb9e92..990092caa833 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -577,21 +577,6 @@ final class ApkSigningBlockUtils {
}
/**
- * Returns the best digest from the map of available digests.
- * similarly to compareContentDigestAlgorithm.
- *
- * Keep in sync with pickBestDigestForV4 in apksigner's ApkSigningBlockUtils.
- */
- static byte[] pickBestDigestForV4(Map<Integer, byte[]> contentDigests) {
- for (int algo : V4_CONTENT_DIGEST_ALGORITHMS) {
- if (contentDigests.containsKey(algo)) {
- return contentDigests.get(algo);
- }
- }
- return null;
- }
-
- /**
* Returns new byte buffer whose content is a shared subsequence of this buffer's content
* between the specified start (inclusive) and end (exclusive) positions. As opposed to
* {@link ByteBuffer#slice()}, the returned buffer's byte order is the same as the source
diff --git a/core/java/android/view/IDisplayWindowInsetsController.aidl b/core/java/android/view/IDisplayWindowInsetsController.aidl
index 429c3aeba9b3..a0d4a6587bcf 100644
--- a/core/java/android/view/IDisplayWindowInsetsController.aidl
+++ b/core/java/android/view/IDisplayWindowInsetsController.aidl
@@ -27,6 +27,13 @@ import android.view.InsetsState;
oneway interface IDisplayWindowInsetsController {
/**
+ * Called when top focused window changes to determine whether or not to take over insets
+ * control. Won't be called if config_remoteInsetsControllerControlsSystemBars is false.
+ * @param packageName: Passes the top package name
+ */
+ void topFocusedWindowChanged(String packageName);
+
+ /**
* @see IWindow#insetsChanged
*/
void insetsChanged(in InsetsState insetsState);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 58597cf3fb6d..00fc67214f75 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -388,16 +388,6 @@ interface IWindowManager
oneway void hideTransientBars(int displayId);
/**
- * When set to {@code true} the system bars will always be shown. This is true even if an app
- * requests to be fullscreen by setting the system ui visibility flags. The
- * functionality was added for the automotive case as a way to guarantee required content stays
- * on screen at all times.
- *
- * @hide
- */
- oneway void setForceShowSystemBars(boolean show);
-
- /**
* Called by System UI to notify of changes to the visibility of Recents.
*/
oneway void setRecentsVisibility(boolean visible);
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index ef9d990168d2..c1998c6009cf 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -119,11 +119,11 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
// If we had a request before to show from IME (tracked with mImeRequestedShow), reaching
// this code here means that we now got control, so we can start the animation immediately.
// If client window is trying to control IME and IME is already visible, it is immediate.
- if (fromIme || mState.getSource(getType()).isVisible()) {
+ if (fromIme || mState.getSource(getType()).isVisible() && getControl() != null) {
return ShowResult.SHOW_IMMEDIATELY;
}
- return getImm().requestImeShow(null /* resultReceiver */)
+ return getImm().requestImeShow(mController.getHost().getWindowToken())
? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED;
}
@@ -132,12 +132,15 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
*/
@Override
void notifyHidden() {
- getImm().notifyImeHidden();
+ getImm().notifyImeHidden(mController.getHost().getWindowToken());
}
@Override
public void removeSurface() {
- getImm().removeImeSurface();
+ final IBinder window = mController.getHost().getWindowToken();
+ if (window != null) {
+ getImm().removeImeSurface(window);
+ }
}
@Override
@@ -146,6 +149,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
super.setControl(control, showTypes, hideTypes);
if (control == null && !mIsRequestedVisibleAwaitingControl) {
hide();
+ removeSurface();
}
}
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 40e6f4b2fce8..700dc66fab55 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -153,6 +153,9 @@ public class InsetsSourceConsumer {
if (oldLeash == null || newLeash == null || !oldLeash.isSameSurface(newLeash)) {
applyHiddenToControl();
}
+ if (!requestedVisible && !mIsAnimationPending) {
+ removeSurface();
+ }
}
}
if (lastControl != null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 13f11dce6e4b..2168fe331972 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13800,6 +13800,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
+ private void notifySubtreeAccessibilityStateChangedByParentIfNeeded() {
+ if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
+ return;
+ }
+
+ final View sendA11yEventView = (View) getParentForAccessibility();
+ if (sendA11yEventView != null && sendA11yEventView.isShown()) {
+ sendA11yEventView.notifySubtreeAccessibilityStateChangedIfNeeded();
+ }
+ }
+
/**
* Changes the visibility of this View without triggering any other changes. This should only
* be used by animation frameworks, such as {@link android.transition.Transition}, where
@@ -16229,7 +16240,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) {
dispatchVisibilityAggregated(newVisibility == VISIBLE);
}
- notifySubtreeAccessibilityStateChangedIfNeeded();
+ // If this view is invisible from visible, then sending the A11y event by its
+ // parent which is shown and has the accessibility important.
+ if ((old & VISIBILITY_MASK) == VISIBLE) {
+ notifySubtreeAccessibilityStateChangedByParentIfNeeded();
+ } else {
+ notifySubtreeAccessibilityStateChangedIfNeeded();
+ }
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 81a78dc177ec..b022d2af7772 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2717,7 +2717,6 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mThreadedRenderer.isEnabled()) {
mAttachInfo.mThreadedRenderer.destroy();
}
- notifySurfaceDestroyed();
} else if ((surfaceReplaced
|| surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged)
&& mSurfaceHolder == null
@@ -2948,6 +2947,10 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ if (surfaceDestroyed) {
+ notifySurfaceDestroyed();
+ }
+
if (triggerGlobalLayoutListener) {
mAttachInfo.mRecomputeGlobalAttributes = false;
mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
@@ -9382,6 +9385,11 @@ public final class ViewRootImpl implements ViewParent,
return mInputEventReceiver.getToken();
}
+ @NonNull
+ public IBinder getWindowToken() {
+ return mAttachInfo.mWindowToken;
+ }
+
/**
* Class for managing the accessibility interaction connection
* based on the global accessibility state.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 864c40f8a740..fa92e29cbf58 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2111,28 +2111,36 @@ public final class InputMethodManager {
/**
* Call showSoftInput with currently focused view.
- * @return {@code true} if IME can be shown.
+ *
+ * @param windowToken the window from which this request originates. If this doesn't match the
+ * currently served view, the request is ignored and returns {@code false}.
+ *
+ * @return {@code true} if IME can (eventually) be shown, {@code false} otherwise.
* @hide
*/
- public boolean requestImeShow(ResultReceiver resultReceiver) {
+ public boolean requestImeShow(IBinder windowToken) {
synchronized (mH) {
final View servedView = getServedViewLocked();
- if (servedView == null) {
+ if (servedView == null || servedView.getWindowToken() != windowToken) {
return false;
}
- showSoftInput(servedView, 0 /* flags */, resultReceiver);
+ showSoftInput(servedView, 0 /* flags */, null /* resultReceiver */);
return true;
}
}
/**
* Notify IME directly that it is no longer visible.
+ *
+ * @param windowToken the window from which this request originates. If this doesn't match the
+ * currently served view, the request is ignored.
* @hide
*/
- public void notifyImeHidden() {
+ public void notifyImeHidden(IBinder windowToken) {
synchronized (mH) {
try {
- if (mCurMethod != null) {
+ if (mCurMethod != null && mCurRootView != null
+ && mCurRootView.getWindowToken() == windowToken) {
mCurMethod.notifyImeHidden();
}
} catch (RemoteException re) {
@@ -2142,15 +2150,15 @@ public final class InputMethodManager {
/**
* Notify IME directly to remove surface as it is no longer visible.
+ * @param windowToken The client window token that requests the IME to remove its surface.
* @hide
*/
- public void removeImeSurface() {
+ public void removeImeSurface(IBinder windowToken) {
synchronized (mH) {
try {
- if (mCurMethod != null) {
- mCurMethod.removeImeSurface();
- }
- } catch (RemoteException re) {
+ mService.removeImeSurfaceFromWindow(windowToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/widget/EditorTouchState.java b/core/java/android/widget/EditorTouchState.java
index ff3ac0732aa2..9eb63087a66e 100644
--- a/core/java/android/widget/EditorTouchState.java
+++ b/core/java/android/widget/EditorTouchState.java
@@ -174,12 +174,9 @@ public class EditorTouchState {
int touchSlop = config.getScaledTouchSlop();
mMovedEnoughForDrag = distanceSquared > touchSlop * touchSlop;
if (mMovedEnoughForDrag) {
- // If the direction of the swipe motion is within 30 degrees of vertical, it is
- // considered a vertical drag. We don't actually have to compute the angle to
- // implement the check though. When the angle is exactly 30 degrees from
- // vertical, 2*deltaX = distance. When the angle is less than 30 degrees from
- // vertical, 2*deltaX < distance.
- mIsDragCloseToVertical = (4 * deltaXSquared) <= distanceSquared;
+ // If the direction of the swipe motion is within 45 degrees of vertical, it is
+ // considered a vertical drag.
+ mIsDragCloseToVertical = Math.abs(deltaX) <= Math.abs(deltaY);
}
}
} else if (action == MotionEvent.ACTION_CANCEL) {
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 843700cef55e..32c68bdd0491 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -108,7 +108,7 @@ public final class SelectionActionModeHelper {
*
* @return the swap result, index 0 is the start index and index 1 is the end index.
*/
- private static int[] sortSelctionIndices(int selectionStart, int selectionEnd) {
+ private static int[] sortSelectionIndices(int selectionStart, int selectionEnd) {
if (selectionStart < selectionEnd) {
return new int[]{selectionStart, selectionEnd};
}
@@ -122,11 +122,11 @@ public final class SelectionActionModeHelper {
* @param textView the selected TextView.
* @return the swap result, index 0 is the start index and index 1 is the end index.
*/
- private static int[] sortSelctionIndicesFromTextView(TextView textView) {
+ private static int[] sortSelectionIndicesFromTextView(TextView textView) {
int selectionStart = textView.getSelectionStart();
int selectionEnd = textView.getSelectionEnd();
- return sortSelctionIndices(selectionStart, selectionEnd);
+ return sortSelectionIndices(selectionStart, selectionEnd);
}
/**
@@ -135,7 +135,7 @@ public final class SelectionActionModeHelper {
public void startSelectionActionModeAsync(boolean adjustSelection) {
// Check if the smart selection should run for editable text.
adjustSelection &= getTextClassificationSettings().isSmartSelectionEnabled();
- int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
+ int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
mSelectionTracker.onOriginalSelection(
getText(mTextView),
@@ -165,7 +165,7 @@ public final class SelectionActionModeHelper {
* Starts Link ActionMode.
*/
public void startLinkActionModeAsync(int start, int end) {
- int[] indexResult = sortSelctionIndices(start, end);
+ int[] indexResult = sortSelectionIndices(start, end);
mSelectionTracker.onOriginalSelection(getText(mTextView), indexResult[0], indexResult[1],
true /*isLink*/);
cancelAsyncTask();
@@ -201,21 +201,21 @@ public final class SelectionActionModeHelper {
/** Reports a selection action event. */
public void onSelectionAction(int menuItemId, @Nullable String actionLabel) {
- int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
+ int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
mSelectionTracker.onSelectionAction(
sortedSelectionIndices[0], sortedSelectionIndices[1],
getActionType(menuItemId), actionLabel, mTextClassification);
}
public void onSelectionDrag() {
- int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
+ int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
mSelectionTracker.onSelectionAction(
sortedSelectionIndices[0], sortedSelectionIndices[1],
SelectionEvent.ACTION_DRAG, /* actionLabel= */ null, mTextClassification);
}
public void onTextChanged(int start, int end) {
- int[] sortedSelectionIndices = sortSelctionIndices(start, end);
+ int[] sortedSelectionIndices = sortSelectionIndices(start, end);
mSelectionTracker.onTextChanged(sortedSelectionIndices[0], sortedSelectionIndices[1],
mTextClassification);
}
@@ -334,7 +334,7 @@ public final class SelectionActionModeHelper {
startSelectionActionMode(startSelectionResult);
};
// TODO do not trigger the animation if the change included only non-printable characters
- int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
+ int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
final boolean didSelectionChange =
result != null && (sortedSelectionIndices[0] != result.mStart
|| sortedSelectionIndices[1] != result.mEnd);
@@ -486,7 +486,7 @@ public final class SelectionActionModeHelper {
if (actionMode != null) {
actionMode.invalidate();
}
- final int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
+ final int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
mSelectionTracker.onSelectionUpdated(
sortedSelectionIndices[0], sortedSelectionIndices[1], mTextClassification);
mTextClassificationAsyncTask = null;
@@ -495,7 +495,7 @@ public final class SelectionActionModeHelper {
private void resetTextClassificationHelper(int selectionStart, int selectionEnd) {
if (selectionStart < 0 || selectionEnd < 0) {
// Use selection indices
- int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(mTextView);
+ int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(mTextView);
selectionStart = sortedSelectionIndices[0];
selectionEnd = sortedSelectionIndices[1];
}
@@ -637,7 +637,7 @@ public final class SelectionActionModeHelper {
mAllowReset = false;
boolean selected = editor.selectCurrentWord();
if (selected) {
- final int[] sortedSelectionIndices = sortSelctionIndicesFromTextView(textView);
+ final int[] sortedSelectionIndices = sortSelectionIndicesFromTextView(textView);
mSelectionStart = sortedSelectionIndices[0];
mSelectionEnd = sortedSelectionIndices[1];
mLogger.logSelectionAction(
@@ -1215,7 +1215,7 @@ public final class SelectionActionModeHelper {
SelectionResult(int start, int end,
@Nullable TextClassification classification, @Nullable TextSelection selection) {
- int[] sortedIndices = sortSelctionIndices(start, end);
+ int[] sortedIndices = sortSelectionIndices(start, end);
mStart = sortedIndices[0];
mEnd = sortedIndices[1];
mClassification = classification;
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 476198b5311a..bbfd07b64ccf 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -358,6 +358,8 @@ public class NativeLibraryHelper {
createNativeLibrarySubdir(subDir);
}
+ // Even if extractNativeLibs is false, we still need to check if the native libs in the APK
+ // are valid. This is done in the native code.
int copyRet = copyNativeBinaries(handle, subDir, supportedAbi);
if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
return copyRet;
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index cc55cff262a3..e09ef49acd10 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -27,6 +27,7 @@ import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -126,6 +127,11 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
};
+ private final Object mNativeTidsLock = new Object();
+ // @GuardedBy("mNativeTidsLock") // Cannot mark it as "GuardedBy" because it's read
+ // directly, as a volatile field.
+ private volatile IntArray mNativeTids = new IntArray(0);
+
/** Injector for {@link BinderCallsStats}. */
public static class Injector {
public Random getRandomGenerator() {
@@ -175,6 +181,8 @@ public class BinderCallsStats implements BinderInternal.Observer {
return null;
}
+ noteNativeThreadId();
+
final CallSession s = obtainCallSession();
s.binderClass = binder.getClass();
s.transactionCode = code;
@@ -312,6 +320,27 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
}
+ private void noteNativeThreadId() {
+ final int tid = getNativeTid();
+ int index = mNativeTids.binarySearch(tid);
+ if (index >= 0) {
+ return;
+ }
+
+ // Use the copy-on-write approach. The changes occur exceedingly infrequently, so
+ // this code path is exercised just a few times per boot
+ synchronized (mNativeTidsLock) {
+ IntArray nativeTids = mNativeTids;
+ index = nativeTids.binarySearch(tid);
+ if (index < 0) {
+ IntArray copyOnWriteArray = new IntArray(nativeTids.size() + 1);
+ copyOnWriteArray.addAll(nativeTids);
+ copyOnWriteArray.add(-index - 1, tid);
+ mNativeTids = copyOnWriteArray;
+ }
+ }
+ }
+
/**
* This method is expensive to call.
*/
@@ -505,6 +534,17 @@ public class BinderCallsStats implements BinderInternal.Observer {
return Binder.getCallingUid();
}
+ protected int getNativeTid() {
+ return Binder.getNativeTid();
+ }
+
+ /**
+ * Returns known Linux TIDs for threads taking incoming binder calls.
+ */
+ public int[] getNativeTids() {
+ return mNativeTids.toArray();
+ }
+
protected long getElapsedRealtimeMicro() {
return SystemClock.elapsedRealtimeNanos() / 1000;
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 0b46658d5a06..0a3fe096279d 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -21,8 +21,6 @@ import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COM
import static android.view.View.SYSTEM_UI_LAYOUT_FLAGS;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowInsets.Type.ime;
-import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -34,8 +32,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -146,17 +142,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if ((view.getWindowSystemUiVisibility() & SYSTEM_UI_LAYOUT_FLAGS) != 0) {
return new Pair<>(Insets.NONE, insets);
}
-
- boolean includeIme = (view.getViewRootImpl().mWindowAttributes.softInputMode
- & SOFT_INPUT_MASK_ADJUST)
- == SOFT_INPUT_ADJUST_RESIZE;
- Insets insetsToApply;
- if (ViewRootImpl.sNewInsetsMode == 0) {
- insetsToApply = insets.getSystemWindowInsets();
- } else {
- insetsToApply = insets.getInsets(systemBars() | (includeIme ? ime() : 0));
- }
- insets = insets.inset(insetsToApply);
+ Insets insetsToApply = insets.getSystemWindowInsets();
return new Pair<>(insetsToApply,
insets.inset(insetsToApply).consumeSystemWindowInsets());
};
diff --git a/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl b/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
index cf1220c08467..03948a92bcab 100644
--- a/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
+++ b/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
@@ -58,4 +58,7 @@ oneway interface IInlineSuggestionsRequestCallback {
// #onFinishInput()} is called on the field specified by the earlier
// {@link #onInputMethodStartInput(AutofillId)}.
void onInputMethodFinishInput();
+
+ // Indicates that the current IME changes inline suggestion session.
+ void onInlineSuggestionsSessionInvalidated();
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 8ec51b89d240..a1cbd3fcae79 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -73,5 +73,8 @@ interface IInputMethodManager {
in float[] matrixValues);
oneway void reportPerceptible(in IBinder windowToken, boolean perceptible);
+ /** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
void removeImeSurface();
+ /** Remove the IME surface. Requires passing the currently focused window. */
+ void removeImeSurfaceFromWindow(in IBinder windowToken);
}
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index 71edfd553e7e..350f35828418 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -61,8 +61,8 @@ bool NativeInputApplicationHandle::updateInfo() {
mInfo.name = getStringField(env, obj, gInputApplicationHandleClassInfo.name, "<null>");
- mInfo.dispatchingTimeout = env->GetLongField(obj,
- gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
+ mInfo.dispatchingTimeout = decltype(mInfo.dispatchingTimeout)(
+ env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutNanos));
jobject tokenObj = env->GetObjectField(obj,
gInputApplicationHandleClassInfo.token);
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 81569e0f7b7a..792c00572318 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -117,8 +117,8 @@ bool NativeInputWindowHandle::updateInfo() {
gInputWindowHandleClassInfo.layoutParamsFlags);
mInfo.layoutParamsType = env->GetIntField(obj,
gInputWindowHandleClassInfo.layoutParamsType);
- mInfo.dispatchingTimeout = env->GetLongField(obj,
- gInputWindowHandleClassInfo.dispatchingTimeoutNanos);
+ mInfo.dispatchingTimeout = decltype(mInfo.dispatchingTimeout)(
+ env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutNanos));
mInfo.frameLeft = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameLeft);
mInfo.frameTop = env->GetIntField(obj,
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index b6427c9aa01c..48f33a6a3d77 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -339,6 +339,10 @@ static jobject JHwBinder_native_getService(
return JHwRemoteBinder::NewObject(env, service);
}
+void JHwBinder_native_setTrebleTestingOverride(JNIEnv*, jclass, jboolean testingOverride) {
+ hardware::details::setTrebleTestingOverride(testingOverride);
+}
+
void JHwBinder_native_configureRpcThreadpool(JNIEnv *, jclass,
jlong maxThreads, jboolean callerWillJoin) {
CHECK(maxThreads > 0);
@@ -368,6 +372,9 @@ static JNINativeMethod gMethods[] = {
{ "getService", "(Ljava/lang/String;Ljava/lang/String;Z)L" PACKAGE_PATH "/IHwBinder;",
(void *)JHwBinder_native_getService },
+ { "setTrebleTestingOverride", "(Z)V",
+ (void *)JHwBinder_native_setTrebleTestingOverride },
+
{ "configureRpcThreadpool", "(JZ)V",
(void *)JHwBinder_native_configureRpcThreadpool },
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index a88f8919ed08..ff336ee64b54 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -122,10 +122,18 @@ void signalExceptionForError(JNIEnv *env, status_t err, bool canThrowRemoteExcep
std::stringstream ss;
ss << "HwBinder Error: (" << err << ")";
- jniThrowException(
- env,
- canThrowRemoteException ? "android/os/RemoteException" : "java/lang/RuntimeException",
- ss.str().c_str());
+ const char* exception = nullptr;
+ if (canThrowRemoteException) {
+ if (err == DEAD_OBJECT) {
+ exception = "android/os/DeadObjectException";
+ } else {
+ exception = "android/os/RemoteException";
+ }
+ } else {
+ exception = "java/lang/RuntimeException";
+ }
+
+ jniThrowException(env, exception, ss.str().c_str());
break;
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 4c9d7abeb5a1..885b0a33e43c 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -30,6 +30,7 @@
#include <unistd.h>
#include <android-base/stringprintf.h>
+#include <android-base/threads.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
@@ -1047,6 +1048,10 @@ static void android_os_Binder_setExtension(JNIEnv* env, jobject obj, jobject ext
jbh->setExtension(extension);
}
+static jint android_os_Binder_getNativeTid() {
+ return (jint)android::base::GetThreadId();
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gBinderMethods[] = {
@@ -1078,6 +1083,8 @@ static const JNINativeMethod gBinderMethods[] = {
{ "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable },
{ "getExtension", "()Landroid/os/IBinder;", (void*)android_os_Binder_getExtension },
{ "setExtension", "(Landroid/os/IBinder;)V", (void*)android_os_Binder_setExtension },
+ // @CriticalNative
+ { "getNativeTid", "()I", (void*)android_os_Binder_getNativeTid },
};
const char* const kBinderPathName = "android/os/Binder";
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 6e49c0dda1ad..b7c5289043d6 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -124,7 +124,6 @@ typedef const std::function<void(std::string)>& fail_fn_t;
static pid_t gSystemServerPid = 0;
static constexpr const char* kVoldAppDataIsolation = "persist.sys.vold_app_data_isolation_enabled";
-static constexpr const char* kPropFuse = "persist.sys.fuse";
static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
static jclass gZygoteClass;
static jmethodID gCallPostForkSystemServerHooks;
@@ -836,29 +835,20 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode,
PrepareDir(user_source, 0710, user_id ? AID_ROOT : AID_SHELL,
multiuser_get_uid(user_id, AID_EVERYBODY), fail_fn);
- bool isFuse = GetBoolProperty(kPropFuse, false);
bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, false);
- if (isFuse) {
- if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
+ if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
const std::string pass_through_source = StringPrintf("/mnt/pass_through/%d", user_id);
PrepareDir(pass_through_source, 0710, AID_ROOT, AID_MEDIA_RW, fail_fn);
BindMount(pass_through_source, "/storage", fail_fn);
- } else if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
+ } else if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
const std::string installer_source = StringPrintf("/mnt/installer/%d", user_id);
BindMount(installer_source, "/storage", fail_fn);
- } else if (isAppDataIsolationEnabled && mount_mode == MOUNT_EXTERNAL_ANDROID_WRITABLE) {
+ } else if (isAppDataIsolationEnabled && mount_mode == MOUNT_EXTERNAL_ANDROID_WRITABLE) {
const std::string writable_source = StringPrintf("/mnt/androidwritable/%d", user_id);
BindMount(writable_source, "/storage", fail_fn);
- } else {
- BindMount(user_source, "/storage", fail_fn);
- }
} else {
- const std::string& storage_source = ExternalStorageViews[mount_mode];
- BindMount(storage_source, "/storage", fail_fn);
-
- // Mount user-specific symlink helper into place
- BindMount(user_source, "/storage/self", fail_fn);
+ BindMount(user_source, "/storage", fail_fn);
}
}
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 00505caa18c3..f5d7246b96a3 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1172,7 +1172,7 @@
<string name="Midnight" msgid="8176019203622191377">"منتصف الليل"</string>
<string name="elapsed_time_short_format_mm_ss" msgid="8689459651807876423">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="1532369154488982046">"اختيار الكل"</string>
+ <string name="selectAll" msgid="1532369154488982046">"تحديد الكل"</string>
<string name="cut" msgid="2561199725874745819">"قص"</string>
<string name="copy" msgid="5472512047143665218">"نسخ"</string>
<string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"تعذّر النسخ في الحافظة"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index ce08e43cb1af..d312d859a58c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1152,7 +1152,7 @@
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Capturar imagen con %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Capturar imagen"</string>
<string name="alwaysUse" msgid="3153558199076112903">"Usar siempre para esta acción"</string>
- <string name="use_a_different_app" msgid="4987790276170972776">"Utiliza otra aplicación"</string>
+ <string name="use_a_different_app" msgid="4987790276170972776">"Usar otra aplicación"</string>
<string name="clearDefaultHintMsg" msgid="1325866337702524936">"Para borrar los valores predeterminados, accede a Ajustes del sistema &gt; Aplicaciones &gt; Descargadas."</string>
<string name="chooseActivity" msgid="8563390197659779956">"Selecciona una acción"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"Elegir una aplicación para el dispositivo USB"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index eb675ddb06a5..485f5bf08224 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1926,7 +1926,7 @@
<string name="time_picker_header_text" msgid="9073802285051516688">"Ezarri ordua"</string>
<string name="time_picker_input_error" msgid="8386271930742451034">"Idatzi balio duen ordu bat"</string>
<string name="time_picker_prompt_label" msgid="303588544656363889">"Idatzi ordua"</string>
- <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Aldatu testu modura ordua zehazteko."</string>
+ <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Ordua idazteko, aldatu testua idazteko metodora."</string>
<string name="time_picker_radial_mode_description" msgid="1222342577115016953">"Aldatu erloju modura ordua zehazteko."</string>
<string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"Betetze automatikoaren aukerak"</string>
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Gorde betetze automatikoarekin erabiltzeko"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 8d9df1f2b09b..bd328b542966 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -857,7 +857,7 @@
<string name="emergency_calls_only" msgid="3057351206678279851">"Só chamadas de emerxencia"</string>
<string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Bloqueada pola rede"</string>
<string name="lockscreen_sim_puk_locked_message" msgid="6618356415831082174">"A tarxeta SIM está bloqueada con código PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consulta a guía do usuario ou ponte en contacto co servizo de asistencia ao cliente."</string>
+ <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consulta a guía para usuarios ou ponte en contacto co servizo de asistencia ao cliente."</string>
<string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"A tarxeta SIM está bloqueada."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"Desbloqueando tarxeta SIM…"</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Debuxaches incorrectamente o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 99665c43bf20..4f3d89009323 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1548,7 +1548,7 @@
<string name="launchBrowserDefault" msgid="6328349989932924119">"ब्राउज़र लॉन्च करें?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"कॉल स्वीकार करें?"</string>
<string name="activity_resolver_use_always" msgid="5575222334666843269">"हमेशा"</string>
- <string name="activity_resolver_use_once" msgid="948462794469672658">"केवल एक बार"</string>
+ <string name="activity_resolver_use_once" msgid="948462794469672658">"सिर्फ़ एक बार"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s वर्क प्रोफ़ाइल का समर्थन नहीं करता"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"टैबलेट"</string>
<string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"टीवी"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e74157f2e02b..eabf37c50878 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1152,7 +1152,7 @@
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"「%1$s」を使用して画像をキャプチャ"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"画像をキャプチャ"</string>
<string name="alwaysUse" msgid="3153558199076112903">"常にこの操作で使用する"</string>
- <string name="use_a_different_app" msgid="4987790276170972776">"別のアプリの使用"</string>
+ <string name="use_a_different_app" msgid="4987790276170972776">"別のアプリを使用"</string>
<string name="clearDefaultHintMsg" msgid="1325866337702524936">"[システム設定]&gt;[アプリ]&gt;[ダウンロード済み]でデフォルト設定をクリアします。"</string>
<string name="chooseActivity" msgid="8563390197659779956">"操作の選択"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"USBデバイス用アプリを選択"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index affbc838048b..351790d44b7b 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1547,7 +1547,7 @@
<string name="sending" msgid="206925243621664438">"Жіберілуде..."</string>
<string name="launchBrowserDefault" msgid="6328349989932924119">"Браузер қосылсын ба?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Қоңырауды қабылдау?"</string>
- <string name="activity_resolver_use_always" msgid="5575222334666843269">"Үнемі"</string>
+ <string name="activity_resolver_use_always" msgid="5575222334666843269">"Әрқашан"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"Бір рет қана"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s жұмыс профилін қолдамайды"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Планшет"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index df8e33d5c149..f1bea56a62fd 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -538,7 +538,7 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Колдонмого сүрөт жыйнагыңызды өзгөртүүгө мүмкүнчүлүк берет."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"медиа жыйнагыңыз сакталган жерлерди окуу"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Колдонмого медиа жыйнагыңыз сакталган жерлерди окууга мүмкүнчүлүк берет."</string>
- <string name="biometric_dialog_default_title" msgid="55026799173208210">"Сиз экениңизди ырастаңыз"</string>
+ <string name="biometric_dialog_default_title" msgid="55026799173208210">"Өзүңүздү ырастаңыз"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалык аппарат жеткиликсиз"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аныктыгын текшерүү жокко чыгарылды"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Таанылган жок"</string>
@@ -1111,7 +1111,7 @@
<string name="inputMethod" msgid="1784759500516314751">"Киргизүү ыкмасы"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Текст боюнча иштер"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Сактагычта орун калбай баратат"</string>
- <string name="low_internal_storage_view_text" msgid="8172166728369697835">"Системанын кээ бир функциялары иштебеши мүмкүн"</string>
+ <string name="low_internal_storage_view_text" msgid="8172166728369697835">"Айрым функциялар иштебеши мүмкүн"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"Тутумда сактагыч жетишсиз. 250МБ бош орун бар экенин текшерип туруп, өчүрүп күйгүзүңүз."</string>
<string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> иштөөдө"</string>
<string name="app_running_notification_text" msgid="5120815883400228566">"Көбүрөөк маалымат үчүн же колдонмону токтотуш үчүн таптап коюңуз."</string>
@@ -1547,7 +1547,7 @@
<string name="sending" msgid="206925243621664438">"Жөнөтүлүүдө…"</string>
<string name="launchBrowserDefault" msgid="6328349989932924119">"Серепчи иштетилсинби?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Чалуу кабыл алынсынбы?"</string>
- <string name="activity_resolver_use_always" msgid="5575222334666843269">"Дайыма"</string>
+ <string name="activity_resolver_use_always" msgid="5575222334666843269">"Ар дайым"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"Бир жолу гана"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s жумуш профилин колдоого албайт"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Планшет"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index a24db6617c2e..b4982ebdeeca 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1547,7 +1547,7 @@
<string name="sending" msgid="206925243621664438">"അയയ്‌ക്കുന്നു…"</string>
<string name="launchBrowserDefault" msgid="6328349989932924119">"ബ്രൗസർ സമാരംഭിക്കണോ?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"കോൾ സ്വീകരിക്കണോ?"</string>
- <string name="activity_resolver_use_always" msgid="5575222334666843269">"എല്ലായ്പ്പോഴും"</string>
+ <string name="activity_resolver_use_always" msgid="5575222334666843269">"എല്ലായ്‌പ്പോഴും"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"ഒരിക്കൽ മാത്രം"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s, ഔദ്യോഗിക പ്രൊഫൈലിനെ പിന്തുണയ്‌ക്കുന്നില്ല"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"ടാബ്‌ലെറ്റ്"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 8eb8cef9f3c2..be21f7b8df15 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1093,7 +1093,7 @@
<string name="elapsed_time_short_format_mm_ss" msgid="8689459651807876423">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="1532369154488982046">"Hammasini belgilash"</string>
- <string name="cut" msgid="2561199725874745819">"Kesish"</string>
+ <string name="cut" msgid="2561199725874745819">"Kesib olish"</string>
<string name="copy" msgid="5472512047143665218">"Nusxa olish"</string>
<string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Vaqtinchalik xotiraga nusxalab bo‘lmadi"</string>
<string name="paste" msgid="461843306215520225">"Joylash"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 8061ed8c6dd2..33675da1fd38 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -538,7 +538,7 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Cho phép ứng dụng này sửa đổi bộ sưu tập ảnh của bạn."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"đọc vị trí từ bộ sưu tập phương tiện"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Cho phép ứng dụng này đọc vị trí từ bộ sưu tập phương tiện của bạn."</string>
- <string name="biometric_dialog_default_title" msgid="55026799173208210">"Xác minh đó là bạn"</string>
+ <string name="biometric_dialog_default_title" msgid="55026799173208210">"Xác minh danh tính của bạn"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Không có phần cứng sinh trắc học"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Đã hủy xác thực"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Không nhận dạng được"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 51737ba80550..6ccfc09a46a0 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"為了延長電池續航力,省電模式會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"為了延長電池續航力,省電模式會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟數據節省模式嗎?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string>
@@ -2000,9 +2000,9 @@
<string name="notification_feedback_indicator" msgid="663476517711323016">"提供意見"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式資訊通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"電池電力可能會在你平常的充電時間前耗盡"</string>
- <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已啟用節約耗電量模式以延長電池續航力"</string>
- <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"節約耗電量"</string>
- <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"節約耗電量模式已關閉"</string>
+ <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已啟用省電模式以延長電池續航力"</string>
+ <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"省電模式"</string>
+ <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"省電模式已關閉"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"手機電力充足,各項功能不再受到限制。"</string>
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"平板電腦電力充足,各項功能不再受到限制。"</string>
<string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"裝置電力充足,各項功能不再受到限制。"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f60766adc7f7..28a164f139e1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -712,10 +712,17 @@
case, this can be disabled (set to false). -->
<bool name="config_enableCarDockHomeLaunch">true</bool>
- <!-- Control whether to force the display of System UI Bars at all times regardless of
- System Ui Flags. This can be useful in the Automotive case if there's a requirement for
- a UI element to be on screen at all times. -->
- <bool name="config_forceShowSystemBars">false</bool>
+ <!-- Control whether to force apps to give up control over the display of system bars at all
+ times regardless of System Ui Flags.
+ In the Automotive case, this is helpful if there's a requirement for an UI element to be on
+ screen at all times. Setting this to true also gives System UI the ability to override the
+ visibility controls for the system through the usage of the
+ "SYSTEM_BAR_VISIBILITY_OVERRIDE" setting.
+ Ex: Only setting the config to true will force show system bars for the entire system.
+ Ex: Setting the config to true and the "SYSTEM_BAR_VISIBILITY_OVERRIDE" setting to
+ "immersive.status=apps" will force show navigation bar for all apps and force hide status
+ bar for all apps. -->
+ <bool name="config_remoteInsetsControllerControlsSystemBars">false</bool>
<!-- HDMI behavior -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 37d1eccefd4a..303fde6705c2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3024,6 +3024,8 @@
<!-- @hide @TestApi -->
<public type="bool" name="config_assistantOnTopOfDream" id="0x01110005" />
+ <!-- @hide @TestApi -->
+ <public type="bool" name="config_remoteInsetsControllerControlsSystemBars" id="0x01110006" />
<!-- ===============================================================
Resources added in version S of the platform
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5bb784a1edc7..16427cd50577 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1669,7 +1669,7 @@
<java-symbol type="bool" name="config_enableCarDockHomeLaunch" />
<java-symbol type="bool" name="config_enableLockBeforeUnlockScreen" />
<java-symbol type="bool" name="config_enableLockScreenRotation" />
- <java-symbol type="bool" name="config_forceShowSystemBars" />
+ <java-symbol type="bool" name="config_remoteInsetsControllerControlsSystemBars" />
<java-symbol type="bool" name="config_lidControlsScreenLock" />
<java-symbol type="bool" name="config_lidControlsSleep" />
<java-symbol type="bool" name="config_lockDayNightMode" />
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index 17d1389a6602..777f4a3e03a8 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -23,6 +23,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.app.ActivityThread;
@@ -180,4 +181,26 @@ public class ContextTest {
VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
return virtualDisplay.getDisplay();
}
+
+ @Test
+ public void testIsUiContext_ContextWrapper() {
+ ContextWrapper wrapper = new ContextWrapper(null /* base */);
+
+ assertFalse(wrapper.isUiContext());
+
+ wrapper = new ContextWrapper(new TestUiContext());
+
+ assertTrue(wrapper.isUiContext());
+ }
+
+ private static class TestUiContext extends ContextWrapper {
+ TestUiContext() {
+ super(null /* base */);
+ }
+
+ @Override
+ public boolean isUiContext() {
+ return true;
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 1b3272572db0..7efd616c5607 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -71,6 +71,9 @@ public class InsetsSourceConsumerTest {
private SurfaceControl mLeash;
@Mock Transaction mMockTransaction;
private InsetsSource mSpyInsetsSource;
+ private boolean mRemoveSurfaceCalled = false;
+ private InsetsController mController;
+ private InsetsState mState;
@Before
public void setup() {
@@ -89,13 +92,19 @@ public class InsetsSourceConsumerTest {
} catch (BadTokenException e) {
// activity isn't running, lets ignore BadTokenException.
}
- InsetsState state = new InsetsState();
+ mState = new InsetsState();
mSpyInsetsSource = Mockito.spy(new InsetsSource(ITYPE_STATUS_BAR));
- state.addSource(mSpyInsetsSource);
-
- mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, state,
- () -> mMockTransaction,
- new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl)));
+ mState.addSource(mSpyInsetsSource);
+
+ mController = new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl));
+ mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mState,
+ () -> mMockTransaction, mController) {
+ @Override
+ public void removeSurface() {
+ super.removeSurface();
+ mRemoveSurfaceCalled = true;
+ }
+ };
});
instrumentation.waitForIdleSync();
@@ -171,6 +180,25 @@ public class InsetsSourceConsumerTest {
mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
new int[1], hideTypes);
assertEquals(statusBars(), hideTypes[0]);
+ assertFalse(mRemoveSurfaceCalled);
+ });
+ }
+
+ @Test
+ public void testRestore_noAnimation() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mConsumer.hide();
+ mController.onStateChanged(mState);
+ mConsumer.setControl(null, new int[1], new int[1]);
+ reset(mMockTransaction);
+ verifyZeroInteractions(mMockTransaction);
+ mRemoveSurfaceCalled = false;
+ int[] hideTypes = new int[1];
+ mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
+ new int[1], hideTypes);
+ assertTrue(mRemoveSurfaceCalled);
+ assertEquals(0, hideTypes[0]);
});
+
}
}
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index 89cc6e743752..df2946c97d20 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -37,7 +37,6 @@ import static org.junit.Assert.assertTrue;
import android.app.Activity;
import android.app.Instrumentation;
import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableString;
@@ -96,7 +95,6 @@ public class EditorCursorDragTest {
mMotionEvents.clear();
}
- @Presubmit
@Test
public void testCursorDrag_horizontal_whenTextViewContentsFitOnScreen() throws Throwable {
String text = "Hello world!";
@@ -145,7 +143,7 @@ public class EditorCursorDragTest {
// Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to
// the handle as the touch moves downwards (and because we have some slop to avoid jumping
// across lines), the cursor position will end up higher than the finger position.
- onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3")));
+ onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2")));
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1")));
// Swipe right-down along a very steep diagonal path. This should not drag the cursor.
@@ -181,7 +179,7 @@ public class EditorCursorDragTest {
// Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to
// the handle as the touch moves downwards (and because we have some slop to avoid jumping
// across lines), the cursor position will end up higher than the finger position.
- onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3")));
+ onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2")));
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1")));
// Swipe right-down along a very steep diagonal path. This should not drag the cursor.
diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
index ec75e40f1334..35fd4bd7dc14 100644
--- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
+++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
@@ -326,9 +326,9 @@ public class EditorTouchStateTest {
mTouchState.update(event1, mConfig);
assertSingleTap(mTouchState, 0f, 0f, 0, 0);
- // Simulate an ACTION_MOVE event that is > 30 deg from vertical.
+ // Simulate an ACTION_MOVE event that is > 45 deg from vertical.
long event2Time = 1002;
- MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 173f);
+ MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 90f);
mTouchState.update(event2, mConfig);
assertDrag(mTouchState, 0f, 0f, 0, 0, false);
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index b7d1c9b993d9..a5117a3e7cc3 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -807,6 +807,38 @@ public class BinderCallsStatsTest {
}
}
+ @Test
+ public void testNativeTids() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats();
+ Binder binder = new Binder();
+
+ bcs.nativeTid = 3;
+
+ CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ bcs.nativeTid = 1;
+
+ callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ bcs.nativeTid = 1;
+
+ callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ bcs.nativeTid = 2;
+
+ callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ int[] tids = bcs.getNativeTids();
+ assertEquals(3, tids.length);
+ assertEquals(1, tids[0]);
+ assertEquals(2, tids[1]);
+ assertEquals(3, tids[2]);
+ }
+
private static class TestHandler extends Handler {
ArrayList<Runnable> mRunnables = new ArrayList<>();
@@ -825,6 +857,7 @@ public class BinderCallsStatsTest {
public int callingUid = CALLING_UID;
public long time = 1234;
public long elapsedTime = 0;
+ public int nativeTid;
TestBinderCallsStats() {
this(mDeviceState);
@@ -874,6 +907,10 @@ public class BinderCallsStatsTest {
protected void setCallingUid(int uid) {
callingUid = uid;
}
- }
+ @Override
+ protected int getNativeTid() {
+ return nativeTid;
+ }
+ }
}
diff --git a/data/keyboards/Vendor_1532_Product_1007.kl b/data/keyboards/Vendor_1532_Product_1007.kl
new file mode 100644
index 000000000000..6f6c286b34a5
--- /dev/null
+++ b/data/keyboards/Vendor_1532_Product_1007.kl
@@ -0,0 +1,65 @@
+# 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.
+
+#
+# Razer Raiju Tournament Edition Controller with wired USB interface.
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x130 BUTTON_X
+# Cross
+key 0x131 BUTTON_A
+# Circle
+key 0x132 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x134 BUTTON_L1
+key 0x135 BUTTON_R1
+key 0x136 BUTTON_L2
+key 0x137 BUTTON_R2
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x02 Z
+axis 0x05 RZ
+
+# L2 axis
+axis 0x09 RTRIGGER
+# R2 axis
+axis 0x0a LTRIGGER
+
+# Left stick click
+key 0x13a BUTTON_THUMBL
+# Right stick click
+key 0x13b BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x138 BUTTON_SELECT
+# Options
+key 0x139 BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# Touchpad press
+key 0x13d BUTTON_1
diff --git a/data/keyboards/Vendor_1532_Product_100a.kl b/data/keyboards/Vendor_1532_Product_100a.kl
new file mode 100644
index 000000000000..b0e966d519b3
--- /dev/null
+++ b/data/keyboards/Vendor_1532_Product_100a.kl
@@ -0,0 +1,65 @@
+# 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.
+
+#
+# Razer Raiju Tournament Edition Controller with wireless Bluetooth interface.
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+# Square
+key 0x130 BUTTON_X
+# Cross
+key 0x131 BUTTON_A
+# Circle
+key 0x132 BUTTON_B
+# Triangle
+key 0x133 BUTTON_Y
+
+key 0x134 BUTTON_L1
+key 0x135 BUTTON_R1
+key 0x136 BUTTON_L2
+key 0x137 BUTTON_R2
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x02 Z
+axis 0x05 RZ
+
+# L2 axis
+axis 0x09 RTRIGGER
+# R2 axis
+axis 0x0a LTRIGGER
+
+# Left stick click
+key 0x13a BUTTON_THUMBL
+# Right stick click
+key 0x13b BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Share
+key 0x138 BUTTON_SELECT
+# Options
+key 0x139 BUTTON_START
+# PS key
+key 0x13c BUTTON_MODE
+
+# Touchpad press
+key 0x13d BUTTON_1
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 3b494e9129db..5e480a66c355 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -24,30 +24,9 @@
#include <log/log.h>
-namespace android {
-
-// --- WeakLooperCallback ---
-
-class WeakLooperCallback: public LooperCallback {
-protected:
- virtual ~WeakLooperCallback() { }
-
-public:
- explicit WeakLooperCallback(const wp<LooperCallback>& callback) :
- mCallback(callback) {
- }
+#include <memory>
- virtual int handleEvent(int fd, int events, void* data) {
- sp<LooperCallback> callback = mCallback.promote();
- if (callback != NULL) {
- return callback->handleEvent(fd, events, data);
- }
- return 0; // the client is gone, remove the callback
- }
-
-private:
- wp<LooperCallback> mCallback;
-};
+namespace android {
// --- PointerController ---
@@ -64,29 +43,50 @@ static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
// The number of events to be read at once for DisplayEventReceiver.
static const int EVENT_BUFFER_SIZE = 100;
-// --- PointerController ---
-
-PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
- mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
- mHandler = new WeakMessageHandler(this);
- mCallback = new WeakLooperCallback(this);
-
- if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
- mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
- Looper::EVENT_INPUT, mCallback, nullptr);
+std::shared_ptr<PointerController> PointerController::create(
+ const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController) {
+ std::shared_ptr<PointerController> controller = std::shared_ptr<PointerController>(
+ new PointerController(policy, looper, spriteController));
+
+ /*
+ * Now we need to hook up the constructed PointerController object to its callbacks.
+ *
+ * This must be executed after the constructor but before any other methods on PointerController
+ * in order to ensure that the fully constructed object is visible on the Looper thread, since
+ * that may be a different thread than where the PointerController is initially constructed.
+ *
+ * Unfortunately, this cannot be done as part of the constructor since we need to hand out
+ * weak_ptr's which themselves cannot be constructed until there's at least one shared_ptr.
+ */
+
+ controller->mHandler->pointerController = controller;
+ controller->mCallback->pointerController = controller;
+ if (controller->mDisplayEventReceiver.initCheck() == NO_ERROR) {
+ controller->mLooper->addFd(controller->mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
+ Looper::EVENT_INPUT, controller->mCallback, nullptr);
} else {
ALOGE("Failed to initialize DisplayEventReceiver.");
}
+ return controller;
+}
+PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
+ const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController)
+ : mPolicy(policy),
+ mLooper(looper),
+ mSpriteController(spriteController),
+ mHandler(new MessageHandler()),
+ mCallback(new LooperCallback()) {
AutoMutex _l(mLock);
mLocked.animationPending = false;
- mLocked.presentation = PRESENTATION_POINTER;
+ mLocked.presentation = Presentation::POINTER;
mLocked.presentationChanged = false;
- mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL;
+ mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
mLocked.pointerFadeDirection = 0;
mLocked.pointerX = 0;
@@ -221,7 +221,7 @@ void PointerController::fade(Transition transition) {
removeInactivityTimeoutLocked();
// Start fading.
- if (transition == TRANSITION_IMMEDIATE) {
+ if (transition == Transition::IMMEDIATE) {
mLocked.pointerFadeDirection = 0;
mLocked.pointerAlpha = 0.0f;
updatePointerLocked();
@@ -238,7 +238,7 @@ void PointerController::unfade(Transition transition) {
resetInactivityTimeoutLocked();
// Start unfading.
- if (transition == TRANSITION_IMMEDIATE) {
+ if (transition == Transition::IMMEDIATE) {
mLocked.pointerFadeDirection = 0;
mLocked.pointerAlpha = 1.0f;
updatePointerLocked();
@@ -262,7 +262,7 @@ void PointerController::setPresentation(Presentation presentation) {
return;
}
- if (presentation == PRESENTATION_POINTER) {
+ if (presentation == Presentation::POINTER) {
if (mLocked.additionalMouseResources.empty()) {
mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
&mLocked.animationResources,
@@ -480,24 +480,35 @@ void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
updatePointerLocked();
}
-void PointerController::handleMessage(const Message& message) {
+void PointerController::MessageHandler::handleMessage(const Message& message) {
+ std::shared_ptr<PointerController> controller = pointerController.lock();
+
+ if (controller == nullptr) {
+ ALOGE("PointerController instance was released before processing message: what=%d",
+ message.what);
+ return;
+ }
switch (message.what) {
case MSG_INACTIVITY_TIMEOUT:
- doInactivityTimeout();
+ controller->doInactivityTimeout();
break;
}
}
-int PointerController::handleEvent(int /* fd */, int events, void* /* data */) {
+int PointerController::LooperCallback::handleEvent(int /* fd */, int events, void* /* data */) {
+ std::shared_ptr<PointerController> controller = pointerController.lock();
+ if (controller == nullptr) {
+ ALOGW("PointerController instance was released with pending callbacks. events=0x%x",
+ events);
+ return 0; // Remove the callback, the PointerController is gone anyways
+ }
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
- ALOGE("Display event receiver pipe was closed or an error occurred. "
- "events=0x%x", events);
+ ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x", events);
return 0; // remove the callback
}
if (!(events & Looper::EVENT_INPUT)) {
- ALOGW("Received spurious callback for unhandled poll event. "
- "events=0x%x", events);
+ ALOGW("Received spurious callback for unhandled poll event. events=0x%x", events);
return 1; // keep the callback
}
@@ -505,7 +516,7 @@ int PointerController::handleEvent(int /* fd */, int events, void* /* data */) {
ssize_t n;
nsecs_t timestamp;
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
- while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
+ while ((n = controller->mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
timestamp = buf[i].header.timestamp;
@@ -514,7 +525,7 @@ int PointerController::handleEvent(int /* fd */, int events, void* /* data */) {
}
}
if (gotVsync) {
- doAnimate(timestamp);
+ controller->doAnimate(timestamp);
}
return 1; // keep the callback
}
@@ -613,7 +624,7 @@ bool PointerController::doBitmapAnimationLocked(nsecs_t timestamp) {
}
void PointerController::doInactivityTimeout() {
- fade(TRANSITION_GRADUAL);
+ fade(Transition::GRADUAL);
}
void PointerController::startAnimationLocked() {
@@ -627,8 +638,9 @@ void PointerController::startAnimationLocked() {
void PointerController::resetInactivityTimeoutLocked() {
mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
- nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT
- ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
+ nsecs_t timeout = mLocked.inactivityTimeout == InactivityTimeout::SHORT
+ ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT
+ : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
}
@@ -655,7 +667,7 @@ void PointerController::updatePointerLocked() REQUIRES(mLock) {
}
if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
- if (mLocked.presentation == PRESENTATION_POINTER) {
+ if (mLocked.presentation == Presentation::POINTER) {
if (mLocked.requestedPointerType == mPolicy->getDefaultPointerIconId()) {
mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
} else {
@@ -731,7 +743,7 @@ PointerController::Spot* PointerController::removeFirstFadingSpotLocked(std::vec
return spot;
}
}
- return NULL;
+ return nullptr;
}
void PointerController::releaseSpotLocked(Spot* spot) {
@@ -772,7 +784,7 @@ void PointerController::loadResourcesLocked() REQUIRES(mLock) {
mLocked.additionalMouseResources.clear();
mLocked.animationResources.clear();
- if (mLocked.presentation == PRESENTATION_POINTER) {
+ if (mLocked.presentation == Presentation::POINTER) {
mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
&mLocked.animationResources, mLocked.viewport.displayId);
}
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index ebc622bae302..14c0679654c6 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -17,19 +17,20 @@
#ifndef _UI_POINTER_CONTROLLER_H
#define _UI_POINTER_CONTROLLER_H
-#include "SpriteController.h"
-
-#include <map>
-#include <vector>
-
-#include <ui/DisplayInfo.h>
+#include <PointerControllerInterface.h>
+#include <gui/DisplayEventReceiver.h>
#include <input/DisplayViewport.h>
#include <input/Input.h>
-#include <PointerControllerInterface.h>
+#include <ui/DisplayInfo.h>
#include <utils/BitSet.h>
-#include <utils/RefBase.h>
#include <utils/Looper.h>
-#include <gui/DisplayEventReceiver.h>
+#include <utils/RefBase.h>
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "SpriteController.h"
namespace android {
@@ -70,25 +71,22 @@ public:
virtual int32_t getCustomPointerIconId() = 0;
};
-
/*
* Tracks pointer movements and draws the pointer sprite to a surface.
*
* Handles pointer acceleration and animation.
*/
-class PointerController : public PointerControllerInterface, public MessageHandler,
- public LooperCallback {
-protected:
- virtual ~PointerController();
-
+class PointerController : public PointerControllerInterface {
public:
- enum InactivityTimeout {
- INACTIVITY_TIMEOUT_NORMAL = 0,
- INACTIVITY_TIMEOUT_SHORT = 1,
+ static std::shared_ptr<PointerController> create(
+ const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController);
+ enum class InactivityTimeout {
+ NORMAL = 0,
+ SHORT = 1,
};
- PointerController(const sp<PointerControllerPolicyInterface>& policy,
- const sp<Looper>& looper, const sp<SpriteController>& spriteController);
+ virtual ~PointerController();
virtual bool getBounds(float* outMinX, float* outMinY,
float* outMaxX, float* outMaxY) const;
@@ -113,8 +111,8 @@ public:
void reloadPointerResources();
private:
- static const size_t MAX_RECYCLED_SPRITES = 12;
- static const size_t MAX_SPOTS = 12;
+ static constexpr size_t MAX_RECYCLED_SPRITES = 12;
+ static constexpr size_t MAX_SPOTS = 12;
enum {
MSG_INACTIVITY_TIMEOUT,
@@ -130,8 +128,13 @@ private:
float x, y;
inline Spot(uint32_t id, const sp<Sprite>& sprite)
- : id(id), sprite(sprite), alpha(1.0f), scale(1.0f),
- x(0.0f), y(0.0f), lastIcon(NULL) { }
+ : id(id),
+ sprite(sprite),
+ alpha(1.0f),
+ scale(1.0f),
+ x(0.0f),
+ y(0.0f),
+ lastIcon(nullptr) {}
void updateSprite(const SpriteIcon* icon, float x, float y, int32_t displayId);
@@ -139,12 +142,24 @@ private:
const SpriteIcon* lastIcon;
};
+ class MessageHandler : public virtual android::MessageHandler {
+ public:
+ void handleMessage(const Message& message) override;
+ std::weak_ptr<PointerController> pointerController;
+ };
+
+ class LooperCallback : public virtual android::LooperCallback {
+ public:
+ int handleEvent(int fd, int events, void* data) override;
+ std::weak_ptr<PointerController> pointerController;
+ };
+
mutable Mutex mLock;
sp<PointerControllerPolicyInterface> mPolicy;
sp<Looper> mLooper;
sp<SpriteController> mSpriteController;
- sp<WeakMessageHandler> mHandler;
+ sp<MessageHandler> mHandler;
sp<LooperCallback> mCallback;
DisplayEventReceiver mDisplayEventReceiver;
@@ -181,14 +196,15 @@ private:
int32_t buttonState;
std::map<int32_t /* displayId */, std::vector<Spot*>> spotsByDisplay;
- std::vector<sp<Sprite> > recycledSprites;
+ std::vector<sp<Sprite>> recycledSprites;
} mLocked GUARDED_BY(mLock);
+ PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController);
+
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
void setPositionLocked(float x, float y);
- void handleMessage(const Message& message);
- int handleEvent(int fd, int events, void* data);
void doAnimate(nsecs_t timestamp);
bool doFadingAnimationLocked(nsecs_t timestamp);
bool doBitmapAnimationLocked(nsecs_t timestamp);
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index a15742671dc7..6e129a064385 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -136,7 +136,7 @@ protected:
sp<MockSprite> mPointerSprite;
sp<MockPointerControllerPolicyInterface> mPolicy;
sp<MockSpriteController> mSpriteController;
- sp<PointerController> mPointerController;
+ std::shared_ptr<PointerController> mPointerController;
private:
void loopThread();
@@ -160,7 +160,7 @@ PointerControllerTest::PointerControllerTest() : mPointerSprite(new NiceMock<Moc
EXPECT_CALL(*mSpriteController, createSprite())
.WillOnce(Return(mPointerSprite));
- mPointerController = new PointerController(mPolicy, mLooper, mSpriteController);
+ mPointerController = PointerController::create(mPolicy, mLooper, mSpriteController);
}
PointerControllerTest::~PointerControllerTest() {
@@ -193,7 +193,7 @@ void PointerControllerTest::loopThread() {
TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
ensureDisplayViewportIsSet();
- mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+ mPointerController->unfade(PointerController::Transition::IMMEDIATE);
std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT);
EXPECT_CALL(*mPointerSprite, setVisible(true));
@@ -208,7 +208,7 @@ TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
TEST_F(PointerControllerTest, updatePointerIcon) {
ensureDisplayViewportIsSet();
- mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+ mPointerController->unfade(PointerController::Transition::IMMEDIATE);
int32_t type = CURSOR_TYPE_ADDITIONAL;
std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type);
@@ -224,7 +224,7 @@ TEST_F(PointerControllerTest, updatePointerIcon) {
TEST_F(PointerControllerTest, setCustomPointerIcon) {
ensureDisplayViewportIsSet();
- mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
+ mPointerController->unfade(PointerController::Transition::IMMEDIATE);
int32_t style = CURSOR_TYPE_CUSTOM;
float hotSpotX = 15;
@@ -246,13 +246,13 @@ TEST_F(PointerControllerTest, setCustomPointerIcon) {
}
TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) {
- mPointerController->setPresentation(PointerController::PRESENTATION_POINTER);
+ mPointerController->setPresentation(PointerController::Presentation::POINTER);
mPointerController->setSpots(nullptr, nullptr, BitSet32(), -1);
mPointerController->clearSpots();
mPointerController->setPosition(1.0f, 1.0f);
mPointerController->move(1.0f, 1.0f);
- mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE);
- mPointerController->fade(PointerController::TRANSITION_IMMEDIATE);
+ mPointerController->unfade(PointerController::Transition::IMMEDIATE);
+ mPointerController->fade(PointerController::Transition::IMMEDIATE);
EXPECT_TRUE(mPolicy->noResourcesAreLoaded());
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index fed65c971f7e..c0b8e1bf3bbe 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -260,7 +260,9 @@ public class LocationManager {
* {@code OP_MONITOR_HIGH_POWER_LOCATION}.
*
* @hide
+ * @deprecated This action is unnecessary from Android S forward.
*/
+ @Deprecated
public static final String HIGH_POWER_REQUEST_CHANGE_ACTION =
"android.location.HIGH_POWER_REQUEST_CHANGE";
@@ -1855,7 +1857,8 @@ public class LocationManager {
"GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
- getGnssStatusTransportMultiplexer().addListener(listener, DIRECT_EXECUTOR);
+ getGnssStatusTransportMultiplexer().addListener(listener,
+ new HandlerExecutor(new Handler()));
return true;
}
@@ -1974,7 +1977,7 @@ public class LocationManager {
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addNmeaListener(@NonNull OnNmeaMessageListener listener) {
- return addNmeaListener(DIRECT_EXECUTOR, listener);
+ return addNmeaListener(listener, null);
}
/**
diff --git a/media/java/android/media/MediaFrameworkInitializer.java b/media/java/android/media/MediaFrameworkInitializer.java
new file mode 100644
index 000000000000..577442ec42e4
--- /dev/null
+++ b/media/java/android/media/MediaFrameworkInitializer.java
@@ -0,0 +1,74 @@
+/*
+ * 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 android.media;
+
+import android.annotation.NonNull;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+import android.media.session.MediaSessionManager;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Class for performing registration for all media services
+ *
+ * TODO (b/160513103): Move this class when moving media service code to APEX
+ * @hide
+ */
+public class MediaFrameworkInitializer {
+ private MediaFrameworkInitializer() {
+ }
+
+ private static volatile MediaServiceManager sMediaServiceManager;
+
+ /**
+ * Sets an instance of {@link MediaServiceManager} that allows
+ * the media mainline module to register/obtain media binder services. This is called
+ * by the platform during the system initialization.
+ *
+ * @param mediaServiceManager instance of {@link MediaServiceManager} that allows
+ * the media mainline module to register/obtain media binder services.
+ */
+ public static void setMediaServiceManager(
+ @NonNull MediaServiceManager mediaServiceManager) {
+ Preconditions.checkState(sMediaServiceManager == null,
+ "setMediaServiceManager called twice!");
+ sMediaServiceManager = Objects.requireNonNull(mediaServiceManager);
+ }
+
+ /** @hide */
+ public static MediaServiceManager getMediaServiceManager() {
+ return sMediaServiceManager;
+ }
+
+ /**
+ * Called by {@link SystemServiceRegistry}'s static initializer and registers all media
+ * services to {@link Context}, so that {@link Context#getSystemService} can return them.
+ *
+ * @throws IllegalStateException if this is called from anywhere besides
+ * {@link SystemServiceRegistry}
+ */
+ public static void registerServiceWrappers() {
+ SystemServiceRegistry.registerContextAwareService(
+ Context.MEDIA_SESSION_SERVICE,
+ MediaSessionManager.class,
+ context -> new MediaSessionManager(context)
+ );
+ }
+}
diff --git a/media/java/android/media/MediaServiceManager.java b/media/java/android/media/MediaServiceManager.java
new file mode 100644
index 000000000000..21e2d84b0200
--- /dev/null
+++ b/media/java/android/media/MediaServiceManager.java
@@ -0,0 +1,68 @@
+/*
+ * 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 android.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * Provides a way to register and obtain the system service binder objects managed by the media
+ * service.
+ *
+ * <p> Only the media mainline module will be able to access an instance of this class.
+ * @hide
+ */
+public class MediaServiceManager {
+ /**
+ * @hide
+ */
+ public MediaServiceManager() {}
+
+ /**
+ * A class that exposes the methods to register and obtain each system service.
+ */
+ public static final class ServiceRegisterer {
+ private final String mServiceName;
+
+ /**
+ * @hide
+ */
+ public ServiceRegisterer(String serviceName) {
+ mServiceName = serviceName;
+ }
+
+ /**
+ * Get the system server binding object for MediaServiceManager.
+ *
+ * <p> This blocks until the service instance is ready.
+ * or a timeout happens, in which case it returns null.
+ */
+ @Nullable
+ public IBinder get() {
+ return ServiceManager.getService(mServiceName);
+ }
+ }
+
+ /**
+ * Returns {@link ServiceRegisterer} for the "media_session" service.
+ */
+ @NonNull
+ public ServiceRegisterer getMediaSessionServiceRegisterer() {
+ return new ServiceRegisterer("media_session");
+ }
+}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 2fd721e6870b..6976a3569655 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -28,14 +28,13 @@ import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.media.AudioManager;
import android.media.IRemoteVolumeController;
+import android.media.MediaFrameworkInitializer;
import android.media.MediaSession2;
import android.media.Session2Token;
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.service.media.MediaBrowserService;
import android.service.notification.NotificationListenerService;
@@ -115,8 +114,10 @@ public final class MediaSessionManager {
// Consider rewriting like DisplayManagerGlobal
// Decide if we need context
mContext = context;
- IBinder b = ServiceManager.getService(Context.MEDIA_SESSION_SERVICE);
- mService = ISessionManager.Stub.asInterface(b);
+ mService = ISessionManager.Stub.asInterface(MediaFrameworkInitializer
+ .getMediaServiceManager()
+ .getMediaSessionServiceRegisterer()
+ .get());
}
/**
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 515d610109ab..df022d562768 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -447,7 +447,7 @@ jobjectArray FilterCallback::getMediaEvent(
if (mediaEvent.avMemory.getNativeHandle() != NULL || mediaEvent.avDataId != 0) {
sp<MediaEvent> mediaEventSp =
new MediaEvent(mIFilter, mediaEvent.avMemory,
- mediaEvent.avDataId, dataLength, obj);
+ mediaEvent.avDataId, dataLength + offset, obj);
mediaEventSp->mAvHandleRefCnt++;
env->SetLongField(obj, eventContext, (jlong) mediaEventSp.get());
mediaEventSp->incStrong(obj);
diff --git a/media/tests/MediaTranscodingTest/build_and_run_unit_tests.sh b/media/tests/MediaTranscodingTest/build_and_run_unit_tests.sh
index b709c5f97b77..43db3530a16b 100644
--- a/media/tests/MediaTranscodingTest/build_and_run_unit_tests.sh
+++ b/media/tests/MediaTranscodingTest/build_and_run_unit_tests.sh
@@ -13,9 +13,6 @@ fi
mm
-# Push the files onto the device.
-. $ANDROID_BUILD_TOP/frameworks/av/media/libmediatranscoding/tests/assets/push_assets.sh
-
echo "[==========] waiting for device"
adb root && adb wait-for-device remount
@@ -27,6 +24,13 @@ echo "[==========] build test apk"
mmm -j16 .
adb install -r -g ${OUT}/testcases/mediatranscodingtest/arm64/mediatranscodingtest.apk
+# Push the files into app's cache directory/
+FILES=$ANDROID_BUILD_TOP/frameworks/av/media/libmediatranscoding/tests/assets/*
+for file in $FILES
+do
+adb push --sync $file /data/user/0/com.android.mediatranscodingtest/cache/
+done
+
echo "[==========] running real transcoding tests"
adb shell am instrument -e class com.android.mediatranscodingtest.MediaTranscodeManagerTest -w com.android.mediatranscodingtest/.MediaTranscodingTestRunner
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
index e5952fb44ac1..3a5e69293a02 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
@@ -67,7 +67,7 @@ public class MediaTranscodeManagerTest
// Setting for transcoding to H.264.
private static final String MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
- private static final int BIT_RATE = 2000000; // 2Mbps
+ private static final int BIT_RATE = 20000000; // 20Mbps
private static final int WIDTH = 1920;
private static final int HEIGHT = 1080;
@@ -177,7 +177,7 @@ public class MediaTranscodeManagerTest
assertNotNull(job);
if (job != null) {
- Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to complete.");
+ Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to cancel.");
boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
assertTrue("Transcode failed to complete in time.", finishedOnTime);
@@ -192,5 +192,43 @@ public class MediaTranscodeManagerTest
stats.mAveragePSNR >= PSNR_THRESHOLD);
}
+ @Test
+ public void testCancelTranscoding() throws Exception {
+ Log.d(TAG, "Starting: testMediaTranscodeManager");
+ Semaphore transcodeCompleteSemaphore = new Semaphore(0);
+
+ // Transcode a 15 seconds video, so that the transcoding is not finished when we cancel.
+ Uri srcUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
+ + mContext.getCacheDir().getAbsolutePath() + "/longtest_15s.mp4");
+ Uri destinationUri = Uri.parse(ContentResolver.SCHEME_FILE + "://"
+ + mContext.getCacheDir().getAbsolutePath() + "/HevcTranscode.mp4");
+
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(srcUri)
+ .setDestinationUri(destinationUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ Executor listenerExecutor = Executors.newSingleThreadExecutor();
+
+ TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor,
+ transcodingJob -> {
+ Log.d(TAG, "Transcoding completed with result: " + transcodingJob.getResult());
+ assertEquals(transcodingJob.getResult(), TranscodingJob.RESULT_CANCELED);
+ transcodeCompleteSemaphore.release();
+ });
+ assertNotNull(job);
+
+ // TODO(hkuang): Wait for progress update before calling cancel to make sure transcoding is
+ // started.
+
+ job.cancel();
+ Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to cancel.");
+ boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
+ 30, TimeUnit.MILLISECONDS);
+ assertTrue("Fails to cancel transcoding", finishedOnTime);
+ }
}
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
new file mode 100644
index 000000000000..ee06720327bc
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
@@ -0,0 +1,182 @@
+/*
+ * 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.mediatranscodingtest;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.media.MediaFormat;
+import android.media.MediaTranscodeManager;
+import android.media.MediaTranscodeManager.TranscodingJob;
+import android.media.MediaTranscodeManager.TranscodingRequest;
+import android.net.Uri;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+/*
+ * Benchmarking for MediaTranscodeManager in the media framework.
+ *
+ * Note: This benchmarking requires to push all the files from http://go/transcodingbenchmark
+ * to /data/user/0/com.android.mediatranscodingtest/cache/ directory after installing the apk.
+ *
+ * TODO(hkuang): Change it to download from server automatically instead of manually.
+ *
+ * To run this test suite:
+ make frameworks/base/media/tests/MediaTranscodingTest
+ make mediatranscodingtest
+
+ adb install -r testcases/mediatranscodingtest/arm64/mediatranscodingtest.apk
+ // Push the files to /data/user/0/com.android.mediatranscodingtest/cache/
+ adb push $DOWNLOADPATH/*.mp4 /data/user/0/com.android.mediatranscodingtest/cache/
+
+ adb shell am instrument -e class \
+ com.android.mediatranscodingtest.MediaTranscodingBenchmark \
+ -w com.android.mediatranscodingtest/.MediaTranscodingTestRunner
+ *
+ */
+public class MediaTranscodingBenchmark
+ extends ActivityInstrumentationTestCase2<MediaTranscodingTest> {
+ private static final String TAG = "MediaTranscodingBenchmark";
+ // TODO(hkuang): Change this to query from MediaCodecInfo.CodecCapabilities for different
+ // resolution.
+ private static final int MINIMUM_TRANSCODING_FPS = 80;
+ private static final int LOOP_COUNT = 10;
+ // Default Setting for transcoding to H.264.
+ private static final String MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
+ private static final int BIT_RATE = 20000000; // 20Mbps
+ private static final int WIDTH = 1920;
+ private static final int HEIGHT = 1080;
+ private Context mContext;
+ private MediaTranscodeManager mMediaTranscodeManager = null;
+
+ public MediaTranscodingBenchmark() {
+ super("com.android.MediaTranscodingBenchmark", MediaTranscodingTest.class);
+ }
+
+ /**
+ * Creates a MediaFormat with the basic set of values.
+ */
+ private static MediaFormat createMediaFormat() {
+ MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, WIDTH, HEIGHT);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
+ return format;
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ Log.d(TAG, "setUp");
+ super.setUp();
+ mContext = getInstrumentation().getContext();
+ mMediaTranscodeManager = MediaTranscodeManager.getInstance(mContext);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /*
+ * Transcode the sourceFileName to destinationFileName with LOOP_COUNT.
+ */
+ private void transcode(final String sourceFileName, final String destinationFileName)
+ throws IOException, InterruptedException {
+ AtomicLong totalTimeMs = new AtomicLong();
+ AtomicLong transcodingTime = new AtomicLong();
+ Uri srcUri = getUri(sourceFileName);
+ Uri dstUri = getUri(destinationFileName);
+
+ MediaTranscodingTestUtil.VideoFileInfo info =
+ MediaTranscodingTestUtil.extractVideoFileInfo(mContext, getUri(sourceFileName));
+ int timeoutSeconds = calMaxTranscodingWaitTimeSeconds(info.mNumVideoFrames,
+ MINIMUM_TRANSCODING_FPS);
+ Log.d(TAG, "Start Transcoding " + info.toString() + " " + timeoutSeconds);
+
+ for (int loop = 0; loop < LOOP_COUNT; ++loop) {
+ Semaphore transcodeCompleteSemaphore = new Semaphore(0);
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(srcUri)
+ .setDestinationUri(dstUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ Executor listenerExecutor = Executors.newSingleThreadExecutor();
+
+ long startTimeMs = System.currentTimeMillis();
+ TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor,
+ transcodingJob -> {
+ Log.d(TAG,
+ "Transcoding completed with result: " + transcodingJob.getResult());
+ assertEquals(transcodingJob.getResult(), TranscodingJob.RESULT_SUCCESS);
+ transcodeCompleteSemaphore.release();
+ transcodingTime.set(System.currentTimeMillis() - startTimeMs);
+ totalTimeMs.addAndGet(transcodingTime.get());
+ });
+
+ if (job != null) {
+ Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to complete.");
+ boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
+ timeoutSeconds, TimeUnit.SECONDS);
+ assertTrue("Transcode failed to complete in time.", finishedOnTime);
+ }
+ Log.i(TAG, "Loop: " + loop + " take " + transcodingTime.get() + " ms ");
+ }
+
+ float fps = info.mNumVideoFrames * 1000 * LOOP_COUNT / totalTimeMs.get();
+ Log.i(TAG, "Transcoding " + info.toString() + " Transcoding fps: " + fps);
+ }
+
+ // Calculate the maximum wait time based on minimum transcoding throughput and frame number.
+ private int calMaxTranscodingWaitTimeSeconds(int numberFrames, int minTranscodingFps) {
+ int waitTimeSeconds = numberFrames / minTranscodingFps;
+ // If waitTimeSeconds is 0, wait for 1 seconds at least.
+ return waitTimeSeconds == 0 ? 1 : waitTimeSeconds;
+ }
+
+ private Uri getUri(final String fileName) {
+ String path = mContext.getCacheDir().getAbsolutePath();
+ return new Uri.Builder().scheme(ContentResolver.SCHEME_FILE).appendPath(path).appendPath(
+ fileName).build();
+ }
+
+ @Test
+ public void testBenchmarkingAVCToAVCWith66FramesWithoutAudio() throws Exception {
+ String videoNameWithoutExtension = "video_1920x1080_66frame_h264_22Mbps_30fps";
+ String testVideoName = videoNameWithoutExtension + ".mp4";
+ String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
+
+ transcode(testVideoName, transcodedVideoName);
+ }
+
+ @Test
+ public void testBenchmarkingAVCToAVCWith66FramesWithAudio() throws Exception {
+ String videoNameWithoutExtension = "video_1920x1080_66frame_h264_22Mbps_30fps_aac";
+ String testVideoName = videoNameWithoutExtension + ".mp4";
+ String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
+
+ transcode(testVideoName, transcodedVideoName);
+ }
+}
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java
index 3b044c7e3707..53b23927fc64 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java
@@ -38,6 +38,7 @@ public class MediaTranscodingTestRunner extends InstrumentationTestRunner {
TestSuite suite = new InstrumentationTestSuite(this);
suite.addTestSuite(MediaTranscodeManagerTest.class);
suite.addTestSuite(MediaTranscodeManagerWithMockServiceTest.class);
+ suite.addTestSuite(MediaTranscodingBenchmark.class);
return suite;
}
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestUtil.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestUtil.java
index a1c32512f94a..69f124f42abd 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestUtil.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestUtil.java
@@ -27,6 +27,7 @@ import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
+import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.util.Log;
import android.util.Size;
@@ -42,6 +43,75 @@ import java.util.Locale;
/* package */ class MediaTranscodingTestUtil {
private static final String TAG = "MediaTranscodingTestUtil";
+ // Helper class to extract the information from source file and transcoded file.
+ static class VideoFileInfo {
+ String mUri;
+ int mNumVideoFrames = 0;
+ int mWidth = 0;
+ int mHeight = 0;
+ float mVideoFrameRate = 0.0f;
+ boolean mHasAudio = false;
+
+ public String toString() {
+ String str = mUri;
+ str += " Width:" + mWidth;
+ str += " Height:" + mHeight;
+ str += " FrameRate:" + mWidth;
+ str += " FrameCount:" + mNumVideoFrames;
+ str += " HasAudio:" + (mHasAudio ? "Yes" : "No");
+ return str;
+ }
+ }
+
+ static VideoFileInfo extractVideoFileInfo(Context ctx, Uri videoUri) throws IOException {
+ VideoFileInfo info = new VideoFileInfo();
+ AssetFileDescriptor afd = null;
+ MediaMetadataRetriever retriever = null;
+
+ try {
+ afd = ctx.getContentResolver().openAssetFileDescriptor(videoUri, "r");
+ retriever = new MediaMetadataRetriever();
+ retriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+
+ info.mUri = videoUri.getLastPathSegment();
+ Log.i(TAG, "Trying to transcode to " + info.mUri);
+ String width = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
+ String height = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
+ if (width != null && height != null) {
+ info.mWidth = Integer.parseInt(width);
+ info.mHeight = Integer.parseInt(height);
+ }
+
+ String frameRate = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_CAPTURE_FRAMERATE);
+ if (frameRate != null) {
+ info.mVideoFrameRate = Float.parseFloat(frameRate);
+ }
+
+ String frameCount = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT);
+ if (frameCount != null) {
+ info.mNumVideoFrames = Integer.parseInt(frameCount);
+ }
+
+ String hasAudio = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_HAS_AUDIO);
+ if (hasAudio != null) {
+ info.mHasAudio = hasAudio.equals("yes");
+ }
+ } finally {
+ if (retriever != null) {
+ retriever.close();
+ }
+ if (afd != null) {
+ afd.close();
+ }
+ }
+ return info;
+ }
+
static VideoTranscodingStatistics computeStats(final Context ctx, final Uri sourceMp4,
final Uri transcodedMp4)
throws Exception {
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 32b33a758535..8598f74e1441 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -49,7 +49,7 @@ android_library {
"androidx.lifecycle_lifecycle-extensions",
"SystemUI-tags",
"SystemUI-proto",
- "dagger2-2.19",
+ "dagger2",
"//external/kotlinc:kotlin-annotations",
],
@@ -59,7 +59,7 @@ android_library {
manifest: "AndroidManifest.xml",
- plugins: ["dagger2-compiler-2.19"],
+ plugins: ["dagger2-compiler"],
}
@@ -104,7 +104,7 @@ android_library {
"mockito-target-inline-minus-junit4",
"testables",
"truth-prebuilt",
- "dagger2-2.19",
+ "dagger2",
"//external/kotlinc:kotlin-annotations",
],
libs: [
@@ -118,7 +118,7 @@ android_library {
"com.android.systemui",
],
- plugins: ["dagger2-compiler-2.19"],
+ plugins: ["dagger2-compiler"],
}
android_app {
@@ -157,7 +157,7 @@ android_app {
kotlincflags: ["-Xjvm-default=enable"],
- plugins: ["dagger2-compiler-2.19"],
+ plugins: ["dagger2-compiler"],
required: ["privapp_whitelist_com.android.systemui"],
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 5bf989a971b9..496742680893 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -67,6 +67,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.volume.VolumeDialogComponent;
+import com.android.systemui.wm.DisplayImeController;
+import com.android.systemui.wm.DisplaySystemBarsController;
import javax.inject.Named;
import javax.inject.Singleton;
@@ -97,6 +99,10 @@ public abstract class CarSystemUIModule {
groupManager, configurationController);
}
+ @Binds
+ abstract DisplayImeController bindDisplayImeController(
+ DisplaySystemBarsController displaySystemBarsController);
+
@Singleton
@Provides
@Named(LEAK_REPORT_EMAIL_NAME)
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
new file mode 100644
index 000000000000..5f9665ff7632
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
@@ -0,0 +1,250 @@
+/*
+ * 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.systemui.wm;
+
+import android.car.settings.CarSettings;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.view.WindowInsets;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Util class to load PolicyControl and allow for querying if a package matches immersive filters.
+ * Similar to {@link com.android.server.wm.PolicyControl}, but separate due to CarSystemUI needing
+ * to set its own policies for system bar visibilities.
+ *
+ * This forces immersive mode behavior for one or both system bars (based on a package
+ * list).
+ *
+ * Control by setting {@link Settings.Global#POLICY_CONTROL_AUTO} to one or more name-value pairs.
+ * e.g.
+ * to force immersive mode everywhere:
+ * "immersive.full=*"
+ * to force hide status bars for com.package1 but not com.package2:
+ * "immersive.status=com.package1,-com.package2"
+ *
+ * Separate multiple name-value pairs with ':'
+ * e.g. "immersive.status=com.package:immersive.navigation=*"
+ */
+public class BarControlPolicy {
+
+ private static final String TAG = "BarControlPolicy";
+ private static final boolean DEBUG = false;
+
+ private static final String NAME_IMMERSIVE_FULL = "immersive.full";
+ private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
+ private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
+
+ @VisibleForTesting
+ static String sSettingValue;
+ @VisibleForTesting
+ static Filter sImmersiveStatusFilter;
+ private static Filter sImmersiveNavigationFilter;
+
+ /** Loads values from the POLICY_CONTROL setting to set filters. */
+ static boolean reloadFromSetting(Context context) {
+ if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
+ String value = null;
+ try {
+ value = Settings.Global.getStringForUser(context.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ UserHandle.USER_CURRENT);
+ if (sSettingValue == value || sSettingValue != null && sSettingValue.equals(value)) {
+ return false;
+ }
+ setFilters(value);
+ sSettingValue = value;
+ } catch (Throwable t) {
+ Slog.w(TAG, "Error loading policy control, value=" + value, t);
+ return false;
+ }
+ return true;
+ }
+
+ /** Used in testing to reset BarControlPolicy. */
+ @VisibleForTesting
+ static void reset() {
+ sSettingValue = null;
+ sImmersiveStatusFilter = null;
+ sImmersiveNavigationFilter = null;
+ }
+
+ /**
+ * Registers a content observer to listen to updates to the SYSTEM_BAR_VISIBILITY_OVERRIDE flag.
+ */
+ static void registerContentObserver(Context context, Handler handler, FilterListener listener) {
+ context.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE), false,
+ new ContentObserver(handler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ if (reloadFromSetting(context)) {
+ listener.onFilterUpdated();
+ }
+ }
+ }, UserHandle.USER_ALL);
+ }
+
+ /**
+ * Returns bar visibilities based on POLICY_CONTROL_AUTO filters and window policies.
+ * @return int[], where the first value is the inset types that should be shown, and the second
+ * is the inset types that should be hidden.
+ */
+ @WindowInsets.Type.InsetsType
+ static int[] getBarVisibilities(String packageName) {
+ int hideTypes = 0;
+ int showTypes = 0;
+ if (matchesStatusFilter(packageName)) {
+ hideTypes |= WindowInsets.Type.statusBars();
+ } else {
+ showTypes |= WindowInsets.Type.statusBars();
+ }
+ if (matchesNavigationFilter(packageName)) {
+ hideTypes |= WindowInsets.Type.navigationBars();
+ } else {
+ showTypes |= WindowInsets.Type.navigationBars();
+ }
+
+ return new int[] {showTypes, hideTypes};
+ }
+
+ private static boolean matchesStatusFilter(String packageName) {
+ return sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(packageName);
+ }
+
+ private static boolean matchesNavigationFilter(String packageName) {
+ return sImmersiveNavigationFilter != null
+ && sImmersiveNavigationFilter.matches(packageName);
+ }
+
+ private static void setFilters(String value) {
+ if (DEBUG) Slog.d(TAG, "setFilters: " + value);
+ sImmersiveStatusFilter = null;
+ sImmersiveNavigationFilter = null;
+ if (value != null) {
+ String[] nvps = value.split(":");
+ for (String nvp : nvps) {
+ int i = nvp.indexOf('=');
+ if (i == -1) continue;
+ String n = nvp.substring(0, i);
+ String v = nvp.substring(i + 1);
+ if (n.equals(NAME_IMMERSIVE_FULL)) {
+ Filter f = Filter.parse(v);
+ sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
+ } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
+ Filter f = Filter.parse(v);
+ sImmersiveStatusFilter = f;
+ } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
+ Filter f = Filter.parse(v);
+ sImmersiveNavigationFilter = f;
+ }
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter);
+ Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter);
+ }
+ }
+
+ private static class Filter {
+ private static final String ALL = "*";
+
+ private final ArraySet<String> mWhitelist;
+ private final ArraySet<String> mBlacklist;
+
+ private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
+ mWhitelist = whitelist;
+ mBlacklist = blacklist;
+ }
+
+ boolean matches(String packageName) {
+ if (packageName == null) return false;
+ if (onBlacklist(packageName)) return false;
+ return onWhitelist(packageName);
+ }
+
+ private boolean onBlacklist(String packageName) {
+ return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+ }
+
+ private boolean onWhitelist(String packageName) {
+ return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+ }
+
+ void dump(PrintWriter pw) {
+ pw.print("Filter[");
+ dump("whitelist", mWhitelist, pw); pw.print(',');
+ dump("blacklist", mBlacklist, pw); pw.print(']');
+ }
+
+ private void dump(String name, ArraySet<String> set, PrintWriter pw) {
+ pw.print(name); pw.print("=(");
+ int n = set.size();
+ for (int i = 0; i < n; i++) {
+ if (i > 0) pw.print(',');
+ pw.print(set.valueAt(i));
+ }
+ pw.print(')');
+ }
+
+ @Override
+ public String toString() {
+ StringWriter sw = new StringWriter();
+ dump(new PrintWriter(sw, true));
+ return sw.toString();
+ }
+
+ // value = comma-delimited list of tokens, where token = (package name|*)
+ // e.g. "com.package1", or "com.android.systemui, com.android.keyguard" or "*"
+ static Filter parse(String value) {
+ if (value == null) return null;
+ ArraySet<String> whitelist = new ArraySet<String>();
+ ArraySet<String> blacklist = new ArraySet<String>();
+ for (String token : value.split(",")) {
+ token = token.trim();
+ if (token.startsWith("-") && token.length() > 1) {
+ token = token.substring(1);
+ blacklist.add(token);
+ } else {
+ whitelist.add(token);
+ }
+ }
+ return new Filter(whitelist, blacklist);
+ }
+ }
+
+ /**
+ * Interface to listen for updates to the filter triggered by the content observer listening to
+ * the SYSTEM_BAR_VISIBILITY_OVERRIDE flag.
+ */
+ interface FilterListener {
+
+ /** Callback triggered when the content observer updates the filter. */
+ void onFilterUpdated();
+ }
+
+ private BarControlPolicy() {}
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
new file mode 100644
index 000000000000..a831464e7987
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
@@ -0,0 +1,168 @@
+/*
+ * 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.systemui.wm;
+
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.IDisplayWindowInsetsController;
+import android.view.InsetsController;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.WindowInsets;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.systemui.TransactionPool;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Controller that maps between displays and {@link IDisplayWindowInsetsController} in order to
+ * give system bar control to SystemUI.
+ * {@link R.bool#config_remoteInsetsControllerControlsSystemBars} determines whether this controller
+ * takes control or not.
+ */
+@Singleton
+public class DisplaySystemBarsController extends DisplayImeController {
+
+ private static final String TAG = "DisplaySystemBarsController";
+
+ private SparseArray<PerDisplay> mPerDisplaySparseArray;
+
+ @Inject
+ public DisplaySystemBarsController(
+ SystemWindows syswin,
+ DisplayController displayController,
+ @Main Handler mainHandler,
+ TransactionPool transactionPool) {
+ super(syswin, displayController, mainHandler, transactionPool);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ PerDisplay pd = new PerDisplay(displayId);
+ try {
+ mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, pd);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to set insets controller on display " + displayId);
+ }
+ // Lazy loading policy control filters instead of during boot.
+ if (mPerDisplaySparseArray == null) {
+ mPerDisplaySparseArray = new SparseArray<>();
+ BarControlPolicy.reloadFromSetting(mSystemWindows.mContext);
+ BarControlPolicy.registerContentObserver(mSystemWindows.mContext, mHandler, () -> {
+ int size = mPerDisplaySparseArray.size();
+ for (int i = 0; i < size; i++) {
+ mPerDisplaySparseArray.valueAt(i).modifyDisplayWindowInsets();
+ }
+ });
+ }
+ mPerDisplaySparseArray.put(displayId, pd);
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ try {
+ mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, null);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
+ }
+ mPerDisplaySparseArray.remove(displayId);
+ }
+
+ @VisibleForTesting
+ class PerDisplay extends IDisplayWindowInsetsController.Stub {
+
+ int mDisplayId;
+ InsetsController mInsetsController;
+ InsetsState mInsetsState = new InsetsState();
+ String mPackageName;
+
+ PerDisplay(int displayId) {
+ mDisplayId = displayId;
+ mInsetsController = new InsetsController(
+ new DisplaySystemBarsInsetsControllerHost(mHandler, this));
+ }
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ if (mInsetsState.equals(insetsState)) {
+ return;
+ }
+ mInsetsState.set(insetsState, true /* copySources */);
+ mInsetsController.onStateChanged(insetsState);
+ if (mPackageName != null) {
+ modifyDisplayWindowInsets();
+ }
+ }
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {
+ mInsetsController.onControlsChanged(activeControls);
+ }
+
+ @Override
+ public void hideInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
+ mInsetsController.hide(types);
+ }
+
+ @Override
+ public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
+ mInsetsController.show(types);
+ }
+
+ @Override
+ public void topFocusedWindowChanged(String packageName) {
+ // If both package names are null or both package names are equal, return.
+ if (mPackageName == packageName
+ || (mPackageName != null && mPackageName.equals(packageName))) {
+ return;
+ }
+ mPackageName = packageName;
+ modifyDisplayWindowInsets();
+ }
+
+ private void modifyDisplayWindowInsets() {
+ if (mPackageName == null) {
+ return;
+ }
+ int[] barVisibilities = BarControlPolicy.getBarVisibilities(mPackageName);
+ updateInsetsState(barVisibilities[0], /* visible= */ true);
+ updateInsetsState(barVisibilities[1], /* visible= */ false);
+ showInsets(barVisibilities[0], /* fromIme= */ false);
+ hideInsets(barVisibilities[1], /* fromIme= */ false);
+ try {
+ mSystemWindows.mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to update window manager service.");
+ }
+ }
+
+ private void updateInsetsState(@WindowInsets.Type.InsetsType int types, boolean visible) {
+ ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
+ for (int i = internalTypes.size() - 1; i >= 0; i--) {
+ mInsetsState.getSource(internalTypes.valueAt(i)).setVisible(visible);
+ }
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java
new file mode 100644
index 000000000000..2f8da44ba851
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java
@@ -0,0 +1,173 @@
+/*
+ * 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.systemui.wm;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IDisplayWindowInsetsController;
+import android.view.InsetsController;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.view.SyncRtSurfaceTransactionApplier;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
+import android.view.WindowInsetsController;
+import android.view.inputmethod.InputMethodManager;
+
+import java.util.List;
+
+/**
+ * Implements {@link InsetsController.Host} for usage by
+ * {@link DisplaySystemBarsController.PerDisplay} instances in {@link DisplaySystemBarsController}.
+ * @hide
+ */
+public class DisplaySystemBarsInsetsControllerHost implements InsetsController.Host {
+
+ private static final String TAG = DisplaySystemBarsInsetsControllerHost.class.getSimpleName();
+
+ private final Handler mHandler;
+ private final IDisplayWindowInsetsController mController;
+ private final float[] mTmpFloat9 = new float[9];
+
+ public DisplaySystemBarsInsetsControllerHost(
+ Handler handler, IDisplayWindowInsetsController controller) {
+ mHandler = handler;
+ mController = controller;
+ }
+
+ @Override
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ @Override
+ public void notifyInsetsChanged() {
+ // no-op
+ }
+
+ @Override
+ public void dispatchWindowInsetsAnimationPrepare(@NonNull WindowInsetsAnimation animation) {
+ // no-op
+ }
+
+ @Override
+ public WindowInsetsAnimation.Bounds dispatchWindowInsetsAnimationStart(
+ @NonNull WindowInsetsAnimation animation,
+ @NonNull WindowInsetsAnimation.Bounds bounds) {
+ return null;
+ }
+
+ @Override
+ public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets,
+ @NonNull List<WindowInsetsAnimation> runningAnimations) {
+ return null;
+ }
+
+ @Override
+ public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) {
+ // no-op
+ }
+
+ @Override
+ public void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
+ for (int i = params.length - 1; i >= 0; i--) {
+ SyncRtSurfaceTransactionApplier.applyParams(
+ new SurfaceControl.Transaction(), params[i], mTmpFloat9);
+ }
+
+ }
+
+ @Override
+ public void updateCompatSysUiVisibility(
+ @InsetsState.InternalInsetsType int type, boolean visible, boolean hasControl) {
+ // no-op
+ }
+
+ @Override
+ public void onInsetsModified(InsetsState insetsState) {
+ try {
+ mController.insetsChanged(insetsState);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send insets to controller");
+ }
+ }
+
+ @Override
+ public boolean hasAnimationCallbacks() {
+ return false;
+ }
+
+ @Override
+ public void setSystemBarsAppearance(
+ @WindowInsetsController.Appearance int appearance,
+ @WindowInsetsController.Appearance int mask) {
+ // no-op
+ }
+
+ @Override
+ public @WindowInsetsController.Appearance int getSystemBarsAppearance() {
+ return 0;
+ }
+
+ @Override
+ public void setSystemBarsBehavior(@WindowInsetsController.Behavior int behavior) {
+ // no-op
+ }
+
+ @Override
+ public @WindowInsetsController.Behavior int getSystemBarsBehavior() {
+ return 0;
+ }
+
+ @Override
+ public void releaseSurfaceControlFromRt(SurfaceControl surfaceControl) {
+ surfaceControl.release();
+ }
+
+ @Override
+ public void addOnPreDrawRunnable(Runnable r) {
+ mHandler.post(r);
+ }
+
+ @Override
+ public void postInsetsAnimationCallback(Runnable r) {
+ mHandler.post(r);
+ }
+
+ @Override
+ public InputMethodManager getInputMethodManager() {
+ return null;
+ }
+
+ @Override
+ public String getRootViewTitle() {
+ return null;
+ }
+
+ @Override
+ public int dipToPx(int dips) {
+ return 0;
+ }
+
+ @Override
+ public IBinder getWindowToken() {
+ return null;
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
index eca51e34995c..232df2eced39 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
@@ -24,6 +24,8 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.content.Intent;
import android.os.Handler;
@@ -44,14 +46,19 @@ import org.junit.runner.RunWith;
public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+ private static final String BLUETOOTH_REMOTE_ADDRESS = "00:11:22:33:44:55";
private ConnectedDeviceVoiceRecognitionNotifier mVoiceRecognitionNotifier;
+ private TestableLooper mTestableLooper;
private Handler mTestHandler;
+ private BluetoothDevice mBluetoothDevice;
@Before
public void setUp() throws Exception {
- TestableLooper testableLooper = TestableLooper.get(this);
- mTestHandler = spy(new Handler(testableLooper.getLooper()));
+ mTestableLooper = TestableLooper.get(this);
+ mTestHandler = spy(new Handler(mTestableLooper.getLooper()));
+ mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
+ BLUETOOTH_REMOTE_ADDRESS);
mVoiceRecognitionNotifier = new ConnectedDeviceVoiceRecognitionNotifier(
mContext, mTestHandler);
mVoiceRecognitionNotifier.onBootCompleted();
@@ -61,8 +68,10 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
public void testReceiveIntent_started_showToast() {
Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, VOICE_RECOGNITION_STARTED);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- waitForIdleSync();
+ mTestableLooper.processAllMessages();
verify(mTestHandler).post(any());
}
@@ -71,8 +80,10 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
public void testReceiveIntent_invalidExtra_noToast() {
Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, INVALID_VALUE);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- waitForIdleSync();
+ mTestableLooper.processAllMessages();
verify(mTestHandler, never()).post(any());
}
@@ -80,8 +91,10 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
@Test
public void testReceiveIntent_noExtra_noToast() {
Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- waitForIdleSync();
+ mTestableLooper.processAllMessages();
verify(mTestHandler, never()).post(any());
}
@@ -89,8 +102,10 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
@Test
public void testReceiveIntent_invalidIntent_noToast() {
Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- waitForIdleSync();
+ mTestableLooper.processAllMessages();
verify(mTestHandler, never()).post(any());
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java
new file mode 100644
index 000000000000..da7cb8e4f6ac
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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.systemui.wm;
+
+import static android.view.WindowInsets.Type.navigationBars;
+import static android.view.WindowInsets.Type.statusBars;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.settings.CarSettings;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class BarControlPolicyTest extends SysuiTestCase {
+
+ private static final String PACKAGE_NAME = "sample.app";
+
+ @Before
+ public void setUp() {
+ BarControlPolicy.reset();
+ }
+
+ @After
+ public void tearDown() {
+ Settings.Global.clearProviderForTest();
+ }
+
+ @Test
+ public void reloadFromSetting_notSet_doesNotSetFilters() {
+ BarControlPolicy.reloadFromSetting(mContext);
+
+ assertThat(BarControlPolicy.sImmersiveStatusFilter).isNull();
+ }
+
+ @Test
+ public void reloadFromSetting_invalidPolicyControlString_doesNotSetFilters() {
+ String text = "sample text";
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ text
+ );
+
+ BarControlPolicy.reloadFromSetting(mContext);
+
+ assertThat(BarControlPolicy.sImmersiveStatusFilter).isNull();
+ }
+
+ @Test
+ public void reloadFromSetting_validPolicyControlString_setsFilters() {
+ String text = "immersive.status=" + PACKAGE_NAME;
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ text
+ );
+
+ BarControlPolicy.reloadFromSetting(mContext);
+
+ assertThat(BarControlPolicy.sImmersiveStatusFilter).isNotNull();
+ }
+
+ @Test
+ public void reloadFromSetting_filtersSet_doesNotSetFiltersAgain() {
+ String text = "immersive.status=" + PACKAGE_NAME;
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ text
+ );
+
+ BarControlPolicy.reloadFromSetting(mContext);
+
+ assertThat(BarControlPolicy.reloadFromSetting(mContext)).isFalse();
+ }
+
+ @Test
+ public void getBarVisibilities_policyControlNotSet_showsSystemBars() {
+ int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME);
+
+ assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars());
+ assertThat(visibilities[1]).isEqualTo(0);
+ }
+
+ @Test
+ public void getBarVisibilities_immersiveStatusForAppAndMatchingApp_hidesStatusBar() {
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ "immersive.status=" + PACKAGE_NAME);
+ BarControlPolicy.reloadFromSetting(mContext);
+
+ int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME);
+
+ assertThat(visibilities[0]).isEqualTo(navigationBars());
+ assertThat(visibilities[1]).isEqualTo(statusBars());
+ }
+
+ @Test
+ public void getBarVisibilities_immersiveStatusForAppAndNonMatchingApp_showsSystemBars() {
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ "immersive.status=" + PACKAGE_NAME);
+ BarControlPolicy.reloadFromSetting(mContext);
+
+ int[] visibilities = BarControlPolicy.getBarVisibilities("sample2.app");
+
+ assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars());
+ assertThat(visibilities[1]).isEqualTo(0);
+ }
+
+ @Test
+ public void getBarVisibilities_immersiveStatusForAppsAndNonApp_showsSystemBars() {
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ "immersive.status=apps");
+ BarControlPolicy.reloadFromSetting(mContext);
+
+ int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME);
+
+ assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars());
+ assertThat(visibilities[1]).isEqualTo(0);
+ }
+
+ @Test
+ public void getBarVisibilities_immersiveFullForAppAndMatchingApp_hidesSystemBars() {
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ "immersive.full=" + PACKAGE_NAME);
+ BarControlPolicy.reloadFromSetting(mContext);
+
+ int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME);
+
+ assertThat(visibilities[0]).isEqualTo(0);
+ assertThat(visibilities[1]).isEqualTo(statusBars() | navigationBars());
+ }
+
+ @Test
+ public void getBarVisibilities_immersiveFullForAppAndNonMatchingApp_showsSystemBars() {
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ "immersive.full=" + PACKAGE_NAME);
+ BarControlPolicy.reloadFromSetting(mContext);
+
+ int[] visibilities = BarControlPolicy.getBarVisibilities("sample2.app");
+
+ assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars());
+ assertThat(visibilities[1]).isEqualTo(0);
+ }
+
+ @Test
+ public void getBarVisibilities_immersiveFullForAppsAndNonApp_showsSystemBars() {
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ "immersive.full=apps");
+ BarControlPolicy.reloadFromSetting(mContext);
+
+ int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME);
+
+ assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars());
+ assertThat(visibilities[1]).isEqualTo(0);
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
new file mode 100644
index 000000000000..29cc8eec4bc3
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.systemui.wm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+
+import android.car.settings.CarSettings;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.IWindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.TransactionPool;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class DisplaySystemBarsControllerTest extends SysuiTestCase {
+
+ private DisplaySystemBarsController mController;
+
+ private static final int DISPLAY_ID = 1;
+
+ @Mock
+ private SystemWindows mSystemWindows;
+ @Mock
+ private IWindowManager mIWindowManager;
+ @Mock
+ private DisplayController mDisplayController;
+ @Mock
+ private Handler mHandler;
+ @Mock
+ private TransactionPool mTransactionPool;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mSystemWindows.mContext = mContext;
+ mSystemWindows.mWmService = mIWindowManager;
+
+ mController = new DisplaySystemBarsController(
+ mSystemWindows,
+ mDisplayController,
+ mHandler,
+ mTransactionPool
+ );
+ }
+
+ @Test
+ public void onDisplayAdded_setsDisplayWindowInsetsControllerOnWMService()
+ throws RemoteException {
+ mController.onDisplayAdded(DISPLAY_ID);
+
+ verify(mIWindowManager).setDisplayWindowInsetsController(
+ eq(DISPLAY_ID), any(DisplaySystemBarsController.PerDisplay.class));
+ }
+
+ @Test
+ public void onDisplayAdded_loadsBarControlPolicyFilters() {
+ String text = "sample text";
+ Settings.Global.putString(
+ mContext.getContentResolver(),
+ CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
+ text
+ );
+
+ mController.onDisplayAdded(DISPLAY_ID);
+
+ assertThat(BarControlPolicy.sSettingValue).isEqualTo(text);
+ }
+
+ @Test
+ public void onDisplayRemoved_unsetsDisplayWindowInsetsControllerInWMService()
+ throws RemoteException {
+ mController.onDisplayAdded(DISPLAY_ID);
+
+ mController.onDisplayRemoved(DISPLAY_ID);
+
+ verify(mIWindowManager).setDisplayWindowInsetsController(
+ DISPLAY_ID, /* displayWindowInsetsController= */ null);
+ }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java
index 5a51ac22b88f..973ab8956304 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallFinish.java
@@ -239,8 +239,8 @@ public class UninstallFinish extends BroadcastReceiver {
builder.addAction((new Notification.Action.Builder(
Icon.createWithResource(context, R.drawable.ic_settings_multiuser),
context.getString(R.string.manage_users),
- PendingIntent.getActivity(context, 0, intent,
- PendingIntent.FLAG_UPDATE_CURRENT))).build());
+ PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
+ | PendingIntent.FLAG_IMMUTABLE))).build());
}
/**
@@ -259,7 +259,7 @@ public class UninstallFinish extends BroadcastReceiver {
builder.addAction((new Notification.Action.Builder(
Icon.createWithResource(context, R.drawable.ic_lock),
context.getString(R.string.manage_device_administrators),
- PendingIntent.getActivity(context, 0, intent,
- PendingIntent.FLAG_UPDATE_CURRENT))).build());
+ PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
+ | PendingIntent.FLAG_IMMUTABLE))).build());
}
}
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
index 9ae31989eeb2..5a756fe50209 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
@@ -46,7 +46,7 @@ public class RecommendationServiceImpl extends RecommendationService
private static final String LOG_TAG = "PrintServiceRecService";
/** All registered plugins */
- private ArrayList<RemotePrintServicePlugin> mPlugins;
+ private final ArrayList<RemotePrintServicePlugin> mPlugins = new ArrayList<>();
/** Lock to keep multi-cast enabled */
private WifiManager.MulticastLock mMultiCastLock;
@@ -62,8 +62,6 @@ public class RecommendationServiceImpl extends RecommendationService
mMultiCastLock.acquire();
}
- mPlugins = new ArrayList<>();
-
try {
for (VendorConfig config : VendorConfig.getAllConfigs(this)) {
try {
@@ -138,6 +136,7 @@ public class RecommendationServiceImpl extends RecommendationService
Log.e(LOG_TAG, "Could not stop plugin", e);
}
}
+ mPlugins.clear();
if (mMultiCastLock != null) {
mMultiCastLock.release();
diff --git a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
index 3565b0e3a9ae..e82997431290 100644
--- a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
+++ b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
@@ -16,9 +16,6 @@
package com.android.settingslib.widget;
-import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_ADVANCED;
-import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_DEFAULT;
-
import android.annotation.ColorInt;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -48,11 +45,12 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
private static final float ADVANCED_ICON_CENTER = 50f;
private static final float ADVANCED_ICON_RADIUS = 48f;
+ public static final int ICON_TYPE_DEFAULT = 0;
+ public static final int ICON_TYPE_ADVANCED = 1;
+
@Retention(RetentionPolicy.SOURCE)
- @IntDef({TYPE_DEFAULT, TYPE_ADVANCED})
+ @IntDef({ICON_TYPE_DEFAULT, ICON_TYPE_ADVANCED})
public @interface AdaptiveOutlineIconType {
- int TYPE_DEFAULT = 0;
- int TYPE_ADVANCED = 1;
}
@VisibleForTesting
@@ -66,7 +64,7 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap) {
super(new AdaptiveIconShapeDrawable(resources));
- init(resources, bitmap, TYPE_DEFAULT);
+ init(resources, bitmap, ICON_TYPE_DEFAULT);
}
public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap,
@@ -96,10 +94,10 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
private @ColorInt int getColor(Resources resources, @AdaptiveOutlineIconType int type) {
int resId;
switch (type) {
- case TYPE_ADVANCED:
+ case ICON_TYPE_ADVANCED:
resId = R.color.advanced_outline_color;
break;
- case TYPE_DEFAULT:
+ case ICON_TYPE_DEFAULT:
default:
resId = R.color.bt_outline_color;
break;
@@ -110,10 +108,10 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
private int getDimensionPixelSize(Resources resources, @AdaptiveOutlineIconType int type) {
int resId;
switch (type) {
- case TYPE_ADVANCED:
+ case ICON_TYPE_ADVANCED:
resId = R.dimen.advanced_dashboard_tile_foreground_image_inset;
break;
- case TYPE_DEFAULT:
+ case ICON_TYPE_DEFAULT:
default:
resId = R.dimen.dashboard_tile_foreground_image_inset;
break;
@@ -133,7 +131,7 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
final int count = canvas.save();
canvas.scale(scaleX, scaleY);
// Draw outline
- if (mType == TYPE_DEFAULT) {
+ if (mType == ICON_TYPE_DEFAULT) {
canvas.drawPath(mPath, mOutlinePaint);
} else {
canvas.drawCircle(ADVANCED_ICON_CENTER, ADVANCED_ICON_CENTER, ADVANCED_ICON_RADIUS,
diff --git a/packages/SettingsLib/Utils/AndroidManifest.xml b/packages/SettingsLib/Utils/AndroidManifest.xml
index fd89676ab6d7..96d9e518663f 100644
--- a/packages/SettingsLib/Utils/AndroidManifest.xml
+++ b/packages/SettingsLib/Utils/AndroidManifest.xml
@@ -16,7 +16,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.settingslib.utils">
+ package="com.android.settingslib.widget">
<uses-sdk android:minSdkVersion="21" />
diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java
index 6125b8509fcf..e7c0d9659d11 100644
--- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java
+++ b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java
@@ -22,7 +22,7 @@ import android.content.pm.PackageManager;
import android.os.UserManager;
import android.util.Log;
-import com.android.settingslib.utils.R;
+import com.android.settingslib.widget.R;
public class AppUtils {
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index c27973f8bc86..287a1aca2fbd 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -22,7 +22,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="wifi_fail_to_scan" msgid="2333336097603822490">"No se pueden buscar las redes."</string>
<string name="wifi_security_none" msgid="7392696451280611452">"Ninguna"</string>
- <string name="wifi_remembered" msgid="3266709779723179188">"Guardada"</string>
+ <string name="wifi_remembered" msgid="3266709779723179188">"Guardado"</string>
<string name="wifi_disconnected" msgid="7054450256284661757">"Desconectado"</string>
<string name="wifi_disabled_generic" msgid="2651916945380294607">"Inhabilitada"</string>
<string name="wifi_disabled_network_failure" msgid="2660396183242399585">"Error de configuración IP"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 3e8b1c1b9cde..f9d57c453f69 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -37,7 +37,7 @@
<string name="wifi_no_internet" msgid="1774198889176926299">"Sen acceso a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Gardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectouse automaticamente a través de %1$s"</string>
- <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectada automaticamente a través dun provedor de valoración de rede"</string>
+ <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectada automaticamente a través dun provedor de valoración de redes"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conectado a través de %1$s"</string>
<string name="connected_via_app" msgid="3532267661404276584">"Wifi conectada a través de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dispoñible a través de %1$s"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 08cf5f9fd5a9..8407db6d3a08 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -211,8 +211,8 @@
<string name="adb_wireless_error" msgid="721958772149779856">"Алдаа"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Wireless debugging"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Боломжтой төхөөрөмжүүдийг харах болох ашиглахын тулд wireless debugging-г асаана уу"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Хурдан хариу үйлдлийн кодоор төхөөрөмжийг хослуул"</string>
- <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Хурдан хариу үйлдлийн кодын сканнер ашиглан шинэ төхөөрөмжүүдийг хослуулна уу"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR кодоор төхөөрөмжийг хослуул"</string>
+ <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR кодын сканнер ашиглан шинэ төхөөрөмжүүдийг хослуулна уу"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Хослуулах кодоор төхөөрөмжийг хослуулна уу"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Зургаан оронтой кодыг ашиглан шинэ төхөөрөмжүүдийг хослуулна уу"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Хослуулсан төхөөрөмжүүд"</string>
@@ -226,12 +226,12 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi хослуулах код"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Хослуулалт амжилтгүй боллоо"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Төхөөрөмжийг ижил сүлжээнд холбосон эсэхийг шалгана уу."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Хурдан хариу үйлдлийн кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Төхөөрөмжийг хослуулж байна…"</string>
- <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Төхөөрөмжийг хослуулж чадсангүй. Хурдан хариу үйлдлийн код буруу эсвэл төхөөрөмжийг ижил сүлжээнд холбоогүй байна."</string>
+ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Төхөөрөмжийг хослуулж чадсангүй. QR код буруу эсвэл төхөөрөмжийг ижил сүлжээнд холбоогүй байна."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP хаяг ба порт"</string>
- <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Хурдан хариу үйлдлийн кодыг скан хийх"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Хурдан хариу үйлдлийн кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу"</string>
+ <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR кодыг скан хийх"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Wi-Fi сүлжээнд холбогдоно уу"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, дебаг хийх, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"Алдаа мэдээлэх товчлол"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index e33df4ad7d1c..32cc39ec5b4f 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -37,7 +37,7 @@
<string name="wifi_no_internet" msgid="1774198889176926299">"Geen internettoegang"</string>
<string name="saved_network" msgid="7143698034077223645">"Opgeslagen door \'<xliff:g id="NAME">%1$s</xliff:g>\'"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatisch verbonden via %1$s"</string>
- <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatisch verbonden via netwerkbeoordelaar"</string>
+ <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatisch verbonden via provider van netwerkbeoordelingen"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Verbonden via %1$s"</string>
<string name="connected_via_app" msgid="3532267661404276584">"Verbonden via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Beschikbaar via %1$s"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 95e916b9871a..68f72896c251 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -1,6 +1,6 @@
package com.android.settingslib.bluetooth;
-import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_ADVANCED;
+import static com.android.settingslib.widget.AdaptiveOutlineDrawable.ICON_TYPE_ADVANCED;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -238,7 +238,7 @@ public class BluetoothUtils {
final Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, iconSize,
iconSize, false);
bitmap.recycle();
- return new AdaptiveOutlineDrawable(resources, resizedBitmap, TYPE_ADVANCED);
+ return new AdaptiveOutlineDrawable(resources, resizedBitmap, ICON_TYPE_ADVANCED);
}
return drawable;
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
index 278b57da0c28..e5ea4467517b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
@@ -41,7 +41,7 @@ public class CircleFramedDrawable extends Drawable {
private final Bitmap mBitmap;
private final int mSize;
- private final Paint mPaint;
+ private Paint mIconPaint;
private float mScale;
private Rect mSrcRect;
@@ -75,18 +75,18 @@ public class CircleFramedDrawable extends Drawable {
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
// opaque circle matte
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mPaint.setColor(Color.BLACK);
- mPaint.setStyle(Paint.Style.FILL);
- canvas.drawPath(fillPath, mPaint);
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setColor(Color.BLACK);
+ paint.setStyle(Paint.Style.FILL);
+ canvas.drawPath(fillPath, paint);
// mask in the icon where the bitmap is opaque
- mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
- canvas.drawBitmap(icon, cropRect, circleRect, mPaint);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+ canvas.drawBitmap(icon, cropRect, circleRect, paint);
// prepare paint for frame drawing
- mPaint.setXfermode(null);
+ paint.setXfermode(null);
mScale = 1f;
@@ -100,7 +100,7 @@ public class CircleFramedDrawable extends Drawable {
final float pad = (mSize - inside) / 2f;
mDstRect.set(pad, pad, mSize - pad, mSize - pad);
- canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null);
+ canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, mIconPaint);
}
public void setScale(float scale) {
@@ -122,8 +122,12 @@ public class CircleFramedDrawable extends Drawable {
@Override
public void setColorFilter(ColorFilter cf) {
+ if (mIconPaint == null) {
+ mIconPaint = new Paint();
+ }
+ mIconPaint.setColorFilter(cf);
}
-
+
@Override
public int getIntrinsicWidth() {
return mSize;
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 7a27676237a1..6ecf303c6dc8 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -68,14 +68,14 @@ android_library {
"iconloader_base",
"SystemUI-tags",
"SystemUI-proto",
- "dagger2-2.19",
+ "dagger2",
"jsr330"
],
manifest: "AndroidManifest.xml",
kotlincflags: ["-Xjvm-default=enable"],
- plugins: ["dagger2-compiler-2.19"],
+ plugins: ["dagger2-compiler"],
}
filegroup {
@@ -139,7 +139,7 @@ android_library {
"mockito-target-extended-minus-junit4",
"testables",
"truth-prebuilt",
- "dagger2-2.19",
+ "dagger2",
"jsr330"
],
libs: [
@@ -151,7 +151,7 @@ android_library {
"--extra-packages",
"com.android.systemui",
],
- plugins: ["dagger2-compiler-2.19"],
+ plugins: ["dagger2-compiler"],
}
android_app {
diff --git a/packages/SystemUI/docs/dagger.md b/packages/SystemUI/docs/dagger.md
index c440fba10135..bb68647ceb00 100644
--- a/packages/SystemUI/docs/dagger.md
+++ b/packages/SystemUI/docs/dagger.md
@@ -206,11 +206,31 @@ public CustomView(@Named(VIEW_CONTEXT) Context themedViewContext, AttributeSet a
## Updating Dagger2
+We depend on the Dagger source found in external/dagger2. We should automatically pick up on updates
+when that repository is updated.
+
+*Deprecated:*
+
Binaries can be downloaded from https://repo1.maven.org/maven2/com/google/dagger/ and then loaded
into
[/prebuilts/tools/common/m2/repository/com/google/dagger/](http://cs/android/prebuilts/tools/common/m2/repository/com/google/dagger/)
+The following commands should work, substituting in the version that you are looking for:
+
+````
+cd prebuilts/tools/common/m2/repository/com/google/dagger/
+
+wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger/2.28.1/
+
+wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.28.1/
+
+wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-spi/2.28.1/
+
+wget -r -np -nH --cut-dirs=4 -erobots=off -R "index.html*" -U "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" https://repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.28.1/
+````
+Then update `prebuilts/tools/common/m2/Android.bp` to point at your new jars.
+
## TODO List
- Eliminate usages of Dependency#get
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 597644bf3295..4527c6c793d5 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -53,6 +53,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="4dp"
+ android:importantForAccessibility="no"
android:layout_weight="1">
<com.android.systemui.qs.QSPanel
android:id="@+id/quick_settings_panel"
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index f474a36b99b7..732758a2ded2 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<com.google.android.systemui.udfps.UdfpsView
+<com.android.systemui.biometrics.UdfpsView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/udfps_view"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index ee2d001866ce..9d3620f34186 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -25,6 +25,7 @@ import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_
import android.app.ActivityManager.TaskSnapshot;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.util.Log;
@@ -62,10 +63,12 @@ public class ThumbnailData {
public ThumbnailData(TaskSnapshot snapshot) {
final HardwareBuffer buffer = snapshot.getHardwareBuffer();
- if (buffer != null && (buffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
+ if (buffer == null || (buffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
// TODO(b/157562905): Workaround for a crash when we get a snapshot without this state
- Log.e("ThumbnailData", "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE");
- thumbnail = Bitmap.createBitmap(buffer.getWidth(), buffer.getHeight(), ARGB_8888);
+ Log.e("ThumbnailData", "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE: "
+ + buffer);
+ Point taskSize = snapshot.getTaskSize();
+ thumbnail = Bitmap.createBitmap(taskSize.x, taskSize.y, ARGB_8888);
thumbnail.eraseColor(Color.BLACK);
} else {
thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.getColorSpace());
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 10dcbd6f9182..a84664ceee3d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -448,8 +448,8 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+ " UpdateSim.onSimCheckResponse: "
+ " attemptsRemaining=" + result.getAttemptsRemaining());
- mStateMachine.reset();
}
+ mStateMachine.reset();
mCheckSimPukThread = null;
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 6c06553a84a6..ad11d71eb132 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -62,6 +62,7 @@ import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayCutout.BoundsPosition;
import android.view.DisplayInfo;
@@ -820,6 +821,7 @@ public class ScreenDecorations extends SystemUI implements Tunable {
private static final float HIDDEN_CAMERA_PROTECTION_SCALE = 0.5f;
+ private Display.Mode mDisplayMode = null;
private final DisplayInfo mInfo = new DisplayInfo();
private final Paint mPaint = new Paint();
private final List<Rect> mBounds = new ArrayList();
@@ -904,11 +906,33 @@ public class ScreenDecorations extends SystemUI implements Tunable {
@Override
public void onDisplayChanged(int displayId) {
+ Display.Mode oldMode = mDisplayMode;
+ mDisplayMode = getDisplay().getMode();
+
+ // Display mode hasn't meaningfully changed, we can ignore it
+ if (!modeChanged(oldMode, mDisplayMode)) {
+ return;
+ }
+
if (displayId == getDisplay().getDisplayId()) {
update();
}
}
+ private boolean modeChanged(Display.Mode oldMode, Display.Mode newMode) {
+ if (oldMode == null) {
+ return true;
+ }
+
+ boolean changed = false;
+ changed |= oldMode.getPhysicalHeight() != newMode.getPhysicalHeight();
+ changed |= oldMode.getPhysicalWidth() != newMode.getPhysicalWidth();
+ // We purposely ignore refresh rate and id changes here, because we don't need to
+ // invalidate for those, and they can trigger the refresh rate to increase
+
+ return changed;
+ }
+
public void setRotation(int rotation) {
mRotation = rotation;
update();
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 941de2dc63ec..5fd7b53435cf 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -21,9 +21,9 @@ import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -57,12 +57,11 @@ public class AppOpsControllerImpl implements AppOpsController,
private static final long NOTED_OP_TIME_DELAY_MS = 5000;
private static final String TAG = "AppOpsControllerImpl";
private static final boolean DEBUG = false;
- private final Context mContext;
private final AppOpsManager mAppOps;
private H mBGHandler;
private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>();
- private final ArrayMap<Integer, Set<Callback>> mCallbacksByCode = new ArrayMap<>();
+ private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>();
private boolean mListening;
@GuardedBy("mActiveItems")
@@ -71,6 +70,7 @@ public class AppOpsControllerImpl implements AppOpsController,
private final List<AppOpItem> mNotedItems = new ArrayList<>();
protected static final int[] OPS = new int[] {
+ AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION,
AppOpsManager.OP_CAMERA,
AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
AppOpsManager.OP_RECORD_AUDIO,
@@ -83,7 +83,6 @@ public class AppOpsControllerImpl implements AppOpsController,
Context context,
@Background Looper bgLooper,
DumpManager dumpManager) {
- mContext = context;
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mBGHandler = new H(bgLooper);
final int numOps = OPS.length;
@@ -131,7 +130,7 @@ public class AppOpsControllerImpl implements AppOpsController,
boolean added = false;
final int numCodes = opsCodes.length;
for (int i = 0; i < numCodes; i++) {
- if (mCallbacksByCode.containsKey(opsCodes[i])) {
+ if (mCallbacksByCode.contains(opsCodes[i])) {
mCallbacksByCode.get(opsCodes[i]).add(callback);
added = true;
} else {
@@ -155,7 +154,7 @@ public class AppOpsControllerImpl implements AppOpsController,
public void removeCallback(int[] opsCodes, AppOpsController.Callback callback) {
final int numCodes = opsCodes.length;
for (int i = 0; i < numCodes; i++) {
- if (mCallbacksByCode.containsKey(opsCodes[i])) {
+ if (mCallbacksByCode.contains(opsCodes[i])) {
mCallbacksByCode.get(opsCodes[i]).remove(callback);
}
}
@@ -312,7 +311,7 @@ public class AppOpsControllerImpl implements AppOpsController,
}
private void notifySuscribers(int code, int uid, String packageName, boolean active) {
- if (mCallbacksByCode.containsKey(code)) {
+ if (mCallbacksByCode.contains(code)) {
if (DEBUG) Log.d(TAG, "Notifying of change in package " + packageName);
for (Callback cb: mCallbacksByCode.get(code)) {
cb.onActiveStateChanged(code, uid, packageName, active);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index c82e1debf185..97e97ffaae0c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -22,6 +22,8 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.LayoutInflater;
@@ -44,6 +46,7 @@ class UdfpsController {
private final Context mContext;
private final IFingerprintService mFingerprintService;
private final WindowManager mWindowManager;
+ private final Handler mHandler;
private UdfpsView mView;
private WindowManager.LayoutParams mLayoutParams;
@@ -96,6 +99,7 @@ class UdfpsController {
mContext = context;
mFingerprintService = fingerprintService;
mWindowManager = windowManager;
+ mHandler = new Handler(Looper.getMainLooper());
start();
}
@@ -138,23 +142,27 @@ class UdfpsController {
}
private void showUdfpsOverlay() {
- Log.v(TAG, "showUdfpsOverlay | adding window");
- if (!mIsOverlayShowing) {
- try {
- mWindowManager.addView(mView, mLayoutParams);
- mIsOverlayShowing = true;
- } catch (RuntimeException e) {
- Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
+ mHandler.post(() -> {
+ Log.v(TAG, "showUdfpsOverlay | adding window");
+ if (!mIsOverlayShowing) {
+ try {
+ mWindowManager.addView(mView, mLayoutParams);
+ mIsOverlayShowing = true;
+ } catch (RuntimeException e) {
+ Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
+ }
}
- }
+ });
}
private void hideUdfpsOverlay() {
- Log.v(TAG, "hideUdfpsOverlay | removing window");
- if (mIsOverlayShowing) {
- mWindowManager.removeView(mView);
- mIsOverlayShowing = false;
- }
+ mHandler.post(() -> {
+ Log.v(TAG, "hideUdfpsOverlay | removing window");
+ if (mIsOverlayShowing) {
+ mWindowManager.removeView(mView);
+ mIsOverlayShowing = false;
+ }
+ });
}
private void onFingerDown(int x, int y, float minor, float major) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
index 40a93e1cdc47..57e2362bd511 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
@@ -24,7 +24,6 @@ import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
@@ -95,9 +94,16 @@ public class BubbleIconFactory extends BaseIconFactory {
Bitmap badgeAndRing = Bitmap.createBitmap(userBadgedBitmap.getWidth(),
userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig());
Canvas c = new Canvas(badgeAndRing);
- Rect dest = new Rect((int) ringStrokeWidth, (int) ringStrokeWidth,
- c.getHeight() - (int) ringStrokeWidth, c.getWidth() - (int) ringStrokeWidth);
- c.drawBitmap(userBadgedBitmap, null, dest, null);
+
+ final int bitmapTop = (int) ringStrokeWidth;
+ final int bitmapLeft = (int) ringStrokeWidth;
+ final int bitmapWidth = c.getWidth() - 2 * (int) ringStrokeWidth;
+ final int bitmapHeight = c.getHeight() - 2 * (int) ringStrokeWidth;
+
+ Bitmap scaledBitmap = Bitmap.createScaledBitmap(userBadgedBitmap, bitmapWidth,
+ bitmapHeight, /* filter */ true);
+ c.drawBitmap(scaledBitmap, bitmapTop, bitmapLeft, /* paint */null);
+
Paint ringPaint = new Paint();
ringPaint.setStyle(Paint.Style.STROKE);
ringPaint.setColor(importantConversationColor);
@@ -105,6 +111,7 @@ public class BubbleIconFactory extends BaseIconFactory {
ringPaint.setStrokeWidth(ringStrokeWidth);
c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2 - ringStrokeWidth,
ringPaint);
+
shadowGenerator.recreateIcon(Bitmap.createBitmap(badgeAndRing), c);
return createIconBitmap(badgeAndRing);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 0873328c2382..4bd046e23dab 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -24,6 +24,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.assist.AssistModule;
+import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
@@ -68,6 +69,7 @@ import dagger.Provides;
},
subcomponents = {StatusBarComponent.class,
NotificationRowComponent.class,
+ DozeComponent.class,
ExpandableNotificationRowComponent.class})
public abstract class SystemUIModule {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
index 4fea45c39d5d..60ee806d0a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
@@ -51,6 +51,14 @@ public class AlwaysOnDisplayPolicy {
static final String KEY_WALLPAPER_VISIBILITY_MS = "wallpaper_visibility_timeout";
static final String KEY_WALLPAPER_FADE_OUT_MS = "wallpaper_fade_out_duration";
+
+ /**
+ * Integer used to dim the screen while dozing.
+ *
+ * @see R.integer.config_screenBrightnessDoze
+ */
+ public int defaultDozeBrightness;
+
/**
* Integer array to map ambient brightness type to real screen brightness.
*
@@ -165,6 +173,8 @@ public class AlwaysOnDisplayPolicy {
DEFAULT_WALLPAPER_FADE_OUT_MS);
wallpaperVisibilityDuration = mParser.getLong(KEY_WALLPAPER_VISIBILITY_MS,
DEFAULT_WALLPAPER_VISIBILITY_MS);
+ defaultDozeBrightness = resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDoze);
screenBrightnessArray = mParser.getIntArray(KEY_SCREEN_BRIGHTNESS_ARRAY,
resources.getIntArray(
R.array.config_doze_brightness_sensor_to_brightness));
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
index abd41d4318bd..5eb9808ebd7c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeAuthRemover.java
@@ -16,20 +16,22 @@
package com.android.systemui.doze;
-import android.content.Context;
-
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Dependency;
+import com.android.systemui.doze.dagger.DozeScope;
+
+import javax.inject.Inject;
/**
* Controls removing Keyguard authorization when the phone goes to sleep.
*/
+@DozeScope
public class DozeAuthRemover implements DozeMachine.Part {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- public DozeAuthRemover(Context context) {
- mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
+ @Inject
+ public DozeAuthRemover(KeyguardUpdateMonitor keyguardUpdateMonitor) {
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 554457b3564a..2a3d67fd7a8d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -22,33 +22,41 @@ import android.util.Log;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeMachine.State;
+import com.android.systemui.doze.dagger.DozeScope;
import java.io.PrintWriter;
+import javax.inject.Inject;
+
/**
* Handles dock events for ambient state changes.
*/
+@DozeScope
public class DozeDockHandler implements DozeMachine.Part {
private static final String TAG = "DozeDockHandler";
private static final boolean DEBUG = DozeService.DEBUG;
private final AmbientDisplayConfiguration mConfig;
- private final DozeMachine mMachine;
+ private DozeMachine mMachine;
private final DockManager mDockManager;
private final DockEventListener mDockEventListener;
private int mDockState = DockManager.STATE_NONE;
- DozeDockHandler(AmbientDisplayConfiguration config, DozeMachine machine,
- DockManager dockManager) {
- mMachine = machine;
+ @Inject
+ DozeDockHandler(AmbientDisplayConfiguration config, DockManager dockManager) {
mConfig = config;
mDockManager = dockManager;
mDockEventListener = new DockEventListener();
}
@Override
+ public void setDozeMachine(DozeMachine dozeMachine) {
+ mMachine = dozeMachine;
+ }
+
+ @Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
case INITIALIZED:
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
deleted file mode 100644
index 3bac196ca59f..000000000000
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.doze;
-
-import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.app.IWallpaperManager;
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
-import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.R;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dock.DockManager;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.phone.BiometricUnlockController;
-import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.util.sensors.AsyncSensorManager;
-import com.android.systemui.util.sensors.ProximitySensor;
-import com.android.systemui.util.wakelock.DelayedWakeLock;
-import com.android.systemui.util.wakelock.WakeLock;
-
-import javax.inject.Inject;
-
-public class DozeFactory {
-
- private final FalsingManager mFalsingManager;
- private final DozeLog mDozeLog;
- private final DozeParameters mDozeParameters;
- private final BatteryController mBatteryController;
- private final AsyncSensorManager mAsyncSensorManager;
- private final AlarmManager mAlarmManager;
- private final WakefulnessLifecycle mWakefulnessLifecycle;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final DockManager mDockManager;
- private final IWallpaperManager mWallpaperManager;
- private final ProximitySensor mProximitySensor;
- private final ProximitySensor.ProximityCheck mProximityCheck;
- private final DelayedWakeLock.Builder mDelayedWakeLockBuilder;
- private final Handler mHandler;
- private final BiometricUnlockController mBiometricUnlockController;
- private final BroadcastDispatcher mBroadcastDispatcher;
- private final DozeHost mDozeHost;
-
- @Inject
- public DozeFactory(FalsingManager falsingManager, DozeLog dozeLog,
- DozeParameters dozeParameters, BatteryController batteryController,
- AsyncSensorManager asyncSensorManager, AlarmManager alarmManager,
- WakefulnessLifecycle wakefulnessLifecycle, KeyguardUpdateMonitor keyguardUpdateMonitor,
- DockManager dockManager, @Nullable IWallpaperManager wallpaperManager,
- ProximitySensor proximitySensor, ProximitySensor.ProximityCheck proximityCheck,
- DelayedWakeLock.Builder delayedWakeLockBuilder, @Main Handler handler,
- BiometricUnlockController biometricUnlockController,
- BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) {
- mFalsingManager = falsingManager;
- mDozeLog = dozeLog;
- mDozeParameters = dozeParameters;
- mBatteryController = batteryController;
- mAsyncSensorManager = asyncSensorManager;
- mAlarmManager = alarmManager;
- mWakefulnessLifecycle = wakefulnessLifecycle;
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mDockManager = dockManager;
- mWallpaperManager = wallpaperManager;
- mProximitySensor = proximitySensor;
- mProximityCheck = proximityCheck;
- mDelayedWakeLockBuilder = delayedWakeLockBuilder;
- mHandler = handler;
- mBiometricUnlockController = biometricUnlockController;
- mBroadcastDispatcher = broadcastDispatcher;
- mDozeHost = dozeHost;
- }
-
- /** Creates a DozeMachine with its parts for {@code dozeService}. */
- DozeMachine assembleMachine(DozeService dozeService) {
- AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(dozeService);
- WakeLock wakeLock = mDelayedWakeLockBuilder.setHandler(mHandler).setTag("Doze").build();
-
- DozeMachine.Service wrappedService = dozeService;
- wrappedService = new DozeBrightnessHostForwarder(wrappedService, mDozeHost);
- wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(
- wrappedService, mDozeParameters);
- wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
- wrappedService, mDozeParameters);
-
- DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock,
- mWakefulnessLifecycle, mBatteryController, mDozeLog, mDockManager,
- mDozeHost);
- machine.setParts(new DozeMachine.Part[]{
- new DozePauser(mHandler, machine, mAlarmManager, mDozeParameters.getPolicy()),
- new DozeFalsingManagerAdapter(mFalsingManager),
- createDozeTriggers(dozeService, mAsyncSensorManager, mDozeHost,
- mAlarmManager, config, mDozeParameters, wakeLock,
- machine, mDockManager, mDozeLog, mProximityCheck),
- createDozeUi(dozeService, mDozeHost, wakeLock, machine, mHandler,
- mAlarmManager, mDozeParameters, mDozeLog),
- new DozeScreenState(wrappedService, mHandler, mDozeHost, mDozeParameters,
- wakeLock),
- createDozeScreenBrightness(dozeService, wrappedService, mAsyncSensorManager,
- mDozeHost, mDozeParameters, mHandler),
- new DozeWallpaperState(mWallpaperManager, mBiometricUnlockController,
- mDozeParameters),
- new DozeDockHandler(config, machine, mDockManager),
- new DozeAuthRemover(dozeService)
- });
-
- return machine;
- }
-
- private DozeMachine.Part createDozeScreenBrightness(Context context,
- DozeMachine.Service service, SensorManager sensorManager, DozeHost host,
- DozeParameters params, Handler handler) {
- Sensor sensor = DozeSensors.findSensorWithType(sensorManager,
- context.getString(R.string.doze_brightness_sensor_type));
- return new DozeScreenBrightness(context, service, sensorManager, sensor,
- mBroadcastDispatcher, host, handler, params.getPolicy());
- }
-
- private DozeTriggers createDozeTriggers(Context context, AsyncSensorManager sensorManager,
- DozeHost host, AlarmManager alarmManager, AmbientDisplayConfiguration config,
- DozeParameters params, WakeLock wakeLock,
- DozeMachine machine, DockManager dockManager, DozeLog dozeLog,
- ProximitySensor.ProximityCheck proximityCheck) {
- boolean allowPulseTriggers = true;
- return new DozeTriggers(context, machine, host, alarmManager, config, params,
- sensorManager, wakeLock, allowPulseTriggers, dockManager,
- mProximitySensor, proximityCheck, dozeLog, mBroadcastDispatcher);
-
- }
-
- private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock,
- DozeMachine machine, Handler handler, AlarmManager alarmManager,
- DozeParameters params, DozeLog dozeLog) {
- return new DozeUi(context, alarmManager, machine, wakeLock, host, handler, params,
- mKeyguardUpdateMonitor, dozeLog);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
index 250308d4c3a6..94b8ba305d0c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFalsingManagerAdapter.java
@@ -16,15 +16,20 @@
package com.android.systemui.doze;
+import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.plugins.FalsingManager;
+import javax.inject.Inject;
+
/**
* Notifies FalsingManager of whether or not AOD is showing.
*/
+@DozeScope
public class DozeFalsingManagerAdapter implements DozeMachine.Part {
private final FalsingManager mFalsingManager;
+ @Inject
public DozeFalsingManagerAdapter(FalsingManager falsingManager) {
mFalsingManager = falsingManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index ae7d82ac4a5e..b9d23ade2ee1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -28,6 +28,8 @@ import android.view.Display;
import com.android.internal.util.Preconditions;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.doze.dagger.DozeScope;
+import com.android.systemui.doze.dagger.WrappedService;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -38,6 +40,8 @@ import com.android.systemui.util.wakelock.WakeLock;
import java.io.PrintWriter;
import java.util.ArrayList;
+import javax.inject.Inject;
+
/**
* Orchestrates all things doze.
*
@@ -46,6 +50,7 @@ import java.util.ArrayList;
*
* During state transitions and in certain states, DozeMachine holds a wake lock.
*/
+@DozeScope
public class DozeMachine {
static final String TAG = "DozeMachine";
@@ -146,9 +151,11 @@ public class DozeMachine {
private boolean mWakeLockHeldForCurrentState = false;
private DockManager mDockManager;
- public DozeMachine(Service service, AmbientDisplayConfiguration config, WakeLock wakeLock,
- WakefulnessLifecycle wakefulnessLifecycle, BatteryController batteryController,
- DozeLog dozeLog, DockManager dockManager, DozeHost dozeHost) {
+ @Inject
+ public DozeMachine(@WrappedService Service service, AmbientDisplayConfiguration config,
+ WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle,
+ BatteryController batteryController, DozeLog dozeLog, DockManager dockManager,
+ DozeHost dozeHost, Part[] parts) {
mDozeService = service;
mConfig = config;
mWakefulnessLifecycle = wakefulnessLifecycle;
@@ -157,6 +164,10 @@ public class DozeMachine {
mDozeLog = dozeLog;
mDockManager = dockManager;
mDozeHost = dozeHost;
+ mParts = parts;
+ for (Part part : parts) {
+ part.setDozeMachine(this);
+ }
}
/**
@@ -168,12 +179,6 @@ public class DozeMachine {
}
}
- /** Initializes the set of {@link Part}s. Must be called exactly once after construction. */
- public void setParts(Part[] parts) {
- Preconditions.checkState(mParts == null);
- mParts = parts;
- }
-
/**
* Requests transitioning to {@code requestedState}.
*
@@ -432,6 +437,9 @@ public class DozeMachine {
/** Alerts that the screenstate is being changed. */
default void onScreenState(int state) {}
+
+ /** Sets the {@link DozeMachine} when this Part is associated with one. */
+ default void setDozeMachine(DozeMachine dozeMachine) {}
}
/** A wrapper interface for {@link android.service.dreams.DreamService} */
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
index 58f144830650..2b4067865415 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
@@ -19,25 +19,35 @@ package com.android.systemui.doze;
import android.app.AlarmManager;
import android.os.Handler;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.util.AlarmTimeout;
+import javax.inject.Inject;
+
/**
* Moves the doze machine from the pausing to the paused state after a timeout.
*/
+@DozeScope
public class DozePauser implements DozeMachine.Part {
public static final String TAG = DozePauser.class.getSimpleName();
private final AlarmTimeout mPauseTimeout;
- private final DozeMachine mMachine;
+ private DozeMachine mMachine;
private final AlwaysOnDisplayPolicy mPolicy;
- public DozePauser(Handler handler, DozeMachine machine, AlarmManager alarmManager,
+ @Inject
+ public DozePauser(@Main Handler handler, AlarmManager alarmManager,
AlwaysOnDisplayPolicy policy) {
- mMachine = machine;
mPauseTimeout = new AlarmTimeout(alarmManager, this::onTimeout, TAG, handler);
mPolicy = policy;
}
@Override
+ public void setDozeMachine(DozeMachine dozeMachine) {
+ mMachine = dozeMachine;
+ }
+
+ @Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
case DOZE_AOD_PAUSING:
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 64cfb4bcd058..342818de3d1e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -19,7 +19,6 @@ package com.android.systemui.doze;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -31,12 +30,17 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.view.Display;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.doze.dagger.BrightnessSensor;
+import com.android.systemui.doze.dagger.DozeScope;
+import com.android.systemui.doze.dagger.WrappedService;
+import com.android.systemui.util.sensors.AsyncSensorManager;
+
+import javax.inject.Inject;
/**
* Controls the screen brightness when dozing.
*/
+@DozeScope
public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachine.Part,
SensorEventListener {
private static final boolean DEBUG_AOD_BRIGHTNESS = SystemProperties
@@ -51,10 +55,8 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
private final Handler mHandler;
private final SensorManager mSensorManager;
private final Sensor mLightSensor;
- private final BroadcastDispatcher mBroadcastDispatcher;
private final int[] mSensorToBrightness;
private final int[] mSensorToScrimOpacity;
- private final boolean mDebuggable;
private boolean mRegistered;
private int mDefaultDozeBrightness;
@@ -71,40 +73,20 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
private int mDebugBrightnessBucket = -1;
private DozeMachine.State mState;
- @VisibleForTesting
- public DozeScreenBrightness(Context context, DozeMachine.Service service,
- SensorManager sensorManager, Sensor lightSensor,
- BroadcastDispatcher broadcastDispatcher, DozeHost host,
- Handler handler, int defaultDozeBrightness, int[] sensorToBrightness,
- int[] sensorToScrimOpacity, boolean debuggable) {
+ @Inject
+ public DozeScreenBrightness(Context context, @WrappedService DozeMachine.Service service,
+ AsyncSensorManager sensorManager, @BrightnessSensor Sensor lightSensor,
+ DozeHost host, Handler handler, AlwaysOnDisplayPolicy alwaysOnDisplayPolicy) {
mContext = context;
mDozeService = service;
mSensorManager = sensorManager;
mLightSensor = lightSensor;
- mBroadcastDispatcher = broadcastDispatcher;
mDozeHost = host;
mHandler = handler;
- mDebuggable = debuggable;
-
- mDefaultDozeBrightness = defaultDozeBrightness;
- mSensorToBrightness = sensorToBrightness;
- mSensorToScrimOpacity = sensorToScrimOpacity;
-
- if (mDebuggable) {
- IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_AOD_BRIGHTNESS);
- mBroadcastDispatcher.registerReceiverWithHandler(this, filter, handler, UserHandle.ALL);
- }
- }
- public DozeScreenBrightness(Context context, DozeMachine.Service service,
- SensorManager sensorManager, Sensor lightSensor,
- BroadcastDispatcher broadcastDispatcher, DozeHost host, Handler handler,
- AlwaysOnDisplayPolicy policy) {
- this(context, service, sensorManager, lightSensor, broadcastDispatcher, host, handler,
- context.getResources().getInteger(
- com.android.internal.R.integer.config_screenBrightnessDoze),
- policy.screenBrightnessArray, policy.dimmingScrimArray, DEBUG_AOD_BRIGHTNESS);
+ mDefaultDozeBrightness = alwaysOnDisplayPolicy.defaultDozeBrightness;
+ mSensorToBrightness = alwaysOnDisplayPolicy.screenBrightnessArray;
+ mSensorToScrimOpacity = alwaysOnDisplayPolicy.dimmingScrimArray;
}
@Override
@@ -139,9 +121,6 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
private void onDestroy() {
setLightSensorEnabled(false);
- if (mDebuggable) {
- mBroadcastDispatcher.unregisterReceiver(this);
- }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 915359374bfe..8c50a16b566f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -26,13 +26,19 @@ import android.os.Handler;
import android.util.Log;
import android.view.Display;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.doze.dagger.DozeScope;
+import com.android.systemui.doze.dagger.WrappedService;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.wakelock.SettableWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
+import javax.inject.Inject;
+
/**
* Controls the screen when dozing.
*/
+@DozeScope
public class DozeScreenState implements DozeMachine.Part {
private static final boolean DEBUG = DozeService.DEBUG;
@@ -59,8 +65,9 @@ public class DozeScreenState implements DozeMachine.Part {
private int mPendingScreenState = Display.STATE_UNKNOWN;
private SettableWakeLock mWakeLock;
- public DozeScreenState(DozeMachine.Service service, Handler handler, DozeHost host,
- DozeParameters parameters, WakeLock wakeLock) {
+ @Inject
+ public DozeScreenState(@WrappedService DozeMachine.Service service, @Main Handler handler,
+ DozeHost host, DozeParameters parameters, WakeLock wakeLock) {
mDozeService = service;
mHandler = handler;
mParameters = parameters;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index aebf41b884c4..37bdda8a06a1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -21,7 +21,6 @@ import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_
import android.annotation.AnyThread;
import android.app.ActivityManager;
-import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -64,10 +63,8 @@ public class DozeSensors {
private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
private final Context mContext;
- private final AlarmManager mAlarmManager;
private final AsyncSensorManager mSensorManager;
private final ContentResolver mResolver;
- private final DozeParameters mDozeParameters;
private final AmbientDisplayConfiguration mConfig;
private final WakeLock mWakeLock;
private final Consumer<Boolean> mProxCallback;
@@ -98,14 +95,12 @@ public class DozeSensors {
}
}
- public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager,
+ DozeSensors(Context context, AsyncSensorManager sensorManager,
DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog,
ProximitySensor proximitySensor) {
mContext = context;
- mAlarmManager = alarmManager;
mSensorManager = sensorManager;
- mDozeParameters = dozeParameters;
mConfig = config;
mWakeLock = wakeLock;
mProxCallback = proxCallback;
@@ -206,7 +201,10 @@ public class DozeSensors {
return findSensorWithType(mSensorManager, type);
}
- static Sensor findSensorWithType(SensorManager sensorManager, String type) {
+ /**
+ * Utility method to find a {@link Sensor} for the supplied string type.
+ */
+ public static Sensor findSensorWithType(SensorManager sensorManager, String type) {
if (TextUtils.isEmpty(type)) {
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index d2bebb7b27d1..19b0ea1db04e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -22,6 +22,7 @@ import android.os.SystemClock;
import android.service.dreams.DreamService;
import android.util.Log;
+import com.android.systemui.doze.dagger.DozeComponent;
import com.android.systemui.plugins.DozeServicePlugin;
import com.android.systemui.plugins.DozeServicePlugin.RequestDoze;
import com.android.systemui.plugins.PluginListener;
@@ -36,16 +37,16 @@ public class DozeService extends DreamService
implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
private static final String TAG = "DozeService";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final DozeFactory mDozeFactory;
+ private final DozeComponent.Builder mDozeComponentBuilder;
private DozeMachine mDozeMachine;
private DozeServicePlugin mDozePlugin;
private PluginManager mPluginManager;
@Inject
- public DozeService(DozeFactory dozeFactory, PluginManager pluginManager) {
+ public DozeService(DozeComponent.Builder dozeComponentBuilder, PluginManager pluginManager) {
+ mDozeComponentBuilder = dozeComponentBuilder;
setDebug(DEBUG);
- mDozeFactory = dozeFactory;
mPluginManager = pluginManager;
}
@@ -56,7 +57,8 @@ public class DozeService extends DreamService
setWindowless(true);
mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
- mDozeMachine = mDozeFactory.assembleMachine(this);
+ DozeComponent dozeComponent = mDozeComponentBuilder.build(this);
+ mDozeMachine = dozeComponent.getDozeMachine();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index eb2463b02ae4..0800a201bd92 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -41,6 +41,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Dependency;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;
import com.android.systemui.util.sensors.AsyncSensorManager;
@@ -51,9 +52,12 @@ import java.io.PrintWriter;
import java.util.Optional;
import java.util.function.Consumer;
+import javax.inject.Inject;
+
/**
* Handles triggers for ambient state changes.
*/
+@DozeScope
public class DozeTriggers implements DozeMachine.Part {
private static final String TAG = "DozeTriggers";
@@ -73,7 +77,7 @@ public class DozeTriggers implements DozeMachine.Part {
private static final int PROXIMITY_TIMEOUT_DELAY_MS = 500;
private final Context mContext;
- private final DozeMachine mMachine;
+ private DozeMachine mMachine;
private final DozeLog mDozeLog;
private final DozeSensors mDozeSensors;
private final DozeHost mDozeHost;
@@ -153,21 +157,21 @@ public class DozeTriggers implements DozeMachine.Part {
}
}
- public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
+ @Inject
+ public DozeTriggers(Context context, DozeHost dozeHost,
AlarmManager alarmManager, AmbientDisplayConfiguration config,
DozeParameters dozeParameters, AsyncSensorManager sensorManager,
- WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager,
+ WakeLock wakeLock, DockManager dockManager,
ProximitySensor proximitySensor, ProximitySensor.ProximityCheck proxCheck,
DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher) {
mContext = context;
- mMachine = machine;
mDozeHost = dozeHost;
mConfig = config;
mDozeParameters = dozeParameters;
mSensorManager = sensorManager;
mWakeLock = wakeLock;
- mAllowPulseTriggers = allowPulseTriggers;
- mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
+ mAllowPulseTriggers = true;
+ mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters,
config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor);
mUiModeManager = mContext.getSystemService(UiModeManager.class);
mDockManager = dockManager;
@@ -177,6 +181,11 @@ public class DozeTriggers implements DozeMachine.Part {
}
@Override
+ public void setDozeMachine(DozeMachine dozeMachine) {
+ mMachine = dozeMachine;
+ }
+
+ @Override
public void destroy() {
mDozeSensors.destroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 1c056215f1cb..0fdaae82e2d0 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -29,15 +29,20 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.wakelock.WakeLock;
import java.util.Calendar;
+import javax.inject.Inject;
+
/**
* The policy controlling doze.
*/
+@DozeScope
public class DozeUi implements DozeMachine.Part {
private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min
@@ -45,7 +50,7 @@ public class DozeUi implements DozeMachine.Part {
private final DozeHost mHost;
private final Handler mHandler;
private final WakeLock mWakeLock;
- private final DozeMachine mMachine;
+ private DozeMachine mMachine;
private final AlarmTimeout mTimeTicker;
private final boolean mCanAnimateTransition;
private final DozeParameters mDozeParameters;
@@ -64,12 +69,12 @@ public class DozeUi implements DozeMachine.Part {
private long mLastTimeTickElapsed = 0;
- public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine,
- WakeLock wakeLock, DozeHost host, Handler handler,
+ @Inject
+ public DozeUi(Context context, AlarmManager alarmManager,
+ WakeLock wakeLock, DozeHost host, @Main Handler handler,
DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor,
DozeLog dozeLog) {
mContext = context;
- mMachine = machine;
mWakeLock = wakeLock;
mHost = host;
mHandler = handler;
@@ -80,6 +85,11 @@ public class DozeUi implements DozeMachine.Part {
mDozeLog = dozeLog;
}
+ @Override
+ public void setDozeMachine(DozeMachine dozeMachine) {
+ mMachine = dozeMachine;
+ }
+
/**
* Decide if we're taking over the screen-off animation
* when the device was configured to skip doze after screen off.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index 7aeb7851bbd1..d5b6cb1a6250 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -21,15 +21,19 @@ import android.app.IWallpaperManager;
import android.os.RemoteException;
import android.util.Log;
+import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.DozeParameters;
import java.io.PrintWriter;
+import javax.inject.Inject;
+
/**
* Propagates doze state to wallpaper engine.
*/
+@DozeScope
public class DozeWallpaperState implements DozeMachine.Part {
private static final String TAG = "DozeWallpaperState";
@@ -41,8 +45,9 @@ public class DozeWallpaperState implements DozeMachine.Part {
private final BiometricUnlockController mBiometricUnlockController;
private boolean mIsAmbientMode;
+ @Inject
public DozeWallpaperState(
- IWallpaperManager wallpaperManagerService,
+ @Nullable IWallpaperManager wallpaperManagerService,
BiometricUnlockController biometricUnlockController,
DozeParameters parameters) {
mWallpaperManagerService = wallpaperManagerService;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/BrightnessSensor.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/BrightnessSensor.java
new file mode 100644
index 000000000000..5af8af366b69
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/BrightnessSensor.java
@@ -0,0 +1,30 @@
+/*
+ * 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.systemui.doze.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface BrightnessSensor {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
new file mode 100644
index 000000000000..e925927e7564
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeComponent.java
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.doze.dagger;
+
+import com.android.systemui.doze.DozeMachine;
+import com.android.systemui.doze.DozeService;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+
+/**
+ * Dagger component for items that require a {@link DozeService}.
+ */
+@Subcomponent(modules = {DozeModule.class})
+@DozeScope
+public interface DozeComponent {
+ /** Simple Builder for {@link DozeComponent}. */
+ @Subcomponent.Factory
+ interface Builder {
+ DozeComponent build(@BindsInstance DozeService dozeService);
+ }
+
+ /** Supply a {@link DozeMachine}. */
+ @DozeScope
+ DozeMachine getDozeMachine();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
new file mode 100644
index 000000000000..a12e280fcca6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java
@@ -0,0 +1,99 @@
+/*
+ * 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.systemui.doze.dagger;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.os.Handler;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.doze.DozeAuthRemover;
+import com.android.systemui.doze.DozeBrightnessHostForwarder;
+import com.android.systemui.doze.DozeDockHandler;
+import com.android.systemui.doze.DozeFalsingManagerAdapter;
+import com.android.systemui.doze.DozeHost;
+import com.android.systemui.doze.DozeMachine;
+import com.android.systemui.doze.DozePauser;
+import com.android.systemui.doze.DozeScreenBrightness;
+import com.android.systemui.doze.DozeScreenState;
+import com.android.systemui.doze.DozeScreenStatePreventingAdapter;
+import com.android.systemui.doze.DozeSensors;
+import com.android.systemui.doze.DozeService;
+import com.android.systemui.doze.DozeSuspendScreenStatePreventingAdapter;
+import com.android.systemui.doze.DozeTriggers;
+import com.android.systemui.doze.DozeUi;
+import com.android.systemui.doze.DozeWallpaperState;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.util.wakelock.DelayedWakeLock;
+import com.android.systemui.util.wakelock.WakeLock;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** Dagger module for use with {@link com.android.systemui.doze.dagger.DozeComponent}. */
+@Module
+public abstract class DozeModule {
+ @Provides
+ @DozeScope
+ @WrappedService
+ static DozeMachine.Service providesWrappedService(DozeService dozeService, DozeHost dozeHost,
+ DozeParameters dozeParameters) {
+ DozeMachine.Service wrappedService = dozeService;
+ wrappedService = new DozeBrightnessHostForwarder(wrappedService, dozeHost);
+ wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(
+ wrappedService, dozeParameters);
+ wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
+ wrappedService, dozeParameters);
+
+ return wrappedService;
+ }
+
+ @Provides
+ @DozeScope
+ static WakeLock providesDozeWakeLock(DelayedWakeLock.Builder delayedWakeLockBuilder,
+ @Main Handler handler) {
+ return delayedWakeLockBuilder.setHandler(handler).setTag("Doze").build();
+ }
+
+ @Provides
+ static DozeMachine.Part[] providesDozeMachinePartes(DozePauser dozePauser,
+ DozeFalsingManagerAdapter dozeFalsingManagerAdapter, DozeTriggers dozeTriggers,
+ DozeUi dozeUi, DozeScreenState dozeScreenState,
+ DozeScreenBrightness dozeScreenBrightness, DozeWallpaperState dozeWallpaperState,
+ DozeDockHandler dozeDockHandler, DozeAuthRemover dozeAuthRemover) {
+ return new DozeMachine.Part[]{
+ dozePauser,
+ dozeFalsingManagerAdapter,
+ dozeTriggers,
+ dozeUi,
+ dozeScreenState,
+ dozeScreenBrightness,
+ dozeWallpaperState,
+ dozeDockHandler,
+ dozeAuthRemover
+ };
+ }
+
+ @Provides
+ @BrightnessSensor
+ static Sensor providesBrightnessSensor(AsyncSensorManager sensorManager, Context context) {
+ return DozeSensors.findSensorWithType(sensorManager,
+ context.getString(R.string.doze_brightness_sensor_type));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java
new file mode 100644
index 000000000000..7a8b8166a969
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java
@@ -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 com.android.systemui.doze.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Scope;
+
+/**
+ * Scope annotation for singleton items within the StatusBarComponent.
+ */
+@Documented
+@Retention(RUNTIME)
+@Scope
+public @interface DozeScope {}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/WrappedService.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/WrappedService.java
new file mode 100644
index 000000000000..ca8a158f21a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/WrappedService.java
@@ -0,0 +1,30 @@
+/*
+ * 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.systemui.doze.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface WrappedService {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 127c5dd54d72..e12b7dd259a5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -5,6 +5,7 @@ import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
+import android.util.Log
import android.util.MathUtils
import android.view.LayoutInflater
import android.view.View
@@ -25,6 +26,7 @@ import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Singleton
+private const val TAG = "MediaCarouselController"
private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)
/**
@@ -236,7 +238,9 @@ class MediaCarouselController @Inject constructor(
val oldData = mediaPlayers[oldKey]
if (oldData != null) {
val oldData = mediaPlayers.remove(oldKey)
- mediaPlayers.put(key, oldData!!)
+ mediaPlayers.put(key, oldData!!)?.let {
+ Log.wtf(TAG, "new key $key already exists when migrating from $oldKey")
+ }
}
var existingPlayer = mediaPlayers[key]
if (existingPlayer == null) {
@@ -271,6 +275,11 @@ class MediaCarouselController @Inject constructor(
updatePageIndicator()
mediaCarouselScrollHandler.onPlayersChanged()
mediaCarousel.requiresRemeasuring = true
+ // Check postcondition: mediaContent should have the same number of children as there are
+ // elements in mediaPlayers.
+ if (mediaPlayers.size != mediaContent.childCount) {
+ Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync")
+ }
}
private fun removePlayer(key: String) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
index e8f0e069c98d..d0642ccf9714 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
@@ -33,23 +33,31 @@ class MediaDataCombineLatest @Inject constructor(
init {
dataSource.addListener(object : MediaDataManager.Listener {
override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
- if (oldKey != null && !oldKey.equals(key)) {
- val s = entries[oldKey]?.second
- entries[key] = data to entries[oldKey]?.second
- entries.remove(oldKey)
+ if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
+ entries[key] = data to entries.remove(oldKey)?.second
+ update(key, oldKey)
} else {
entries[key] = data to entries[key]?.second
+ update(key, key)
}
- update(key, oldKey)
}
override fun onMediaDataRemoved(key: String) {
remove(key)
}
})
deviceSource.addListener(object : MediaDeviceManager.Listener {
- override fun onMediaDeviceChanged(key: String, data: MediaDeviceData?) {
- entries[key] = entries[key]?.first to data
- update(key, key)
+ override fun onMediaDeviceChanged(
+ key: String,
+ oldKey: String?,
+ data: MediaDeviceData?
+ ) {
+ if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
+ entries[key] = entries.remove(oldKey)?.first to data
+ update(key, oldKey)
+ } else {
+ entries[key] = entries[key]?.first to data
+ update(key, key)
+ }
}
override fun onKeyRemoved(key: String) {
remove(key)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 8cb93bfc6d4d..299ae5b50aa9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -517,22 +517,36 @@ class MediaDataManager(
fun onNotificationRemoved(key: String) {
Assert.isMainThread()
- if (useMediaResumption && mediaEntries.get(key)?.resumeAction != null) {
+ val removed = mediaEntries.remove(key)
+ if (useMediaResumption && removed?.resumeAction != null) {
Log.d(TAG, "Not removing $key because resumable")
- // Move to resume key aka package name
- val data = mediaEntries.remove(key)!!
- val resumeAction = getResumeMediaAction(data.resumeAction!!)
- val updated = data.copy(token = null, actions = listOf(resumeAction),
+ // Move to resume key (aka package name) if that key doesn't already exist.
+ val resumeAction = getResumeMediaAction(removed.resumeAction!!)
+ val updated = removed.copy(token = null, actions = listOf(resumeAction),
actionsToShowInCompact = listOf(0), active = false, resumption = true)
- mediaEntries.put(data.packageName, updated)
- // Notify listeners of "new" controls
+ val pkg = removed?.packageName
+ val migrate = mediaEntries.put(pkg, updated) == null
+ // Notify listeners of "new" controls when migrating or removed and update when not
val listenersCopy = listeners.toSet()
- listenersCopy.forEach {
- it.onMediaDataLoaded(data.packageName, key, updated)
+ if (migrate) {
+ listenersCopy.forEach {
+ it.onMediaDataLoaded(pkg, key, updated)
+ }
+ } else {
+ // Since packageName is used for the key of the resumption controls, it is
+ // possible that another notification has already been reused for the resumption
+ // controls of this package. In this case, rather than renaming this player as
+ // packageName, just remove it and then send a update to the existing resumption
+ // controls.
+ listenersCopy.forEach {
+ it.onMediaDataRemoved(key)
+ }
+ listenersCopy.forEach {
+ it.onMediaDataLoaded(pkg, pkg, updated)
+ }
}
return
}
- val removed = mediaEntries.remove(key)
if (removed != null) {
val listenersCopy = listeners.toSet()
listenersCopy.forEach {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 7ae2dc5c0941..143f8496e7aa 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -71,7 +71,8 @@ class MediaDeviceManager @Inject constructor(
val controller = data.token?.let {
MediaController(context, it)
}
- entry = Token(key, controller, localMediaManagerFactory.create(data.packageName))
+ entry = Token(key, oldKey, controller,
+ localMediaManagerFactory.create(data.packageName))
entries[key] = entry
entry.start()
}
@@ -98,23 +99,24 @@ class MediaDeviceManager @Inject constructor(
}
}
- private fun processDevice(key: String, device: MediaDevice?) {
+ private fun processDevice(key: String, oldKey: String?, device: MediaDevice?) {
val enabled = device != null
val data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name)
listeners.forEach {
- it.onMediaDeviceChanged(key, data)
+ it.onMediaDeviceChanged(key, oldKey, data)
}
}
interface Listener {
/** Called when the route has changed for a given notification. */
- fun onMediaDeviceChanged(key: String, data: MediaDeviceData?)
+ fun onMediaDeviceChanged(key: String, oldKey: String?, data: MediaDeviceData?)
/** Called when the notification was removed. */
fun onKeyRemoved(key: String)
}
private inner class Token(
val key: String,
+ val oldKey: String?,
val controller: MediaController?,
val localMediaManager: LocalMediaManager
) : LocalMediaManager.DeviceCallback {
@@ -125,7 +127,7 @@ class MediaDeviceManager @Inject constructor(
set(value) {
if (!started || value != field) {
field = value
- processDevice(key, value)
+ processDevice(key, oldKey, value)
}
}
fun start() {
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java
index 5d9439f5f127..c581ac677532 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java
@@ -16,6 +16,8 @@
package com.android.systemui.onehanded;
+import android.view.SurfaceControl;
+
/**
* Additional callback interface for OneHanded animation
*/
@@ -30,7 +32,7 @@ public interface OneHandedAnimationCallback {
/**
* Called when OneHanded animation is ended.
*/
- default void onOneHandedAnimationEnd(
+ default void onOneHandedAnimationEnd(SurfaceControl.Transaction tx,
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
index 08f08c585224..1926c44abcba 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
@@ -19,16 +19,16 @@ package com.android.systemui.onehanded;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
-import android.content.Context;
import android.graphics.Rect;
import android.view.SurfaceControl;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.view.animation.OvershootInterpolator;
import androidx.annotation.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
import javax.inject.Inject;
@@ -39,18 +39,6 @@ public class OneHandedAnimationController {
private static final float FRACTION_START = 0f;
private static final float FRACTION_END = 1f;
- public static final int ANIM_TYPE_TRANSLATE = 0;
- public static final int ANIM_TYPE_SCALE = 1;
-
- // Note: ANIM_TYPE_SCALE reserve for the future development
- @IntDef(prefix = {"ANIM_TYPE_"}, value = {
- ANIM_TYPE_TRANSLATE,
- ANIM_TYPE_SCALE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AnimationType {
- }
-
public static final int TRANSITION_DIRECTION_NONE = 0;
public static final int TRANSITION_DIRECTION_TRIGGER = 1;
public static final int TRANSITION_DIRECTION_EXIT = 2;
@@ -64,42 +52,57 @@ public class OneHandedAnimationController {
public @interface TransitionDirection {
}
- private final Interpolator mFastOutSlowInInterpolator;
+ private final Interpolator mOvershootInterpolator;
private final OneHandedSurfaceTransactionHelper mSurfaceTransactionHelper;
- private OneHandedTransitionAnimator mCurrentAnimator;
+ private final HashMap<SurfaceControl, OneHandedTransitionAnimator> mAnimatorMap =
+ new HashMap<>();
/**
* Constructor of OneHandedAnimationController
*/
@Inject
- public OneHandedAnimationController(Context context,
+ public OneHandedAnimationController(
OneHandedSurfaceTransactionHelper surfaceTransactionHelper) {
mSurfaceTransactionHelper = surfaceTransactionHelper;
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
+ mOvershootInterpolator = new OvershootInterpolator();
}
@SuppressWarnings("unchecked")
OneHandedTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds,
Rect endBounds) {
- if (mCurrentAnimator == null) {
- mCurrentAnimator = setupOneHandedTransitionAnimator(
- OneHandedTransitionAnimator.ofBounds(leash, startBounds, endBounds));
- } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_TRANSLATE
- && mCurrentAnimator.isRunning()) {
- mCurrentAnimator.updateEndValue(endBounds);
+ final OneHandedTransitionAnimator animator = mAnimatorMap.get(leash);
+ if (animator == null) {
+ mAnimatorMap.put(leash, setupOneHandedTransitionAnimator(
+ OneHandedTransitionAnimator.ofBounds(leash, startBounds, endBounds)));
+ } else if (animator.isRunning()) {
+ animator.updateEndValue(endBounds);
} else {
- mCurrentAnimator.cancel();
- mCurrentAnimator = setupOneHandedTransitionAnimator(
- OneHandedTransitionAnimator.ofBounds(leash, startBounds, endBounds));
+ animator.cancel();
+ mAnimatorMap.put(leash, setupOneHandedTransitionAnimator(
+ OneHandedTransitionAnimator.ofBounds(leash, startBounds, endBounds)));
+ }
+ return mAnimatorMap.get(leash);
+ }
+
+ HashMap<SurfaceControl, OneHandedTransitionAnimator> getAnimatorMap() {
+ return mAnimatorMap;
+ }
+
+ boolean isAnimatorsConsumed() {
+ return mAnimatorMap.isEmpty();
+ }
+
+ void removeAnimator(SurfaceControl key) {
+ final OneHandedTransitionAnimator animator = mAnimatorMap.remove(key);
+ if (animator != null && animator.isRunning()) {
+ animator.cancel();
}
- return mCurrentAnimator;
}
OneHandedTransitionAnimator setupOneHandedTransitionAnimator(
OneHandedTransitionAnimator animator) {
animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper);
- animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setInterpolator(mOvershootInterpolator);
animator.setFloatValues(FRACTION_START, FRACTION_END);
return animator;
}
@@ -114,7 +117,6 @@ public class OneHandedAnimationController {
ValueAnimator.AnimatorListener {
private final SurfaceControl mLeash;
- private final @AnimationType int mAnimationType;
private T mStartValue;
private T mEndValue;
private T mCurrentValue;
@@ -127,10 +129,8 @@ public class OneHandedAnimationController {
private @TransitionDirection int mTransitionDirection;
private int mTransitionOffset;
- private OneHandedTransitionAnimator(SurfaceControl leash, @AnimationType int animationType,
- T startValue, T endValue) {
+ private OneHandedTransitionAnimator(SurfaceControl leash, T startValue, T endValue) {
mLeash = leash;
- mAnimationType = animationType;
mStartValue = startValue;
mEndValue = endValue;
addListener(this);
@@ -150,8 +150,10 @@ public class OneHandedAnimationController {
@Override
public void onAnimationEnd(Animator animation) {
mCurrentValue = mEndValue;
+ final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
+ onEndTransaction(mLeash, tx);
if (mOneHandedAnimationCallback != null) {
- mOneHandedAnimationCallback.onOneHandedAnimationEnd(this);
+ mOneHandedAnimationCallback.onOneHandedAnimationEnd(tx, this);
}
}
@@ -196,6 +198,10 @@ public class OneHandedAnimationController {
return this;
}
+ SurfaceControl getLeash() {
+ return mLeash;
+ }
+
Rect getDestinationBounds() {
return (Rect) mEndValue;
}
@@ -227,11 +233,6 @@ public class OneHandedAnimationController {
return mEndValue;
}
- @AnimationType
- int getAnimationType() {
- return mAnimationType;
- }
-
void setCurrentValue(T value) {
mCurrentValue = value;
}
@@ -250,11 +251,9 @@ public class OneHandedAnimationController {
@VisibleForTesting
static OneHandedTransitionAnimator<Rect> ofBounds(SurfaceControl leash,
Rect startValue, Rect endValue) {
- // At R, we only support translate type first.
- final int animType = ANIM_TYPE_TRANSLATE;
- return new OneHandedTransitionAnimator<Rect>(leash, animType,
- new Rect(startValue), new Rect(endValue)) {
+ return new OneHandedTransitionAnimator<Rect>(leash, new Rect(startValue),
+ new Rect(endValue)) {
private final Rect mTmpRect = new Rect();
@@ -282,7 +281,7 @@ public class OneHandedAnimationController {
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
getSurfaceTransactionHelper()
.alpha(tx, leash, 1f)
- .crop(tx, leash, getStartValue())
+ .translate(tx, leash, getEndValue().top - getStartValue().top)
.round(tx, leash);
tx.apply();
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
index 063d7c843aa5..28d70491b6ee 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -22,11 +22,14 @@ import static com.android.systemui.onehanded.OneHandedAnimationController.TRANSI
import static com.android.systemui.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_TRIGGER;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
+import android.view.Display;
+import android.view.DisplayInfo;
import android.view.SurfaceControl;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;
@@ -39,10 +42,12 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.systemui.Dumpable;
import com.android.systemui.wm.DisplayController;
+import com.android.systemui.wm.DisplayLayout;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Objects;
@@ -68,22 +73,22 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
@VisibleForTesting
static final int MSG_OFFSET_FINISH = 3;
- private final Handler mUpdateHandler;
+ private final Rect mLastVisualDisplayBounds = new Rect();
+ private final Rect mDefaultDisplayBounds = new Rect();
+ private Handler mUpdateHandler;
private boolean mIsInOneHanded;
private int mEnterExitAnimationDurationMs;
@VisibleForTesting
- DisplayAreaInfo mDisplayAreaInfo;
+ HashMap<DisplayAreaInfo, SurfaceControl> mDisplayAreaMap = new HashMap();
private DisplayController mDisplayController;
+ private DisplayLayout mDisplayLayout;
+ private DisplayInfo mDisplayInfo = new DisplayInfo();
private OneHandedAnimationController mAnimationController;
- private SurfaceControl mLeash;
- private List<OneHandedTransitionCallback> mTransitionCallbacks = new ArrayList<>();
- private OneHandedSurfaceTransactionHelper mSurfaceTransactionHelper;
private OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
- private Rect mLastVisualDisplayBounds;
- private Rect mDefaultDisplayBounds;
+ private List<OneHandedTransitionCallback> mTransitionCallbacks = new ArrayList<>();
@VisibleForTesting
OneHandedAnimationCallback mOneHandedAnimationCallback =
@@ -94,17 +99,23 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
}
@Override
- public void onOneHandedAnimationEnd(
+ public void onOneHandedAnimationEnd(SurfaceControl.Transaction tx,
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
- mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_OFFSET_FINISH,
- obtainArgsFromAnimator(animator)));
+ mAnimationController.removeAnimator(animator.getLeash());
+ if (mAnimationController.isAnimatorsConsumed()) {
+ mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_OFFSET_FINISH,
+ obtainArgsFromAnimator(animator)));
+ }
}
@Override
public void onOneHandedAnimationCancel(
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
- mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_OFFSET_FINISH,
- obtainArgsFromAnimator(animator)));
+ mAnimationController.removeAnimator(animator.getLeash());
+ if (mAnimationController.isAnimatorsConsumed()) {
+ mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_OFFSET_FINISH,
+ obtainArgsFromAnimator(animator)));
+ }
}
};
@@ -112,34 +123,24 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
private Handler.Callback mUpdateCallback = (msg) -> {
SomeArgs args = (SomeArgs) msg.obj;
final Rect currentBounds = args.arg1 != null ? (Rect) args.arg1 : mDefaultDisplayBounds;
- final int xOffset = args.argi1;
final int yOffset = args.argi2;
final int direction = args.argi3;
- if (mLeash == null || !mLeash.isValid()) {
- Log.w(TAG, "mLeash is null, abort transition");
- return false;
- }
switch (msg.what) {
case MSG_RESET_IMMEDIATE:
- final OneHandedAnimationController.OneHandedTransitionAnimator animator =
- mAnimationController.getAnimator(mLeash, currentBounds,
- mDefaultDisplayBounds);
- if (animator != null && animator.isRunning()) {
- animator.cancel();
- }
- final SurfaceControl.Transaction tx =
- mSurfaceControlTransactionFactory.getTransaction();
- tx.setPosition(mLeash, 0, 0)
- .setWindowCrop(mLeash, -1/* reset */, -1/* reset */)
- .apply();
- finishOffset(currentBounds, yOffset, direction);
+ resetWindowsOffset();
+ mLastVisualDisplayBounds.set(currentBounds);
+ finishOffset(0, TRANSITION_DIRECTION_EXIT);
break;
case MSG_OFFSET_ANIMATE:
- offsetWindows(currentBounds, 0, yOffset, direction, mEnterExitAnimationDurationMs);
+ final Rect toBounds = new Rect(mDefaultDisplayBounds.left,
+ mDefaultDisplayBounds.top + yOffset,
+ mDefaultDisplayBounds.right,
+ mDefaultDisplayBounds.bottom + yOffset);
+ offsetWindows(currentBounds, toBounds, direction, mEnterExitAnimationDurationMs);
break;
case MSG_OFFSET_FINISH:
- finishOffset(currentBounds, yOffset, direction);
+ finishOffset(yOffset, direction);
break;
}
args.recycle();
@@ -152,17 +153,15 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
@Inject
public OneHandedDisplayAreaOrganizer(Context context,
DisplayController displayController,
- OneHandedAnimationController animationController,
- OneHandedSurfaceTransactionHelper surfaceTransactionHelper) {
-
+ OneHandedAnimationController animationController) {
mUpdateHandler = new Handler(OneHandedThread.get().getLooper(), mUpdateCallback);
mAnimationController = animationController;
mDisplayController = displayController;
+ mDisplayLayout = getDisplayLayout(context);
+ mDisplayLayout.getStableBounds(mDefaultDisplayBounds);
+ mLastVisualDisplayBounds.set(mDefaultDisplayBounds);
mEnterExitAnimationDurationMs = context.getResources().getInteger(
com.android.systemui.R.integer.config_one_handed_translate_animation_duration);
- mDefaultDisplayBounds = new Rect(0, 0, getDisplayBounds().x, getDisplayBounds().y);
- mLastVisualDisplayBounds = new Rect(mDefaultDisplayBounds);
- mSurfaceTransactionHelper = surfaceTransactionHelper;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
}
@@ -171,40 +170,52 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
@NonNull SurfaceControl leash) {
Objects.requireNonNull(displayAreaInfo, "displayAreaInfo must not be null");
Objects.requireNonNull(leash, "leash must not be null");
- mDisplayAreaInfo = displayAreaInfo;
- mLeash = leash;
- }
- @Override
- public void onDisplayAreaInfoChanged(@NonNull DisplayAreaInfo displayAreaInfo) {
- Objects.requireNonNull(displayAreaInfo, "displayArea must not be null");
- // Stop one handed without animation and reset cropped size immediately
- if (displayAreaInfo.configuration.orientation
- != mDisplayAreaInfo.configuration.orientation) {
- final Rect newBounds = displayAreaInfo.configuration.windowConfiguration.getBounds();
- resetImmediately(newBounds);
+ if (displayAreaInfo.featureId != FEATURE_ONE_HANDED) {
+ Log.w(TAG, "Bypass onDisplayAreaAppeared()! displayAreaInfo=" + displayAreaInfo);
+ return;
}
- mDisplayAreaInfo = displayAreaInfo;
+ mDisplayAreaMap.put(displayAreaInfo, leash);
}
@Override
public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) {
Objects.requireNonNull(displayAreaInfo,
"Requires valid displayArea, and displayArea must not be null");
- if (displayAreaInfo.token.asBinder() != mDisplayAreaInfo.token.asBinder()) {
+
+ if (!mDisplayAreaMap.containsKey(displayAreaInfo)) {
Log.w(TAG, "Unrecognized token: " + displayAreaInfo.token);
return;
}
- mDisplayAreaInfo = displayAreaInfo;
+ mDisplayAreaMap.remove(displayAreaInfo);
+ }
- // Stop one handed immediately
- if (isInOneHanded()) {
- final Rect newBounds = mDisplayAreaInfo.configuration.windowConfiguration.getBounds();
- resetImmediately(newBounds);
+ @Override
+ public void unregisterOrganizer() {
+ super.unregisterOrganizer();
+ if (mDisplayAreaMap != null) {
+ mDisplayAreaMap.clear();
}
}
/**
+ * Handler for display rotation changes.
+ */
+ public void onRotateDisplay(Resources res, int toRotation) {
+ // Stop one handed without animation and reset cropped size immediately
+ final Rect newBounds = new Rect();
+ mDisplayLayout.rotateTo(res, toRotation);
+ mDisplayLayout.getStableBounds(newBounds);
+
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = newBounds;
+ args.argi1 = 0 /* xOffset */;
+ args.argi2 = 0 /* yOffset */;
+ args.argi3 = TRANSITION_DIRECTION_EXIT;
+ mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESET_IMMEDIATE, args));
+ }
+
+ /**
* Offset the windows by a given offset on Y-axis, triggered also from screen rotation.
* Directly perform manipulation/offset on the leash.
*/
@@ -217,55 +228,43 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
}
- /**
- * Immediately resize/reset leash from previous cropped boundary to default.
- * (i.e Screen rotation need to reset crop and position before applying new bounds)
- */
- public void resetImmediately(Rect newDisplayBounds) {
- updateDisplayBounds(newDisplayBounds);
- if (mDisplayAreaInfo != null && mLeash != null) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = newDisplayBounds;
- args.argi1 = 0 /* xOffset */;
- args.argi2 = 0 /* yOffset */;
- args.argi3 = TRANSITION_DIRECTION_EXIT;
- mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESET_IMMEDIATE, args));
- }
- }
-
- private void offsetWindows(Rect currentbounds, int xOffset, int yOffset, int direction,
- int durationMs) {
+ private void offsetWindows(Rect fromBounds, Rect toBounds, int direction, int durationMs) {
if (Looper.myLooper() != mUpdateHandler.getLooper()) {
throw new RuntimeException("Callers should call scheduleOffset() instead of this "
+ "directly");
}
- if (mDisplayAreaInfo == null || mLeash == null) {
- Log.w(TAG, "mToken is not set");
- return;
- }
+ mDisplayAreaMap.forEach(
+ (key, leash) -> animateWindows(leash, fromBounds, toBounds, direction,
+ durationMs));
+ }
- Rect toBounds = new Rect(mDefaultDisplayBounds.left,
- mDefaultDisplayBounds.top + yOffset,
- mDefaultDisplayBounds.right,
- mDefaultDisplayBounds.bottom + yOffset);
- animateWindows(currentbounds, toBounds, direction, durationMs);
+ private void resetWindowsOffset() {
+ mUpdateHandler.post(() -> {
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ mDisplayAreaMap.forEach(
+ (key, leash) -> {
+ final OneHandedAnimationController.OneHandedTransitionAnimator animator =
+ mAnimationController.getAnimatorMap().remove(leash);
+ if (animator != null && animator.isRunning()) {
+ animator.cancel();
+ }
+ tx.setPosition(leash, 0, 0)
+ .setWindowCrop(leash, -1/* reset */, -1/* reset */);
+ });
+ tx.apply();
+ });
}
- private void animateWindows(Rect fromBounds, Rect toBounds,
+ private void animateWindows(SurfaceControl leash, Rect fromBounds, Rect toBounds,
@OneHandedAnimationController.TransitionDirection int direction, int durationMs) {
if (Looper.myLooper() != mUpdateHandler.getLooper()) {
throw new RuntimeException("Callers should call scheduleOffset() instead of "
+ "this directly");
}
- // Could happen when exit one handed
- if (mDisplayAreaInfo == null || mLeash == null) {
- Log.w(TAG, "Abort animation, invalid leash");
- return;
- }
-
mUpdateHandler.post(() -> {
final OneHandedAnimationController.OneHandedTransitionAnimator animator =
- mAnimationController.getAnimator(mLeash, fromBounds, toBounds);
+ mAnimationController.getAnimator(leash, fromBounds, toBounds);
if (animator != null) {
animator.setTransitionDirection(direction)
.setOneHandedAnimationCallback(mOneHandedAnimationCallback)
@@ -275,7 +274,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
});
}
- private void finishOffset(Rect currentBounds, int offset,
+ private void finishOffset(int offset,
@OneHandedAnimationController.TransitionDirection int direction) {
if (Looper.myLooper() != mUpdateHandler.getLooper()) {
throw new RuntimeException(
@@ -284,18 +283,14 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
// Only finishOffset() can update mIsInOneHanded to ensure the state is handle in sequence,
// the flag *MUST* be updated before dispatch mTransitionCallbacks
mIsInOneHanded = (offset > 0 || direction == TRANSITION_DIRECTION_TRIGGER);
- mLastVisualDisplayBounds.set(currentBounds);
- if (direction == TRANSITION_DIRECTION_TRIGGER) {
- mLastVisualDisplayBounds.offsetTo(0, offset);
- for (int i = mTransitionCallbacks.size() - 1; i >= 0; i--) {
- final OneHandedTransitionCallback callback = mTransitionCallbacks.get(i);
- callback.onStartFinished(mLastVisualDisplayBounds);
- }
- } else {
- mLastVisualDisplayBounds.offsetTo(0, 0);
- for (int i = mTransitionCallbacks.size() - 1; i >= 0; i--) {
- final OneHandedTransitionCallback callback = mTransitionCallbacks.get(i);
- callback.onStopFinished(mLastVisualDisplayBounds);
+ mLastVisualDisplayBounds.offsetTo(0,
+ direction == TRANSITION_DIRECTION_TRIGGER ? offset : 0);
+ for (int i = mTransitionCallbacks.size() - 1; i >= 0; i--) {
+ final OneHandedTransitionCallback callback = mTransitionCallbacks.get(i);
+ if (direction == TRANSITION_DIRECTION_TRIGGER) {
+ callback.onStartFinished(getLastVisualDisplayBounds());
+ } else {
+ callback.onStopFinished(getLastVisualDisplayBounds());
}
}
}
@@ -332,6 +327,16 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
return mUpdateHandler;
}
+ private DisplayLayout getDisplayLayout(Context context) {
+ final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY);
+ if (display != null) {
+ display.getDisplayInfo(mDisplayInfo);
+ } else {
+ Log.w(TAG, "get DEFAULT_DISPLAY return null");
+ }
+ return new DisplayLayout(mDisplayInfo, context.getResources(), false, false);
+ }
+
/**
* Register transition callback
*/
@@ -349,29 +354,23 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
return args;
}
- private void updateDisplayBounds(Rect newDisplayBounds) {
- if (newDisplayBounds == null) {
- mDefaultDisplayBounds.set(0, 0, getDisplayBounds().x, getDisplayBounds().y);
- } else {
- mDefaultDisplayBounds.set(newDisplayBounds);
- }
- }
-
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
final String innerPrefix = " ";
pw.println(TAG + "states: ");
pw.print(innerPrefix + "mIsInOneHanded=");
pw.println(mIsInOneHanded);
- pw.print(innerPrefix + "mDisplayAreaInfo=");
- pw.println(mDisplayAreaInfo);
- pw.print(innerPrefix + "mLeash=");
- pw.println(mLeash);
+ pw.print(innerPrefix + "mDisplayAreaMap=");
+ pw.println(mDisplayAreaMap);
pw.print(innerPrefix + "mDefaultDisplayBounds=");
pw.println(mDefaultDisplayBounds);
pw.print(innerPrefix + "mLastVisualDisplayBounds=");
pw.println(mLastVisualDisplayBounds);
pw.print(innerPrefix + "getDisplayBounds()=");
pw.println(getDisplayBounds());
+ if (mDisplayLayout != null) {
+ pw.print(innerPrefix + "mDisplayLayout(w, h)=");
+ pw.println(mDisplayLayout.width() + ", " + mDisplayLayout.height());
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
index d60b43f7a0aa..4dacdf3158f8 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
@@ -27,11 +27,13 @@ import android.graphics.Rect;
import androidx.annotation.NonNull;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.model.SysUiState;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.wm.DisplayChangeController;
import com.android.systemui.wm.DisplayController;
import java.io.FileDescriptor;
@@ -50,15 +52,18 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
private boolean mIsOneHandedEnabled;
private boolean mTaskChangeToExit;
private float mOffSetFraction;
- private DisplayController mDisplayController;
+
+ private final DisplayController mDisplayController;
+ private final OneHandedGestureHandler mGestureHandler;
+ private final OneHandedTimeoutHandler mTimeoutHandler;
+ private final OneHandedTouchHandler mTouchHandler;
+ private final SysUiState mSysUiFlagContainer;
+
+ private Context mContext;
private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
- private OneHandedGestureHandler mGestureHandler;
private OneHandedGestureHandler.OneHandedGestureEventCallback mGestureEventCallback;
- private OneHandedTimeoutHandler mTimeoutHandler;
- private OneHandedTouchHandler mTouchHandler;
private OneHandedTouchHandler.OneHandedTouchEventCallback mTouchEventCallback;
private OneHandedTransitionCallback mTransitionCallback;
- private SysUiState mSysUiFlagContainer;
/**
* Handler for system task stack changes, exit when user lunch new task or bring task to front
@@ -84,6 +89,17 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
};
/**
+ * Handle rotation based on OnDisplayChangingListener callback
+ */
+ @VisibleForTesting
+ private final DisplayChangeController.OnDisplayChangingListener mRotationController =
+ (display, fromRotation, toRotation, wct) -> {
+ if (mDisplayAreaOrganizer != null) {
+ mDisplayAreaOrganizer.onRotateDisplay(mContext.getResources(), toRotation);
+ }
+ };
+
+ /**
* Constructor of OneHandedManager
*/
@Inject
@@ -93,9 +109,10 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
OneHandedTouchHandler touchHandler,
OneHandedGestureHandler gestureHandler,
SysUiState sysUiState) {
-
+ mContext = context;
mDisplayAreaOrganizer = displayAreaOrganizer;
mDisplayController = displayController;
+ mDisplayController.addDisplayChangingController(mRotationController);
mSysUiFlagContainer = sysUiState;
mOffSetFraction =
context.getResources().getFraction(R.fraction.config_one_handed_offset, 1, 1);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index d7cc11b7fd15..32f8c126373d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -171,7 +171,6 @@ public class PipTouchHandler {
private float mSavedSnapFraction = -1f;
private boolean mSendingHoverAccessibilityEvents;
private boolean mMovementWithinDismiss;
- private boolean mHideMenuAfterShown = false;
private PipAccessibilityInteractionConnection mConnection;
// Touch state
@@ -273,7 +272,9 @@ public class PipTouchHandler {
mMagnetizedPip.setAnimateStuckToTarget(
(target, velX, velY, flung, after) -> {
- mMotionHelper.animateIntoDismissTarget(target, velX, velY, flung, after);
+ if (mEnableDismissDragToEdge) {
+ mMotionHelper.animateIntoDismissTarget(target, velX, velY, flung, after);
+ }
return Unit.INSTANCE;
});
mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() {
@@ -281,7 +282,9 @@ public class PipTouchHandler {
public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
// Show the dismiss target, in case the initial touch event occurred within the
// magnetic field radius.
- showDismissTargetMaybe();
+ if (mEnableDismissDragToEdge) {
+ showDismissTargetMaybe();
+ }
}
@Override
@@ -726,7 +729,6 @@ public class PipTouchHandler {
// on and changing MotionEvents into HoverEvents.
// Let's not enable menu show/hide for a11y services.
if (!mAccessibilityManager.isTouchExplorationEnabled()) {
- mHideMenuAfterShown = true;
mTouchState.scheduleHoverExitTimeoutCallback();
}
if (!shouldDeliverToMenu && mSendingHoverAccessibilityEvents) {
@@ -813,9 +815,6 @@ public class PipTouchHandler {
mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
mMovementBounds, mExpandedMovementBounds, callback);
}
- if (mHideMenuAfterShown) {
- mMenuController.hideMenu();
- }
} else if (menuState == MENU_STATE_NONE && mMenuState == MENU_STATE_FULL) {
// Try and restore the PiP to the closest edge, using the saved snap fraction
// if possible
@@ -853,7 +852,6 @@ public class PipTouchHandler {
}
}
mMenuState = menuState;
- mHideMenuAfterShown = false;
updateMovementBounds();
// If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
// as well, or it can't handle a11y focus and pip menu can't perform any action.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index c454048d0649..daf8ca324c74 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -104,4 +104,13 @@ public class QSDetailClipper {
public void showBackground() {
mBackground.showSecondLayer();
}
+
+ /**
+ * Cancels the animator if it's running.
+ */
+ public void cancelAnimator() {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 3e2f9dec5807..e5ed88c10a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -208,6 +208,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
public void showImmediately() {
if (!isShown) {
setVisibility(VISIBLE);
+ mClipper.cancelAnimator();
mClipper.showBackground();
isShown = true;
setTileSpecs();
@@ -230,6 +231,10 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
mUiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED);
isShown = false;
mToolbar.dismissPopupMenus();
+ mClipper.cancelAnimator();
+ // Make sure we're not opening (because we're closing). Nobody can think we are
+ // customizing after the next two lines.
+ mOpening = false;
setCustomizing(false);
save();
if (animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index fba7a22351e2..2ef693467d27 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -21,7 +21,6 @@ import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_
import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
@@ -33,6 +32,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R;
import com.android.systemui.qs.PseudoGridView;
import com.android.systemui.qs.QSUserSwitcherEvent;
@@ -100,7 +100,8 @@ public class UserDetailView extends PseudoGridView {
if (item.picture == null) {
v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
} else {
- Drawable drawable = new BitmapDrawable(v.getResources(), item.picture);
+ int avatarSize = (int) v.getResources().getDimension(R.dimen.qs_framed_avatar_size);
+ Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize);
drawable.setColorFilter(
item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
v.bind(name, drawable, item.info.id);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 423f85f2ddd0..bd65ef06f3a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -282,7 +282,7 @@ public final class NotificationEntry extends ListEntry {
+ " doesn't match existing key " + mKey);
}
- mRanking = ranking;
+ mRanking = ranking.withAudiblyAlertedInfo(mRanking);
}
/*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 673aa3903156..85a3bc91dc7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -142,7 +142,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
.expandableNotificationRow(row)
.notificationEntry(entry)
.onDismissRunnable(onDismissRunnable)
- .rowContentBindStage(mRowContentBindStage)
.onExpandClickListener(mPresenter)
.build();
ExpandableNotificationRowController rowController =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 582e3e5b6c34..a7d83b3b2774 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -37,6 +37,8 @@ import android.widget.RemoteViews;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.ImageMessageConsumer;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.media.MediaDataManagerKt;
+import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.SmartReplyController;
@@ -71,6 +73,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
public static final String TAG = "NotifContentInflater";
private boolean mInflateSynchronously = false;
+ private final boolean mIsMediaInQS;
private final NotificationRemoteInputManager mRemoteInputManager;
private final NotifRemoteViewCache mRemoteViewCache;
private final Lazy<SmartReplyConstants> mSmartReplyConstants;
@@ -85,12 +88,14 @@ public class NotificationContentInflater implements NotificationRowContentBinder
Lazy<SmartReplyConstants> smartReplyConstants,
Lazy<SmartReplyController> smartReplyController,
ConversationNotificationProcessor conversationProcessor,
+ MediaFeatureFlag mediaFeatureFlag,
@Background Executor bgExecutor) {
mRemoteViewCache = remoteViewCache;
mRemoteInputManager = remoteInputManager;
mSmartReplyConstants = smartReplyConstants;
mSmartReplyController = smartReplyController;
mConversationProcessor = conversationProcessor;
+ mIsMediaInQS = mediaFeatureFlag.getEnabled();
mBgExecutor = bgExecutor;
}
@@ -135,7 +140,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
bindParams.usesIncreasedHeight,
bindParams.usesIncreasedHeadsUpHeight,
callback,
- mRemoteInputManager.getRemoteViewsOnClickHandler());
+ mRemoteInputManager.getRemoteViewsOnClickHandler(),
+ mIsMediaInQS);
if (mInflateSynchronously) {
task.onPostExecute(task.doInBackground());
} else {
@@ -711,6 +717,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
private RemoteViews.OnClickHandler mRemoteViewClickHandler;
private CancellationSignal mCancellationSignal;
private final ConversationNotificationProcessor mConversationProcessor;
+ private final boolean mIsMediaInQS;
private AsyncInflationTask(
Executor bgExecutor,
@@ -726,7 +733,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
boolean usesIncreasedHeight,
boolean usesIncreasedHeadsUpHeight,
InflationCallback callback,
- RemoteViews.OnClickHandler remoteViewClickHandler) {
+ RemoteViews.OnClickHandler remoteViewClickHandler,
+ boolean isMediaFlagEnabled) {
mEntry = entry;
mRow = row;
mSmartReplyConstants = smartReplyConstants;
@@ -742,6 +750,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
mRemoteViewClickHandler = remoteViewClickHandler;
mCallback = callback;
mConversationProcessor = conversationProcessor;
+ mIsMediaInQS = isMediaFlagEnabled;
entry.setInflationTask(this);
}
@@ -765,7 +774,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
packageContext = new RtlEnabledContext(packageContext);
}
Notification notification = sbn.getNotification();
- if (notification.isMediaNotification()) {
+ if (notification.isMediaNotification() && !(mIsMediaInQS
+ && MediaDataManagerKt.isMediaNotification(sbn))) {
MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
packageContext);
processor.processNotification(notification, recoveredBuilder);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
index 9846f2dcd170..321656df504a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
@@ -25,7 +25,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
-import com.android.systemui.statusbar.notification.row.RowContentBindStage;
import com.android.systemui.statusbar.phone.StatusBar;
import dagger.Binds;
@@ -57,8 +56,6 @@ public interface ExpandableNotificationRowComponent {
@BindsInstance
Builder onDismissRunnable(@DismissRunnable Runnable runnable);
@BindsInstance
- Builder rowContentBindStage(RowContentBindStage rowContentBindStage);
- @BindsInstance
Builder onExpandClickListener(ExpandableNotificationRow.OnExpandClickListener presenter);
ExpandableNotificationRowComponent build();
}
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 f5999f5c8294..f5ea1c880a41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -211,8 +211,4 @@ public class DozeParameters implements TunerService.Tunable,
public void onTuningChanged(String key, String newValue) {
mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
}
-
- public AlwaysOnDisplayPolicy getPolicy() {
- return mAlwaysOnPolicy;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index 304fe0090e77..539158c40d45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -614,8 +614,10 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
// Bubble controller will give us a valid display id if it should get the back event
BubbleController bubbleController = Dependency.get(BubbleController.class);
int bubbleDisplayId = bubbleController.getExpandedDisplayId(mContext);
- if (code == KeyEvent.KEYCODE_BACK && bubbleDisplayId != INVALID_DISPLAY) {
+ if (bubbleDisplayId != INVALID_DISPLAY) {
ev.setDisplayId(bubbleDisplayId);
+ } else {
+ ev.setDisplayId(mContext.getDisplay().getDisplayId());
}
InputManager.getInstance().injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 732f25f90eb5..e942d85790c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -371,12 +371,26 @@ public abstract class PanelViewController {
float vectorVel = (float) Math.hypot(
mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
- boolean expand = flingExpands(vel, vectorVel, x, y)
- || event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel;
+ final boolean onKeyguard =
+ mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+
+ final boolean expand;
+ if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
+ // If we get a cancel, put the shade back to the state it was in when the gesture
+ // started
+ if (onKeyguard) {
+ expand = true;
+ } else {
+ expand = !mPanelClosedOnDown;
+ }
+ } else {
+ expand = flingExpands(vel, vectorVel, x, y);
+ }
+
mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
mStatusBar.isFalsingThresholdNeeded(), mStatusBar.isWakeUpComingFromTouch());
// Log collapse gesture if on lock screen.
- if (!expand && mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+ if (!expand && onKeyguard) {
float displayDensity = mStatusBar.getDisplayDensity();
int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity);
int velocityDp = (int) Math.abs(vel / displayDensity);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 60fc17d9474a..686b87127239 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -348,10 +348,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
}
if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
- // In case the user isn't unlocked, make sure to delay a bit because the system is hosed
- // with too many things at this case, in order to not skip the initial frames.
- mScrimInFront.postOnAnimationDelayed(this::scheduleUpdate, 16);
mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
+ scheduleUpdate();
} else if ((!mDozeParameters.getAlwaysOn() && oldState == ScrimState.AOD)
|| (mState == ScrimState.AOD && !mDozeParameters.getDisplayNeedsBlanking())) {
// Scheduling a frame isn't enough when:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 812ce1c62677..6dd96f92b344 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -82,6 +82,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
private boolean mClockVisibleByUser = true;
private boolean mAttached;
+ private boolean mScreenReceiverRegistered;
private Calendar mCalendar;
private String mClockFormatString;
private SimpleDateFormat mClockFormat;
@@ -213,6 +214,14 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
+ if (mScreenReceiverRegistered) {
+ mScreenReceiverRegistered = false;
+ mBroadcastDispatcher.unregisterReceiver(mScreenReceiver);
+ if (mSecondsHandler != null) {
+ mSecondsHandler.removeCallbacks(mSecondTick);
+ mSecondsHandler = null;
+ }
+ }
if (mAttached) {
mBroadcastDispatcher.unregisterReceiver(mIntentReceiver);
mAttached = false;
@@ -363,12 +372,14 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
mSecondsHandler.postAtTime(mSecondTick,
SystemClock.uptimeMillis() / 1000 * 1000 + 1000);
}
+ mScreenReceiverRegistered = true;
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
mBroadcastDispatcher.registerReceiver(mScreenReceiver, filter);
}
} else {
if (mSecondsHandler != null) {
+ mScreenReceiverRegistered = false;
mBroadcastDispatcher.unregisterReceiver(mScreenReceiver);
mSecondsHandler.removeCallbacks(mSecondTick);
mSecondsHandler = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 07de388598b7..c43ad36d4462 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -106,9 +106,9 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
public void updateNotification(@NonNull String key, boolean alert) {
super.updateNotification(key, alert);
- AlertEntry alertEntry = getHeadsUpEntry(key);
- if (alert && alertEntry != null) {
- setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(alertEntry.mEntry));
+ HeadsUpEntry headsUpEntry = getHeadsUpEntry(key);
+ if (alert && headsUpEntry != null) {
+ setEntryPinned(headsUpEntry, shouldHeadsUpBecomePinned(headsUpEntry.mEntry));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 512d0f3910f8..5ec5ec662164 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -24,7 +24,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.database.DataSetObserver;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
@@ -36,6 +35,7 @@ import android.view.ViewStub;
import android.widget.FrameLayout;
import com.android.settingslib.animation.AppearAnimationUtils;
+import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -288,7 +288,8 @@ public class KeyguardUserSwitcher {
if (item.picture == null) {
v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
} else {
- Drawable drawable = new BitmapDrawable(v.getResources(), item.picture);
+ int avatarSize = (int) v.getResources().getDimension(R.dimen.kg_framed_avatar_size);
+ Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize);
drawable.setColorFilter(
item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
v.bind(name, drawable, item.info.id);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 3bd33ccca911..251693e162d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -16,11 +16,11 @@
package com.android.systemui.statusbar.policy;
+import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
+
import static com.android.settingslib.Utils.updateLocationEnabled;
import android.app.ActivityManager;
-import android.app.AppOpsManager;
-import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -36,8 +36,9 @@ import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import com.android.systemui.BootCompleteCache;
+import com.android.systemui.appops.AppOpItem;
+import com.android.systemui.appops.AppOpsController;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.Utils;
@@ -51,41 +52,32 @@ import javax.inject.Singleton;
* A controller to manage changes of location related states and update the views accordingly.
*/
@Singleton
-public class LocationControllerImpl extends BroadcastReceiver implements LocationController {
-
- private static final int[] mHighPowerRequestAppOpArray
- = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
+public class LocationControllerImpl extends BroadcastReceiver implements LocationController,
+ AppOpsController.Callback {
- private Context mContext;
+ private final Context mContext;
+ private final AppOpsController mAppOpsController;
+ private final BootCompleteCache mBootCompleteCache;
+ private final H mHandler;
- private AppOpsManager mAppOpsManager;
- private StatusBarManager mStatusBarManager;
- private BroadcastDispatcher mBroadcastDispatcher;
- private BootCompleteCache mBootCompleteCache;
private boolean mAreActiveLocationRequests;
- private final H mHandler;
-
@Inject
- public LocationControllerImpl(Context context, @Main Looper mainLooper,
- @Background Looper bgLooper, BroadcastDispatcher broadcastDispatcher,
+ public LocationControllerImpl(Context context, AppOpsController appOpsController,
+ @Main Looper mainLooper, BroadcastDispatcher broadcastDispatcher,
BootCompleteCache bootCompleteCache) {
mContext = context;
- mBroadcastDispatcher = broadcastDispatcher;
+ mAppOpsController = appOpsController;
mBootCompleteCache = bootCompleteCache;
mHandler = new H(mainLooper);
// Register to listen for changes in location settings.
IntentFilter filter = new IntentFilter();
- filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
filter.addAction(LocationManager.MODE_CHANGED_ACTION);
- mBroadcastDispatcher.registerReceiverWithHandler(this, filter,
- new Handler(bgLooper), UserHandle.ALL);
+ broadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler, UserHandle.ALL);
- mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- mStatusBarManager
- = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
+ mAppOpsController.addCallback(new int[]{OP_MONITOR_HIGH_POWER_LOCATION}, this);
// Examine the current location state and initialize the status view.
updateActiveLocationRequests();
@@ -160,27 +152,12 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
*/
@VisibleForTesting
protected boolean areActiveHighPowerLocationRequests() {
- List<AppOpsManager.PackageOps> packages
- = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
- // AppOpsManager can return null when there is no requested data.
- if (packages != null) {
- final int numPackages = packages.size();
- for (int packageInd = 0; packageInd < numPackages; packageInd++) {
- AppOpsManager.PackageOps packageOp = packages.get(packageInd);
- List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
- if (opEntries != null) {
- final int numOps = opEntries.size();
- for (int opInd = 0; opInd < numOps; opInd++) {
- AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
- // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because
- // of the mHighPowerRequestAppOpArray filter, but checking defensively.
- if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
- if (opEntry.isRunning()) {
- return true;
- }
- }
- }
- }
+ List<AppOpItem> appOpsItems = mAppOpsController.getActiveAppOps();
+
+ final int numItems = appOpsItems.size();
+ for (int i = 0; i < numItems; i++) {
+ if (appOpsItems.get(i).getCode() == OP_MONITOR_HIGH_POWER_LOCATION) {
+ return true;
}
}
@@ -198,14 +175,16 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
@Override
public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
- updateActiveLocationRequests();
- } else if (LocationManager.MODE_CHANGED_ACTION.equals(action)) {
- mHandler.sendEmptyMessage(H.MSG_LOCATION_SETTINGS_CHANGED);
+ if (LocationManager.MODE_CHANGED_ACTION.equals(intent.getAction())) {
+ mHandler.locationSettingsChanged();
}
}
+ @Override
+ public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
+ updateActiveLocationRequests();
+ }
+
private final class H extends Handler {
private static final int MSG_LOCATION_SETTINGS_CHANGED = 1;
private static final int MSG_LOCATION_ACTIVE_CHANGED = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/util/Assert.java b/packages/SystemUI/src/com/android/systemui/util/Assert.java
index 3f05657ed09e..e08936cbf75e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Assert.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Assert.java
@@ -25,16 +25,21 @@ import androidx.annotation.VisibleForTesting;
*/
public class Assert {
private static final Looper sMainLooper = Looper.getMainLooper();
- private static Looper sTestLooper = null;
+ private static Thread sTestThread = null;
@VisibleForTesting
public static void setTestableLooper(Looper testLooper) {
- sTestLooper = testLooper;
+ setTestThread(testLooper == null ? null : testLooper.getThread());
+ }
+
+ @VisibleForTesting
+ public static void setTestThread(Thread thread) {
+ sTestThread = thread;
}
public static void isMainThread() {
if (!sMainLooper.isCurrentThread()
- && (sTestLooper == null || !sTestLooper.isCurrentThread())) {
+ && (sTestThread == null || sTestThread != Thread.currentThread())) {
throw new IllegalStateException("should be called from the main thread."
+ " sMainLooper.threadName=" + sMainLooper.getThread().getName()
+ " Thread.currentThread()=" + Thread.currentThread().getName());
@@ -43,7 +48,7 @@ public class Assert {
public static void isNotMainThread() {
if (sMainLooper.isCurrentThread()
- && (sTestLooper == null || sTestLooper.isCurrentThread())) {
+ && (sTestThread == null || sTestThread == Thread.currentThread())) {
throw new IllegalStateException("should not be called from the main thread.");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
index 7729965b56c4..bf22a9897d16 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java
@@ -32,6 +32,7 @@ import java.util.concurrent.Executors;
import javax.inject.Singleton;
+import dagger.Binds;
import dagger.Module;
import dagger.Provides;
@@ -199,4 +200,10 @@ public abstract class ConcurrencyModule {
public static Executor provideUiBackgroundExecutor() {
return Executors.newSingleThreadExecutor();
}
+
+ /**
+ * Binds {@link ThreadFactoryImpl} to {@link ThreadFactory}.
+ */
+ @Binds
+ public abstract ThreadFactory bindExecutorFactory(ThreadFactoryImpl impl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java
new file mode 100644
index 000000000000..0352fb51bc21
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java
@@ -0,0 +1,44 @@
+/*
+ * 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.systemui.util.concurrency;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Factory for building Executors running on a unique named thread.
+ *
+ * Use this when our generally available @Main, @Background, @UiBackground, @LongRunning, or
+ * similar global qualifiers don't quite cut it. Note that the methods here create entirely new
+ * threads; there are no singletons here. Use responsibly.
+ */
+public interface ThreadFactory {
+ /**
+ * Return an {@link java.util.concurrent.Executor} running on a named thread.
+ *
+ * The thread is implicitly started and may be left running indefinitely, depending on the
+ * implementation. Assume this is the case and use responsibly.
+ **/
+ Executor buildExecutorOnNewThread(String threadName);
+
+ /**
+ * Return an {@link DelayableExecutor} running on a named thread.
+ *
+ * The thread is implicitly started and may be left running indefinitely, depending on the
+ * implementation. Assume this is the case and use responsibly.
+ **/
+ DelayableExecutor buildDelayableExecutorOnNewThread(String threadName);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java
new file mode 100644
index 000000000000..ca8d83607634
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java
@@ -0,0 +1,38 @@
+/*
+ * 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.systemui.util.concurrency;
+
+import android.os.HandlerThread;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+class ThreadFactoryImpl implements ThreadFactory {
+ @Inject
+ ThreadFactoryImpl() {}
+
+ public Executor buildExecutorOnNewThread(String threadName) {
+ return buildDelayableExecutorOnNewThread(threadName);
+ }
+
+ public DelayableExecutor buildDelayableExecutorOnNewThread(String threadName) {
+ HandlerThread handlerThread = new HandlerThread(threadName);
+ handlerThread.start();
+ return new ExecutorImpl(handlerThread.getLooper());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java b/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java
index 450336a6b73b..ed4df175b1a6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/AsyncSensorManager.java
@@ -25,18 +25,18 @@ import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.TriggerEventListener;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.MemoryFile;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.util.concurrency.ThreadFactory;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -56,25 +56,14 @@ public class AsyncSensorManager extends SensorManager
private final SensorManager mInner;
private final List<Sensor> mSensorCache;
- private final Handler mHandler;
+ private final Executor mExecutor;
private final List<SensorManagerPlugin> mPlugins;
@Inject
- public AsyncSensorManager(SensorManager sensorManager, PluginManager pluginManager) {
- this(sensorManager, pluginManager, null);
- }
-
- @VisibleForTesting
- public AsyncSensorManager(
- SensorManager sensorManager, PluginManager pluginManager, Handler handler) {
+ public AsyncSensorManager(SensorManager sensorManager, ThreadFactory threadFactory,
+ PluginManager pluginManager) {
mInner = sensorManager;
- if (handler == null) {
- HandlerThread handlerThread = new HandlerThread("async_sensor");
- handlerThread.start();
- mHandler = new Handler(handlerThread.getLooper());
- } else {
- mHandler = handler;
- }
+ mExecutor = threadFactory.buildExecutorOnNewThread("async_sensor");
mSensorCache = mInner.getSensorList(Sensor.TYPE_ALL);
mPlugins = new ArrayList<>();
if (pluginManager != null) {
@@ -97,7 +86,7 @@ public class AsyncSensorManager extends SensorManager
protected boolean registerListenerImpl(SensorEventListener listener,
Sensor sensor, int delayUs, Handler handler, int maxReportLatencyUs,
int reservedFlags) {
- mHandler.post(() -> {
+ mExecutor.execute(() -> {
if (!mInner.registerListener(listener, sensor, delayUs, maxReportLatencyUs, handler)) {
Log.e(TAG, "Registering " + listener + " for " + sensor + " failed.");
}
@@ -129,12 +118,12 @@ public class AsyncSensorManager extends SensorManager
@Override
protected void registerDynamicSensorCallbackImpl(DynamicSensorCallback callback,
Handler handler) {
- mHandler.post(() -> mInner.registerDynamicSensorCallback(callback, handler));
+ mExecutor.execute(() -> mInner.registerDynamicSensorCallback(callback, handler));
}
@Override
protected void unregisterDynamicSensorCallbackImpl(DynamicSensorCallback callback) {
- mHandler.post(() -> mInner.unregisterDynamicSensorCallback(callback));
+ mExecutor.execute(() -> mInner.unregisterDynamicSensorCallback(callback));
}
@Override
@@ -145,7 +134,7 @@ public class AsyncSensorManager extends SensorManager
if (sensor == null) {
throw new IllegalArgumentException("sensor cannot be null");
}
- mHandler.post(() -> {
+ mExecutor.execute(() -> {
if (!mInner.requestTriggerSensor(listener, sensor)) {
Log.e(TAG, "Requesting " + listener + " for " + sensor + " failed.");
}
@@ -158,7 +147,7 @@ public class AsyncSensorManager extends SensorManager
boolean disable) {
Preconditions.checkArgument(disable);
- mHandler.post(() -> {
+ mExecutor.execute(() -> {
if (!mInner.cancelTriggerSensor(listener, sensor)) {
Log.e(TAG, "Canceling " + listener + " for " + sensor + " failed.");
}
@@ -178,7 +167,7 @@ public class AsyncSensorManager extends SensorManager
Log.w(TAG, "No plugins registered");
return false;
}
- mHandler.post(() -> {
+ mExecutor.execute(() -> {
for (int i = 0; i < mPlugins.size(); i++) {
mPlugins.get(i).registerListener(sensor, listener);
}
@@ -194,7 +183,7 @@ public class AsyncSensorManager extends SensorManager
*/
public void unregisterPluginListener(SensorManagerPlugin.Sensor sensor,
SensorManagerPlugin.SensorEventListener listener) {
- mHandler.post(() -> {
+ mExecutor.execute(() -> {
for (int i = 0; i < mPlugins.size(); i++) {
mPlugins.get(i).unregisterListener(sensor, listener);
}
@@ -214,14 +203,14 @@ public class AsyncSensorManager extends SensorManager
@Override
protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
- mHandler.post(() -> mInner.setOperationParameter(parameter));
+ mExecutor.execute(() -> mInner.setOperationParameter(parameter));
return true;
}
@Override
protected void unregisterListenerImpl(SensorEventListener listener,
Sensor sensor) {
- mHandler.post(() -> {
+ mExecutor.execute(() -> {
if (sensor == null) {
mInner.unregisterListener(listener);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 8ba5b9951c54..38b20c030116 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -226,6 +226,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
&& mAnimation != null) {
startAnimation(mImeShowing, true /* forceRestart */);
+ } else if (!mImeShowing) {
+ removeImeSurface();
}
});
}
@@ -251,6 +253,11 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
mHandler.post(() -> startAnimation(false /* show */, false /* forceRestart */));
}
+ @Override
+ public void topFocusedWindowChanged(String packageName) {
+ // no-op
+ }
+
/**
* Sends the local visibility state back to window manager. Needed for legacy adjustForIme.
*/
@@ -370,16 +377,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
dispatchEndPositioning(mDisplayId, mCancelled, t);
if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
t.hide(mImeSourceControl.getLeash());
- final IInputMethodManager imms = getImms();
- if (imms != null) {
- try {
- // Remove the IME surface to make the insets invisible for
- // non-client controlled insets.
- imms.removeImeSurface();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to remove IME surface.", e);
- }
- }
+ removeImeSurface();
}
t.apply();
mTransactionPool.release(t);
@@ -402,6 +400,19 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
+ void removeImeSurface() {
+ final IInputMethodManager imms = getImms();
+ if (imms != null) {
+ try {
+ // Remove the IME surface to make the insets invisible for
+ // non-client controlled insets.
+ imms.removeImeSurface();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to remove IME surface.", e);
+ }
+ }
+ }
+
/**
* Allows other things to synchronize with the ime position
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
index f29f04244901..3d679deaa426 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
@@ -26,11 +26,14 @@ import android.util.ArraySet;
import android.util.Log;
import android.view.Display;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.Set;
public class SysuiTestableContext extends TestableContext {
- private Set<BroadcastReceiver> mRegisteredReceivers = new ArraySet<>();
+ @GuardedBy("mRegisteredReceivers")
+ private final Set<BroadcastReceiver> mRegisteredReceivers = new ArraySet<>();
public SysuiTestableContext(Context base) {
super(base);
@@ -54,7 +57,11 @@ public class SysuiTestableContext extends TestableContext {
}
public void cleanUpReceivers(String testName) {
- Set<BroadcastReceiver> copy = new ArraySet<>(mRegisteredReceivers);
+ Set<BroadcastReceiver> copy;
+ synchronized (mRegisteredReceivers) {
+ copy = new ArraySet<>(mRegisteredReceivers);
+ mRegisteredReceivers.clear();
+ }
for (BroadcastReceiver r : copy) {
try {
unregisterReceiver(r);
@@ -68,7 +75,9 @@ public class SysuiTestableContext extends TestableContext {
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
if (receiver != null) {
- mRegisteredReceivers.add(receiver);
+ synchronized (mRegisteredReceivers) {
+ mRegisteredReceivers.add(receiver);
+ }
}
return super.registerReceiver(receiver, filter);
}
@@ -77,7 +86,9 @@ public class SysuiTestableContext extends TestableContext {
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
if (receiver != null) {
- mRegisteredReceivers.add(receiver);
+ synchronized (mRegisteredReceivers) {
+ mRegisteredReceivers.add(receiver);
+ }
}
return super.registerReceiver(receiver, filter, broadcastPermission, scheduler);
}
@@ -86,7 +97,9 @@ public class SysuiTestableContext extends TestableContext {
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
if (receiver != null) {
- mRegisteredReceivers.add(receiver);
+ synchronized (mRegisteredReceivers) {
+ mRegisteredReceivers.add(receiver);
+ }
}
return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission, scheduler);
}
@@ -94,7 +107,9 @@ public class SysuiTestableContext extends TestableContext {
@Override
public void unregisterReceiver(BroadcastReceiver receiver) {
if (receiver != null) {
- mRegisteredReceivers.remove(receiver);
+ synchronized (mRegisteredReceivers) {
+ mRegisteredReceivers.remove(receiver);
+ }
}
super.unregisterReceiver(receiver);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
index 2bcc22c4b99e..f7f3a377f31d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
@@ -35,10 +35,10 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.tests.R;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java
index 8bc2e2bc77b6..43d2ad1dfe0a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java
@@ -20,7 +20,7 @@ import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
-import com.android.systemui.tests.R;
+import com.android.systemui.R;
/**
* Referenced by NotificationTestHelper#makeBubbleMetadata
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index 00d333fb593b..c591c1bd42bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -16,13 +16,13 @@
package com.android.systemui.doze;
-import android.hardware.display.AmbientDisplayConfiguration;
-
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
+import android.hardware.display.AmbientDisplayConfiguration;
+
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.sensors.FakeSensorManager;
@@ -37,7 +37,6 @@ public class DozeConfigurationUtil {
when(params.getPulseOnSigMotion()).thenReturn(false);
when(params.getPickupVibrationThreshold()).thenReturn(0);
when(params.getProxCheckBeforePulse()).thenReturn(true);
- when(params.getPolicy()).thenReturn(mock(AlwaysOnDisplayPolicy.class));
when(params.doubleTapReportsTouchCoordinates()).thenReturn(false);
when(params.getDisplayNeedsBlanking()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index dc027997578f..5c2b153bf452 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -57,7 +57,8 @@ public class DozeDockHandlerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mConfig = DozeConfigurationUtil.createMockConfig();
mDockManagerFake = spy(new DockManagerFake());
- mDockHandler = new DozeDockHandler(mConfig, mMachine, mDockManagerFake);
+ mDockHandler = new DozeDockHandler(mConfig, mDockManagerFake);
+ mDockHandler.setDozeMachine(mMachine);
when(mMachine.getState()).thenReturn(State.DOZE_AOD);
doReturn(true).when(mConfig).alwaysOnEnabled(anyInt());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 1f07f46bf764..8078b6c8bda4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -88,8 +88,7 @@ public class DozeMachineTest extends SysuiTestCase {
mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake,
mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog, mDockManager,
- mHost);
- mMachine.setParts(new DozeMachine.Part[]{mPartMock});
+ mHost, new DozeMachine.Part[]{mPartMock});
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 3ef60274cd76..3e60e016a0a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -40,14 +40,17 @@ import android.content.Intent;
import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
import android.view.Display;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.concurrency.FakeThreadFactory;
+import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.FakeSensorManager;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -55,22 +58,24 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(AndroidJUnit4.class)
@SmallTest
+@RunWith(AndroidTestingRunner.class)
public class DozeScreenBrightnessTest extends SysuiTestCase {
- static final int DEFAULT_BRIGHTNESS = 10;
- static final int[] SENSOR_TO_BRIGHTNESS = new int[]{-1, 1, 2, 3, 4};
- static final int[] SENSOR_TO_OPACITY = new int[]{-1, 10, 0, 0, 0};
+ private static final int DEFAULT_BRIGHTNESS = 10;
+ private static final int[] SENSOR_TO_BRIGHTNESS = new int[]{-1, 1, 2, 3, 4};
+ private static final int[] SENSOR_TO_OPACITY = new int[]{-1, 10, 0, 0, 0};
- DozeServiceFake mServiceFake;
- FakeSensorManager.FakeGenericSensor mSensor;
- FakeSensorManager mSensorManager;
+ private DozeServiceFake mServiceFake;
+ private FakeSensorManager.FakeGenericSensor mSensor;
+ private AsyncSensorManager mSensorManager;
+ private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
@Mock
DozeHost mDozeHost;
- @Mock
- BroadcastDispatcher mBroadcastDispatcher;
- DozeScreenBrightness mScreen;
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+ private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor);
+
+ private DozeScreenBrightness mScreen;
@Before
public void setUp() throws Exception {
@@ -83,12 +88,17 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
return null;
}).when(mDozeHost).prepareForGentleSleep(any());
mServiceFake = new DozeServiceFake();
- mSensorManager = new FakeSensorManager(mContext);
- mSensor = mSensorManager.getFakeLightSensor();
+ FakeSensorManager fakeSensorManager = new FakeSensorManager(mContext);
+ mSensorManager = new AsyncSensorManager(fakeSensorManager, mFakeThreadFactory, null);
+
+ mAlwaysOnDisplayPolicy = new AlwaysOnDisplayPolicy(mContext);
+ mAlwaysOnDisplayPolicy.defaultDozeBrightness = DEFAULT_BRIGHTNESS;
+ mAlwaysOnDisplayPolicy.screenBrightnessArray = SENSOR_TO_BRIGHTNESS;
+ mAlwaysOnDisplayPolicy.dimmingScrimArray = SENSOR_TO_OPACITY;
+ mSensor = fakeSensorManager.getFakeLightSensor();
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
- mSensor.getSensor(), mBroadcastDispatcher, mDozeHost, null /* handler */,
- DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY,
- true /* debuggable */);
+ mSensor.getSensor(), mDozeHost, null /* handler */,
+ mAlwaysOnDisplayPolicy);
mScreen.onScreenState(Display.STATE_ON);
}
@@ -106,6 +116,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(3);
@@ -116,6 +127,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
public void testAod_usesDebugValue() throws Exception {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+ mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
Intent intent = new Intent(DozeScreenBrightness.ACTION_AOD_BRIGHTNESS);
intent.putExtra(DozeScreenBrightness.BRIGHTNESS_BUCKET, 1);
@@ -141,6 +154,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(1);
@@ -153,9 +167,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
@Test
public void testPulsing_withoutLightSensor_setsAoDDimmingScrimTransparent() throws Exception {
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
- null /* sensor */, mBroadcastDispatcher, mDozeHost, null /* handler */,
- DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY,
- true /* debuggable */);
+ null /* sensor */, mDozeHost, null /* handler */,
+ mAlwaysOnDisplayPolicy);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE);
reset(mDozeHost);
@@ -174,6 +187,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(DOZE_PULSING, DOZE_PULSE_DONE);
mScreen.transitionTo(DOZE_PULSE_DONE, DOZE);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(1);
@@ -183,9 +197,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
@Test
public void testNullSensor() throws Exception {
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
- null /* sensor */, mBroadcastDispatcher, mDozeHost, null /* handler */,
- DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY,
- true /* debuggable */);
+ null /* sensor */, mDozeHost, null /* handler */,
+ mAlwaysOnDisplayPolicy);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
@@ -198,6 +211,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.transitionTo(DOZE_AOD, FINISH);
+ waitForSensorManager();
mSensor.sendSensorEvent(1);
@@ -205,10 +219,11 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
}
@Test
- public void testNonPositiveBrightness_keepsPreviousBrightnessAndScrim() throws Exception {
+ public void testNonPositiveBrightness_keepsPreviousBrightnessAndScrim() {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(1);
mSensor.sendSensorEvent(0);
@@ -222,6 +237,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(2);
@@ -233,6 +249,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
reset(mDozeHost);
mScreen.transitionTo(DOZE_AOD_PAUSED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(2);
verify(mDozeHost).setAodDimmingScrim(eq(0f));
}
@@ -242,6 +259,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
mScreen.onScreenState(Display.STATE_DOZE);
+ waitForSensorManager();
mSensor.sendSensorEvent(2);
mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSING);
@@ -251,4 +269,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mScreen.transitionTo(DOZE_AOD_PAUSED, DOZE_AOD);
verify(mDozeHost).setAodDimmingScrim(eq(0f));
}
+
+ private void waitForSensorManager() {
+ mFakeExecutor.runAllReady();
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index ebd2c3afe646..7ebead8a33fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -152,7 +152,7 @@ public class DozeSensorsTest extends SysuiTestCase {
private class TestableDozeSensors extends DozeSensors {
TestableDozeSensors() {
- super(getContext(), mAlarmManager, mSensorManager, mDozeParameters,
+ super(getContext(), mSensorManager, mDozeParameters,
mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog,
mProximitySensor);
for (TriggerSensor sensor : mSensors) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 655f933d28fe..d3af835873e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -30,9 +30,7 @@ import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.hardware.Sensor;
import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.view.Display;
@@ -43,6 +41,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.concurrency.FakeThreadFactory;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.FakeProximitySensor;
import com.android.systemui.util.sensors.FakeSensorManager;
@@ -92,15 +91,16 @@ public class DozeTriggersTest extends SysuiTestCase {
mTapSensor = mSensors.getFakeTapSensor().getSensor();
WakeLock wakeLock = new WakeLockFake();
AsyncSensorManager asyncSensorManager =
- new AsyncSensorManager(mSensors, null, new Handler());
+ new AsyncSensorManager(mSensors, new FakeThreadFactory(mExecutor), null);
FakeThresholdSensor thresholdSensor = new FakeThresholdSensor();
thresholdSensor.setLoaded(true);
mProximitySensor = new FakeProximitySensor(thresholdSensor, null, mExecutor);
- mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, config, parameters,
- asyncSensorManager, wakeLock, true, mDockManager, mProximitySensor,
+ mTriggers = new DozeTriggers(mContext, mHost, mAlarmManager, config, parameters,
+ asyncSensorManager, wakeLock, mDockManager, mProximitySensor,
mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher);
+ mTriggers.setDozeMachine(mMachine);
waitForSensorManager();
}
@@ -186,6 +186,6 @@ public class DozeTriggersTest extends SysuiTestCase {
}
private void waitForSensorManager() {
- TestableLooper.get(this).processAllMessages();
+ mExecutor.runAllReady();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
index c5bddc1f096f..069699c271f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
@@ -81,8 +81,9 @@ public class DozeUiTest extends SysuiTestCase {
mWakeLock = new WakeLockFake();
mHandler = mHandlerThread.getThreadHandler();
- mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler,
+ mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler,
mDozeParameters, mKeyguardUpdateMonitor, mDozeLog);
+ mDozeUi.setDozeMachine(mMachine);
}
@After
@@ -136,8 +137,9 @@ public class DozeUiTest extends SysuiTestCase {
reset(mDozeParameters);
reset(mHost);
when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
- mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler,
+ mDozeUi = new DozeUi(mContext, mAlarmManager, mWakeLock, mHost, mHandler,
mDozeParameters, mKeyguardUpdateMonitor, mDozeLog);
+ mDozeUi.setDozeMachine(mMachine);
// Never animate if display doesn't support it.
mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index dbc5596d9f4e..492b33e3c4a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import android.graphics.Color;
@@ -47,6 +48,7 @@ import java.util.Map;
public class MediaDataCombineLatestTest extends SysuiTestCase {
private static final String KEY = "TEST_KEY";
+ private static final String OLD_KEY = "TEST_KEY_OLD";
private static final String APP = "APP";
private static final String PACKAGE = "PKG";
private static final int BG_COLOR = Color.RED;
@@ -97,7 +99,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void eventNotEmittedWithoutMedia() {
// WHEN device source emits an event without media data
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// THEN an event isn't emitted
verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any());
}
@@ -105,7 +107,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void emitEventAfterDeviceFirst() {
// GIVEN that a device event has already been received
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// WHEN media event is received
mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// THEN the listener receives a combined event
@@ -119,7 +121,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
// GIVEN that media event has already been received
mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// WHEN device event is received
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture());
@@ -127,6 +129,64 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
}
@Test
+ public void migrateKeyMediaFirst() {
+ // GIVEN that media and device info has already been received
+ mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
+ mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
+ reset(mListener);
+ // WHEN a key migration event is received
+ mDataListener.onMediaDataLoaded(KEY, OLD_KEY, mMediaData);
+ // THEN the listener receives a combined event
+ ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
+ verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture());
+ assertThat(captor.getValue().getDevice()).isNotNull();
+ }
+
+ @Test
+ public void migrateKeyDeviceFirst() {
+ // GIVEN that media and device info has already been received
+ mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
+ mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
+ reset(mListener);
+ // WHEN a key migration event is received
+ mDeviceListener.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
+ // THEN the listener receives a combined event
+ ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
+ verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture());
+ assertThat(captor.getValue().getDevice()).isNotNull();
+ }
+
+ @Test
+ public void migrateKeyMediaAfter() {
+ // GIVEN that media and device info has already been received
+ mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
+ mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
+ reset(mListener);
+ // WHEN a second key migration event is received for media
+ mDataListener.onMediaDataLoaded(KEY, OLD_KEY, mMediaData);
+ // THEN the key has already been migrated
+ ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
+ verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture());
+ assertThat(captor.getValue().getDevice()).isNotNull();
+ }
+
+ @Test
+ public void migrateKeyDeviceAfter() {
+ // GIVEN that media and device info has already been received
+ mDataListener.onMediaDataLoaded(OLD_KEY, null, mMediaData);
+ mDeviceListener.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
+ mDataListener.onMediaDataLoaded(KEY, OLD_KEY, mMediaData);
+ reset(mListener);
+ // WHEN a second key migration event is received for the device
+ mDeviceListener.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
+ // THEN the key has already be migrated
+ ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
+ verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture());
+ assertThat(captor.getValue().getDevice()).isNotNull();
+ }
+
+ @Test
public void mediaDataRemoved() {
// WHEN media data is removed without first receiving device or data
mDataListener.onMediaDataRemoved(KEY);
@@ -143,7 +203,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void mediaDataRemovedAfterDeviceEvent() {
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
mDataListener.onMediaDataRemoved(KEY);
verify(mListener).onMediaDataRemoved(eq(KEY));
}
@@ -152,7 +212,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
public void mediaDataKeyUpdated() {
// GIVEN that device and media events have already been received
mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
// WHEN the key is changed
mDataListener.onMediaDataLoaded("NEW_KEY", KEY, mMediaData);
// THEN the listener gets a load event with the correct keys
@@ -163,7 +223,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void getDataIncludesDevice() {
// GIVEN that device and media events have been received
- mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ mDeviceListener.onMediaDeviceChanged(KEY, null, mDeviceData);
mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// THEN the result of getData includes device info
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 6761b282b26a..59c2d0e86c56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -31,6 +31,7 @@ import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
private const val KEY = "KEY"
+private const val KEY_2 = "KEY_2"
private const val PACKAGE_NAME = "com.android.systemui"
private const val APP_NAME = "SystemUI"
private const val SESSION_ARTIST = "artist"
@@ -156,8 +157,43 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
// WHEN the notification is removed
mediaDataManager.onNotificationRemoved(KEY)
- // THEN the media data indicates that it is
+ // THEN the media data indicates that it is for resumption
+ assertThat(listener.data!!.resumption).isTrue()
+ // AND the new key is the package name
+ assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
+ assertThat(listener.oldKey!!).isEqualTo(KEY)
+ assertThat(listener.removedKey).isNull()
+ }
+
+ @Test
+ fun testOnNotificationRemoved_twoWithResumption() {
+ // GIVEN that the manager has two notifications with resume actions
+ val listener = TestListener()
+ mediaDataManager.addListener(listener)
+ whenever(controller.metadata).thenReturn(metadataBuilder.build())
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataManager.onNotificationAdded(KEY_2, mediaNotification)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(2)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(2)
+ val data = listener.data!!
+ assertThat(data.resumption).isFalse()
+ val resumableData = data.copy(resumeAction = Runnable {})
+ mediaDataManager.onMediaDataLoaded(KEY, null, resumableData)
+ mediaDataManager.onMediaDataLoaded(KEY_2, null, resumableData)
+ // WHEN the first is removed
+ mediaDataManager.onNotificationRemoved(KEY)
+ // THEN the data is for resumption and the key is migrated to the package name
+ assertThat(listener.data!!.resumption).isTrue()
+ assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
+ assertThat(listener.oldKey!!).isEqualTo(KEY)
+ assertThat(listener.removedKey).isNull()
+ // WHEN the second is removed
+ mediaDataManager.onNotificationRemoved(KEY_2)
+ // THEN the data is for resumption and the second key is removed
assertThat(listener.data!!.resumption).isTrue()
+ assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
+ assertThat(listener.oldKey!!).isEqualTo(PACKAGE_NAME)
+ assertThat(listener.removedKey!!).isEqualTo(KEY_2)
}
@Test
@@ -190,6 +226,7 @@ class MediaDataManagerTest : SysuiTestCase() {
var data: MediaData? = null
var key: String? = null
var oldKey: String? = null
+ var removedKey: String? = null
override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
this.key = key
@@ -198,9 +235,7 @@ class MediaDataManagerTest : SysuiTestCase() {
}
override fun onMediaDataRemoved(key: String) {
- this.key = key
- oldKey = null
- data = null
+ removedKey = key
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index fc22eeb3ea68..3c6e19f0ec6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -166,7 +166,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// THEN the listener for the old key should removed.
verify(lmm).unregisterCallback(any())
// AND a new device event emitted
- val data = captureDeviceData(KEY)
+ val data = captureDeviceData(KEY, KEY_OLD)
assertThat(data.enabled).isTrue()
assertThat(data.name).isEqualTo(DEVICE_NAME)
}
@@ -179,13 +179,14 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// WHEN the new key is the same as the old key
manager.onMediaDataLoaded(KEY, KEY, mediaData)
// THEN no event should be emitted
- verify(listener, never()).onMediaDeviceChanged(eq(KEY), any())
+ verify(listener, never()).onMediaDeviceChanged(eq(KEY), eq(null), any())
}
@Test
fun unknownOldKey() {
- manager.onMediaDataLoaded(KEY, "unknown", mediaData)
- verify(listener).onMediaDeviceChanged(eq(KEY), any())
+ val oldKey = "unknown"
+ manager.onMediaDataLoaded(KEY, oldKey, mediaData)
+ verify(listener).onMediaDeviceChanged(eq(KEY), eq(oldKey), any())
}
@Test
@@ -223,7 +224,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
manager.removeListener(listener)
// THEN it doesn't receive device events
manager.onMediaDataLoaded(KEY, null, mediaData)
- verify(listener, never()).onMediaDeviceChanged(eq(KEY), any())
+ verify(listener, never()).onMediaDeviceChanged(eq(KEY), eq(null), any())
}
@Test
@@ -318,9 +319,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
return captor.getValue()
}
- fun captureDeviceData(key: String): MediaDeviceData {
+ fun captureDeviceData(key: String, oldKey: String? = null): MediaDeviceData {
val captor = ArgumentCaptor.forClass(MediaDeviceData::class.java)
- verify(listener).onMediaDeviceChanged(eq(key), captor.capture())
+ verify(listener).onMediaDeviceChanged(eq(key), eq(oldKey), captor.capture())
return captor.getValue()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
index 2d9fa1bbd5ca..583d0692565f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
@@ -16,7 +16,7 @@
package com.android.systemui.onehanded;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
@@ -52,12 +52,12 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mOneHandedAnimationController = new OneHandedAnimationController(mContext,
+ mOneHandedAnimationController = new OneHandedAnimationController(
new OneHandedSurfaceTransactionHelper(mContext));
}
@Test
- public void testGetAnimator_withSameBounds_returnTranslateAnimator() {
+ public void testGetAnimator_withSameBounds_returnAnimator() {
final Rect originalBounds = new Rect(0, 0, TEST_BOUNDS_WIDTH, TEST_BOUNDS_HEIGHT);
final Rect destinationBounds = originalBounds;
destinationBounds.offset(0, 300);
@@ -65,7 +65,6 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase {
mOneHandedAnimationController
.getAnimator(mMockLeash, originalBounds, destinationBounds);
- assertEquals("Expected translate animation",
- OneHandedAnimationController.ANIM_TYPE_TRANSLATE, animator.getAnimationType());
+ assertNotNull(animator);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
index 28dad14f221a..07a32a977f82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -29,11 +29,11 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.Configuration;
-import android.graphics.Rect;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.DisplayInfo;
+import android.view.Display;
+import android.view.Surface;
import android.view.SurfaceControl;
import android.window.DisplayAreaInfo;
import android.window.IWindowContainerToken;
@@ -58,7 +58,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
static final int DISPLAY_HEIGHT = 1000;
DisplayAreaInfo mDisplayAreaInfo;
- DisplayInfo mDisplayInfo;
+ Display mDisplay;
Handler mUpdateHandler;
OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
OneHandedAnimationController.OneHandedTransitionAnimator mFakeAnimator;
@@ -80,20 +80,13 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mDisplayAreaOrganizer = new OneHandedDisplayAreaOrganizer(mContext,
- mMockDisplayController,
- mMockAnimationController,
- mMockSurfaceTransactionHelper);
- mUpdateHandler = Mockito.spy(mDisplayAreaOrganizer.getUpdateHandler());
mToken = new WindowContainerToken(mMockRealToken);
mLeash = new SurfaceControl();
+ mDisplay = mContext.getDisplay();
mDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY, FEATURE_ONE_HANDED);
mDisplayAreaInfo.configuration.orientation = Configuration.ORIENTATION_PORTRAIT;
- mDisplayInfo = new DisplayInfo();
- mDisplayInfo.logicalWidth = DISPLAY_WIDTH;
- mDisplayInfo.logicalHeight = DISPLAY_HEIGHT;
-
when(mMockAnimationController.getAnimator(any(), any(), any())).thenReturn(null);
+ when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
when(mMockSurfaceTransactionHelper.translate(any(), any(), anyFloat())).thenReturn(
mMockSurfaceTransactionHelper);
when(mMockSurfaceTransactionHelper.crop(any(), any(), any())).thenReturn(
@@ -106,8 +99,11 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
when(mMockAnimator.setTransitionDirection(anyInt())).thenReturn(mFakeAnimator);
when(mMockLeash.getWidth()).thenReturn(DISPLAY_WIDTH);
when(mMockLeash.getHeight()).thenReturn(DISPLAY_HEIGHT);
- when(mMockDisplayController.getDisplay(anyInt())).thenReturn(null);
+ mDisplayAreaOrganizer = new OneHandedDisplayAreaOrganizer(mContext,
+ mMockDisplayController,
+ mMockAnimationController);
+ mUpdateHandler = Mockito.spy(mDisplayAreaOrganizer.getUpdateHandler());
}
@Test
@@ -135,7 +131,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
mDisplayAreaOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
mDisplayAreaOrganizer.onDisplayAreaInfoChanged(newDisplayAreaInfo);
- assertThat(mDisplayAreaOrganizer.mDisplayAreaInfo).isEqualTo(newDisplayAreaInfo);
+ assertThat(mDisplayAreaOrganizer.mDisplayAreaMap.containsKey(mDisplayAreaInfo)).isTrue();
}
@Test
@@ -154,13 +150,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
public void testResetImmediately() {
// To prevent mNativeObject of Surface is null in the test flow
when(mMockLeash.isValid()).thenReturn(false);
- final Rect newBounds = new Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
- final DisplayAreaInfo newDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY,
- FEATURE_ONE_HANDED);
- newDisplayAreaInfo.configuration.orientation = Configuration.ORIENTATION_LANDSCAPE;
-
- mDisplayAreaOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mMockLeash);
- mDisplayAreaOrganizer.onDisplayAreaInfoChanged(newDisplayAreaInfo);
+ mDisplayAreaOrganizer.onRotateDisplay(mContext.getResources(), Surface.ROTATION_90);
assertThat(mUpdateHandler.hasMessages(
OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isNotNull();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
index f4fc7eafe247..b6b2217837b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.Display;
import androidx.test.filters.SmallTest;
@@ -45,6 +46,7 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class OneHandedManagerImplTest extends OneHandedTestCase {
+ Display mDisplay;
OneHandedManagerImpl mOneHandedManagerImpl;
OneHandedTimeoutHandler mTimeoutHandler;
@@ -53,8 +55,6 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
@Mock
OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
@Mock
- OneHandedSurfaceTransactionHelper mMockSurfaceTransactionHelper;
- @Mock
OneHandedTouchHandler mMockTouchHandler;
@Mock
OneHandedGestureHandler mMockGestureHandler;
@@ -64,6 +64,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mDisplay = mContext.getDisplay();
mOneHandedManagerImpl = new OneHandedManagerImpl(getContext(),
mMockDisplayController,
mMockDisplayAreaOrganizer,
@@ -72,19 +73,18 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
mMockSysUiState);
mTimeoutHandler = Mockito.spy(OneHandedTimeoutHandler.get());
+ when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
when(mMockDisplayAreaOrganizer.isInOneHanded()).thenReturn(false);
}
-
@Test
public void testDefaultShouldNotInOneHanded() {
final OneHandedSurfaceTransactionHelper transactionHelper =
new OneHandedSurfaceTransactionHelper(mContext);
final OneHandedAnimationController animationController = new OneHandedAnimationController(
- mContext, transactionHelper);
+ transactionHelper);
OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer(
- mContext, mMockDisplayController, animationController,
- mMockSurfaceTransactionHelper);
+ mContext, mMockDisplayController, animationController);
assertThat(displayAreaOrganizer.isInOneHanded()).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
index e6287e7063d3..7eeae67c9fdf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/MediaNotificationProcessorTest.java
@@ -38,8 +38,8 @@ import android.widget.RemoteViews;
import androidx.palette.graphics.Palette;
import androidx.test.runner.AndroidJUnit4;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.tests.R;
import org.junit.After;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index 25da74137a90..a2f8c1cb0ad3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -50,7 +50,9 @@ import android.widget.TextView;
import androidx.test.filters.SmallTest;
import androidx.test.filters.Suppress;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
@@ -59,7 +61,6 @@ import com.android.systemui.statusbar.notification.row.NotificationRowContentBin
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
-import com.android.systemui.tests.R;
import org.junit.Assert;
import org.junit.Before;
@@ -110,6 +111,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
() -> smartReplyConstants,
() -> smartReplyController,
mConversationNotificationProcessor,
+ mock(MediaFeatureFlag.class),
mock(Executor.class));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 5640f08264a6..c5374b2eb049 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -43,6 +43,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
@@ -86,6 +87,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
@@ -120,8 +122,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
@Mock private NotificationGutsManager mGutsManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private NotificationMediaManager mNotificationMediaManager;
- @Mock private ExpandableNotificationRowComponent.Builder
- mExpandableNotificationRowComponentBuilder;
+ @Mock(answer = Answers.RETURNS_SELF)
+ private ExpandableNotificationRowComponent.Builder mExpandableNotificationRowComponentBuilder;
@Mock private ExpandableNotificationRowComponent mExpandableNotificationRowComponent;
@Mock private FalsingManager mFalsingManager;
@Mock private KeyguardBypassController mKeyguardBypassController;
@@ -197,6 +199,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
() -> mock(SmartReplyConstants.class),
() -> mock(SmartReplyController.class),
mock(ConversationNotificationProcessor.class),
+ mock(MediaFeatureFlag.class),
mBgExecutor);
mRowContentBindStage = new RowContentBindStage(
binder,
@@ -209,21 +212,9 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
when(mExpandableNotificationRowComponentBuilder
.expandableNotificationRow(viewCaptor.capture()))
.thenReturn(mExpandableNotificationRowComponentBuilder);
- when(mExpandableNotificationRowComponentBuilder
- .notificationEntry(any()))
- .thenReturn(mExpandableNotificationRowComponentBuilder);
- when(mExpandableNotificationRowComponentBuilder
- .onDismissRunnable(any()))
- .thenReturn(mExpandableNotificationRowComponentBuilder);
- when(mExpandableNotificationRowComponentBuilder
- .rowContentBindStage(any()))
- .thenReturn(mExpandableNotificationRowComponentBuilder);
- when(mExpandableNotificationRowComponentBuilder
- .onExpandClickListener(any()))
- .thenReturn(mExpandableNotificationRowComponentBuilder);
-
when(mExpandableNotificationRowComponentBuilder.build())
.thenReturn(mExpandableNotificationRowComponent);
+
when(mExpandableNotificationRowComponent.getExpandableNotificationRowController())
.thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
new ExpandableNotificationRowController(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 362914d6f848..8ccbb2ebb0db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -43,9 +43,11 @@ import android.text.TextUtils;
import android.view.LayoutInflater;
import android.widget.RemoteViews;
+import com.android.systemui.R;
import com.android.systemui.TestableDependency;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.bubbles.BubblesTestActivity;
+import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -68,7 +70,6 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
-import com.android.systemui.tests.R;
import org.mockito.ArgumentCaptor;
@@ -133,6 +134,7 @@ public class NotificationTestHelper {
() -> mock(SmartReplyConstants.class),
() -> mock(SmartReplyController.class),
mock(ConversationNotificationProcessor.class),
+ mock(MediaFeatureFlag.class),
mock(Executor.class));
contentBinder.setInflateSynchronously(true);
mBindStage = new RowContentBindStage(contentBinder,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
index 45f7c5a6fdc0..a147c8d0f121 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
@@ -24,10 +24,10 @@ import android.widget.RemoteViews;
import androidx.test.filters.SmallTest;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.tests.R;
import org.junit.Assert;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index 5ce209b1f249..4d6922c02c41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -15,12 +15,13 @@
package com.android.systemui.statusbar.policy;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.content.Intent;
import android.location.LocationManager;
import android.testing.AndroidTestingRunner;
@@ -31,12 +32,15 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.appops.AppOpsController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -46,11 +50,15 @@ public class LocationControllerImplTest extends SysuiTestCase {
private LocationControllerImpl mLocationController;
private TestableLooper mTestableLooper;
+ @Mock private AppOpsController mAppOpsController;
+
@Before
public void setup() {
+ MockitoAnnotations.initMocks(this);
+
mTestableLooper = TestableLooper.get(this);
mLocationController = spy(new LocationControllerImpl(mContext,
- mTestableLooper.getLooper(),
+ mAppOpsController,
mTestableLooper.getLooper(),
mock(BroadcastDispatcher.class),
mock(BootCompleteCache.class)));
@@ -67,12 +75,12 @@ public class LocationControllerImplTest extends SysuiTestCase {
mLocationController.addCallback(callback);
mLocationController.addCallback(mock(LocationChangeCallback.class));
- when(mLocationController.areActiveHighPowerLocationRequests()).thenReturn(false);
- mLocationController.onReceive(mContext, new Intent(
- LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION));
- when(mLocationController.areActiveHighPowerLocationRequests()).thenReturn(true);
- mLocationController.onReceive(mContext, new Intent(
- LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION));
+ doReturn(false).when(mLocationController).areActiveHighPowerLocationRequests();
+ mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
+ "", false);
+ doReturn(true).when(mLocationController).areActiveHighPowerLocationRequests();
+ mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
+ "", true);
mTestableLooper.processAllMessages();
}
@@ -107,11 +115,22 @@ public class LocationControllerImplTest extends SysuiTestCase {
LocationChangeCallback callback = mock(LocationChangeCallback.class);
mLocationController.addCallback(callback);
+
+ mTestableLooper.processAllMessages();
+
mLocationController.onReceive(mContext, new Intent(LocationManager.MODE_CHANGED_ACTION));
mTestableLooper.processAllMessages();
verify(callback, times(2)).onLocationSettingsChanged(anyBoolean());
+
+ doReturn(true).when(mLocationController).areActiveHighPowerLocationRequests();
+ mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
+ "", true);
+
+ mTestableLooper.processAllMessages();
+
+ verify(callback, times(1)).onLocationActiveChanged(anyBoolean());
}
@Test
@@ -124,6 +143,8 @@ public class LocationControllerImplTest extends SysuiTestCase {
verify(callback).onLocationSettingsChanged(anyBoolean());
mLocationController.removeCallback(callback);
+ mTestableLooper.processAllMessages();
+
mLocationController.onReceive(mContext, new Intent(LocationManager.MODE_CHANGED_ACTION));
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java
new file mode 100644
index 000000000000..8c9248222014
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.util.concurrency;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Implementation of {@link ThreadFactory} that returns {@link FakeExecutor} where it can.
+ */
+public class FakeThreadFactory implements ThreadFactory {
+ private final FakeExecutor mFakeExecutor;
+
+ public FakeThreadFactory(FakeExecutor fakeExecutor) {
+ mFakeExecutor = fakeExecutor;
+ }
+
+ @Override
+ public Executor buildExecutorOnNewThread(String threadName) {
+ return mFakeExecutor;
+ }
+
+ @Override
+ public DelayableExecutor buildDelayableExecutorOnNewThread(String threadName) {
+ return mFakeExecutor;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
index 9149599f2c7c..0d8dd2c0f140 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/AsyncSensorManagerTest.java
@@ -23,15 +23,16 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.hardware.SensorEventListener;
-import android.os.Handler;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.concurrency.FakeThreadFactory;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -39,20 +40,20 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
public class AsyncSensorManagerTest extends SysuiTestCase {
private AsyncSensorManager mAsyncSensorManager;
private SensorEventListener mListener;
private FakeSensorManager.FakeProximitySensor mSensor;
private PluginManager mPluginManager;
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
@Before
public void setUp() throws Exception {
mPluginManager = mock(PluginManager.class);
FakeSensorManager fakeSensorManager = new FakeSensorManager(mContext);
mAsyncSensorManager = new AsyncSensorManager(
- fakeSensorManager, mPluginManager, new Handler());
+ fakeSensorManager, new FakeThreadFactory(mFakeExecutor), mPluginManager);
mSensor = fakeSensorManager.getFakeProximitySensor();
mListener = mock(SensorEventListener.class);
}
@@ -99,6 +100,6 @@ public class AsyncSensorManagerTest extends SysuiTestCase {
}
public void waitUntilRequestsCompleted() {
- TestableLooper.get(this).processAllMessages();
+ mFakeExecutor.runAllReady();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java
index 8ba7d62ba843..d3a35a735f6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ThresholdSensorImplTest.java
@@ -20,12 +20,14 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import android.os.Handler;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.Assert;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.concurrency.FakeThreadFactory;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -33,21 +35,20 @@ import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
public class ThresholdSensorImplTest extends SysuiTestCase {
private ThresholdSensorImpl mThresholdSensor;
private FakeSensorManager mSensorManager;
private AsyncSensorManager mAsyncSensorManager;
private FakeSensorManager.FakeProximitySensor mFakeProximitySensor;
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
@Before
public void setUp() throws Exception {
- allowTestableLooperAsMainThread();
mSensorManager = new FakeSensorManager(getContext());
mAsyncSensorManager = new AsyncSensorManager(
- mSensorManager, null, new Handler());
+ mSensorManager, new FakeThreadFactory(mFakeExecutor), null);
mFakeProximitySensor = mSensorManager.getFakeProximitySensor();
ThresholdSensorImpl.Builder thresholdSensorBuilder = new ThresholdSensorImpl.Builder(
@@ -60,6 +61,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
@Test
public void testSingleListener() {
+ Assert.setTestThread(Thread.currentThread());
TestableListener listener = new TestableListener();
assertFalse(mThresholdSensor.isRegistered());
@@ -81,6 +83,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
@Test
public void testMultiListener() {
+ Assert.setTestThread(Thread.currentThread());
TestableListener listenerA = new TestableListener();
TestableListener listenerB = new TestableListener();
@@ -114,6 +117,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
@Test
public void testDuplicateListener() {
+ Assert.setTestThread(Thread.currentThread());
TestableListener listenerA = new TestableListener();
assertFalse(mThresholdSensor.isRegistered());
@@ -138,6 +142,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
}
@Test
public void testUnregister() {
+ Assert.setTestThread(Thread.currentThread());
TestableListener listener = new TestableListener();
assertFalse(mThresholdSensor.isRegistered());
@@ -157,6 +162,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
@Test
public void testPauseAndResume() {
+ Assert.setTestThread(Thread.currentThread());
TestableListener listener = new TestableListener();
assertFalse(mThresholdSensor.isRegistered());
@@ -199,6 +205,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
@Test
public void testAlertListeners() {
+ Assert.setTestThread(Thread.currentThread());
TestableListener listenerA = new TestableListener();
TestableListener listenerB = new TestableListener();
@@ -230,6 +237,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
@Test
public void testHysteresis() {
+ Assert.setTestThread(Thread.currentThread());
float lowValue = 10f;
float highValue = 100f;
FakeSensorManager.FakeGenericSensor sensor = mSensorManager.getFakeLightSensor();
@@ -278,6 +286,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
@Test
public void testAlertAfterPause() {
+ Assert.setTestThread(Thread.currentThread());
TestableListener listener = new TestableListener();
mThresholdSensor.register(listener);
@@ -307,7 +316,7 @@ public class ThresholdSensorImplTest extends SysuiTestCase {
}
private void waitForSensorManager() {
- TestableLooper.get(this).processAllMessages();
+ mFakeExecutor.runAllReady();
}
}
diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 74df11370e50..e10bab4b36b5 100644
--- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -42,6 +42,7 @@ import android.net.dhcp.DhcpPacket;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.system.Os;
import android.util.Log;
@@ -224,9 +225,19 @@ public class EthernetTetheringTest {
}
+ private boolean isAdbOverNetwork() {
+ // If adb TCP port opened, this test may running by adb over network.
+ return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1)
+ || (SystemProperties.getInt("service.adb.tcp.port", -1) > -1);
+ }
+
@Test
public void testPhysicalEthernet() throws Exception {
assumeTrue(mEm.isAvailable());
+ // Do not run this test if adb is over network and ethernet is connected.
+ // It is likely the adb run over ethernet, the adb would break when ethernet is switching
+ // from client mode to server mode. See b/160389275.
+ assumeFalse(isAdbOverNetwork());
// Get an interface to use.
final String iface = mTetheredInterfaceRequester.getInterface();
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index c82dff22e328..a4c5a2341d77 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -295,6 +295,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
mEventTypes = info.eventTypes;
mFeedbackType = info.feedbackType;
String[] packageNames = info.packageNames;
+ mPackageNames.clear();
if (packageNames != null) {
mPackageNames.addAll(Arrays.asList(packageNames));
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 468e93a8f683..669bb24e0e77 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -747,6 +747,13 @@ public class AccessibilityWindowManager {
* Dumps all {@link AccessibilityWindowInfo}s here.
*/
void dumpLocked(FileDescriptor fd, final PrintWriter pw, String[] args) {
+ pw.append("Global Info [ ");
+ pw.println("Top focused display Id = " + mTopFocusedDisplayId);
+ pw.println(" Active Window Id = " + mActiveWindowId);
+ pw.println(" Top Focused Window Id = " + mTopFocusedWindowId);
+ pw.println(" Accessibility Focused Window Id = " + mAccessibilityFocusedWindowId
+ + " ]");
+ pw.println();
if (mWindows != null) {
final int windowCount = mWindows.size();
for (int j = 0; j < windowCount; j++) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index 68eeb0a3ca2e..b2daae48bb0e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -103,6 +103,8 @@ final class AutofillInlineSuggestionsRequestSession {
private boolean mDestroyed = false;
@GuardedBy("mLock")
private boolean mPreviousHasNonPinSuggestionShow;
+ @GuardedBy("mLock")
+ private boolean mImeSessionInvalidated = false;
AutofillInlineSuggestionsRequestSession(
@NonNull InputMethodManagerInternal inputMethodManagerInternal, int userId,
@@ -157,7 +159,7 @@ final class AutofillInlineSuggestionsRequestSession {
Slog.d(TAG,
"onInlineSuggestionsResponseLocked called for:" + inlineFillUi.getAutofillId());
}
- if (mImeRequest == null || mResponseCallback == null) {
+ if (mImeRequest == null || mResponseCallback == null || mImeSessionInvalidated) {
return false;
}
// TODO(b/151123764): each session should only correspond to one field.
@@ -191,6 +193,7 @@ final class AutofillInlineSuggestionsRequestSession {
if (mDestroyed) {
return;
}
+ mImeSessionInvalidated = false;
if (sDebug) Slog.d(TAG, "onCreateInlineSuggestionsRequestLocked called: " + mAutofillId);
mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(mUserId,
new InlineSuggestionsRequestInfo(mComponentName, mAutofillId, mUiExtras),
@@ -291,6 +294,7 @@ final class AutofillInlineSuggestionsRequestSession {
return;
}
mImeRequestReceived = true;
+ mImeSessionInvalidated = false;
if (request != null && callback != null) {
mImeRequest = request;
@@ -346,6 +350,20 @@ final class AutofillInlineSuggestionsRequestSession {
}
}
+ /**
+ * Handles the IME session status received from the IME.
+ *
+ * <p> Should only be invoked in the {@link #mHandler} thread.
+ */
+ private void handleOnReceiveImeSessionInvalidated() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ mImeSessionInvalidated = true;
+ }
+ }
+
private static final class InlineSuggestionsRequestCallbackImpl extends
IInlineSuggestionsRequestCallback.Stub {
@@ -433,6 +451,18 @@ final class AutofillInlineSuggestionsRequestSession {
session, false, false));
}
}
+
+ @BinderThread
+ @Override
+ public void onInlineSuggestionsSessionInvalidated() throws RemoteException {
+ if (sDebug) Slog.d(TAG, "onInlineSuggestionsSessionInvalidated() called.");
+ final AutofillInlineSuggestionsRequestSession session = mSession.get();
+ if (session != null) {
+ session.mHandler.sendMessage(obtainMessage(
+ AutofillInlineSuggestionsRequestSession
+ ::handleOnReceiveImeSessionInvalidated, session));
+ }
+ }
}
private static boolean match(@Nullable AutofillId autofillId,
diff --git a/services/backup/OWNERS b/services/backup/OWNERS
index ba61d1c0849b..7c7e74285bf5 100644
--- a/services/backup/OWNERS
+++ b/services/backup/OWNERS
@@ -1,7 +1,12 @@
# Bug component: 656484
+aabhinav@google.com
alsutton@google.com
bryanmawhinney@google.com
+jstemmer@google.com
nathch@google.com
+niagra@google.com
+niamhfw@google.com
+philippov@google.com
rthakohov@google.com
tobiast@google.com
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 7334c86d90ac..84bd59b7730e 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -43,8 +43,6 @@ import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIE
import static android.os.storage.OnObbStateChangeListener.MOUNTED;
import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
import static android.os.storage.StorageManager.PROP_FORCED_SCOPED_STORAGE_WHITELIST;
-import static android.os.storage.StorageManager.PROP_FUSE;
-import static android.os.storage.StorageManager.PROP_SETTINGS_FUSE;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -131,7 +129,6 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DataUnit;
-import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -233,13 +230,6 @@ class StorageManagerService extends IStorageManager.Stub
*/
private static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
- /**
- * If {@code 1}, enables FuseDaemon to intercept file system ops. If {@code -1},
- * disables FuseDaemon. If {@code 0}, uses the default value from the build system.
- */
- private static final String FUSE_ENABLED = "fuse_enabled";
- private static final boolean DEFAULT_FUSE_ENABLED = true;
-
@GuardedBy("mLock")
private final Set<Integer> mFuseMountedUser = new ArraySet<>();
@@ -609,8 +599,6 @@ class StorageManagerService extends IStorageManager.Stub
// Not guarded by a lock.
private final StorageSessionController mStorageSessionController;
- private final boolean mIsFuseEnabled;
-
private final boolean mVoldAppDataIsolationEnabled;
@GuardedBy("mLock")
@@ -926,7 +914,6 @@ class StorageManagerService extends IStorageManager.Stub
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
mContext.getMainExecutor(), (properties) -> {
refreshIsolatedStorageSettings();
- refreshFuseSettings();
});
refreshIsolatedStorageSettings();
}
@@ -993,27 +980,6 @@ class StorageManagerService extends IStorageManager.Stub
}
/**
- * The most recent flag change takes precedence. Change fuse Settings flag if Device Config is
- * changed. Settings flag change will in turn change fuse system property (persist.sys.fuse)
- * whenever the user reboots.
- */
- private void refreshFuseSettings() {
- int isFuseEnabled = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
- FUSE_ENABLED, 0);
- if (isFuseEnabled == 1) {
- Slog.d(TAG, "Device Config flag for FUSE is enabled, turn Settings fuse flag on");
- SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
- + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "true");
- } else if (isFuseEnabled == -1) {
- Slog.d(TAG, "Device Config flag for FUSE is disabled, turn Settings fuse flag off");
- SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
- + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "false");
- }
- // else, keep the build config.
- // This can be overridden by direct adjustment of persist.sys.fflag.override.settings_fuse
- }
-
- /**
* MediaProvider has a ton of code that makes assumptions about storage
* paths never changing, so we outright kill them to pick up new state.
*/
@@ -1091,13 +1057,9 @@ class StorageManagerService extends IStorageManager.Stub
final UserManager userManager = mContext.getSystemService(UserManager.class);
final List<UserInfo> users = userManager.getUsers();
- if (mIsFuseEnabled) {
- mStorageSessionController.onReset(mVold, () -> {
- mHandler.removeCallbacksAndMessages(null);
- });
- } else {
- killMediaProvider(users);
- }
+ mStorageSessionController.onReset(mVold, () -> {
+ mHandler.removeCallbacksAndMessages(null);
+ });
final int[] systemUnlockedUsers;
synchronized (mLock) {
@@ -1490,8 +1452,7 @@ class StorageManagerService extends IStorageManager.Stub
final ActivityManagerInternal amInternal =
LocalServices.getService(ActivityManagerInternal.class);
- if (mIsFuseEnabled && vol.mountUserId >= 0
- && !amInternal.isUserRunning(vol.mountUserId, 0)) {
+ if (vol.mountUserId >= 0 && !amInternal.isUserRunning(vol.mountUserId, 0)) {
Slog.d(TAG, "Ignoring volume " + vol.getId() + " because user "
+ Integer.toString(vol.mountUserId) + " is no longer running.");
return;
@@ -1803,12 +1764,8 @@ class StorageManagerService extends IStorageManager.Stub
SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
- // If there is no value in the property yet (first boot after data wipe), this value may be
- // incorrect until #updateFusePropFromSettings where we set the correct value and reboot if
- // different
- mIsFuseEnabled = SystemProperties.getBoolean(PROP_FUSE, DEFAULT_FUSE_ENABLED);
- mVoldAppDataIsolationEnabled = mIsFuseEnabled && SystemProperties.getBoolean(
- ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
+ mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
+ ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
mContext = context;
mResolver = mContext.getContentResolver();
mCallbacks = new Callbacks(FgThread.get().getLooper());
@@ -1821,7 +1778,7 @@ class StorageManagerService extends IStorageManager.Stub
// Add OBB Action Handler to StorageManagerService thread.
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
- mStorageSessionController = new StorageSessionController(mContext, mIsFuseEnabled);
+ mStorageSessionController = new StorageSessionController(mContext);
mInstaller = new Installer(mContext);
mInstaller.onStart();
@@ -1869,26 +1826,6 @@ class StorageManagerService extends IStorageManager.Stub
PackageManager.FEATURE_AUTOMOTIVE);
}
- /**
- * Checks if user changed the persistent settings_fuse flag from Settings UI
- * and updates PROP_FUSE (reboots if changed).
- */
- private void updateFusePropFromSettings() {
- boolean settingsFuseFlag = SystemProperties.getBoolean(PROP_SETTINGS_FUSE,
- DEFAULT_FUSE_ENABLED);
- Slog.d(TAG, "FUSE flags. Settings: " + settingsFuseFlag
- + ". Default: " + DEFAULT_FUSE_ENABLED);
-
- if (mIsFuseEnabled != settingsFuseFlag) {
- Slog.i(TAG, "Toggling persist.sys.fuse to " + settingsFuseFlag);
- // Set prop_fuse to match prop_settings_fuse because it is used by native daemons like
- // init, zygote, installd and vold
- SystemProperties.set(PROP_FUSE, Boolean.toString(settingsFuseFlag));
- // Then perform hard reboot to kick policy into place
- mContext.getSystemService(PowerManager.class).reboot("fuse_prop");
- }
- }
-
private void start() {
connectStoraged();
connectVold();
@@ -1987,15 +1924,6 @@ class StorageManagerService extends IStorageManager.Stub
if (provider != null) {
mExternalStorageAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}
-
- if (!mIsFuseEnabled) {
- try {
- mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null,
- mAppOpsCallback);
- mIAppOpsService.startWatchingMode(OP_LEGACY_STORAGE, null, mAppOpsCallback);
- } catch (RemoteException e) {
- }
- }
}
private ProviderInfo getProviderInfo(String authority) {
@@ -2071,7 +1999,6 @@ class StorageManagerService extends IStorageManager.Stub
private void bootCompleted() {
mBootCompleted = true;
mHandler.obtainMessage(H_BOOT_COMPLETED).sendToTarget();
- updateFusePropFromSettings();
}
private void handleBootCompleted() {
@@ -4269,14 +4196,14 @@ class StorageManagerService extends IStorageManager.Stub
return Zygote.MOUNT_EXTERNAL_NONE;
}
- if (mIsFuseEnabled && mStorageManagerInternal.isExternalStorageService(uid)) {
+ if (mStorageManagerInternal.isExternalStorageService(uid)) {
// Determine if caller requires pass_through mount; note that we do this for
// all processes that share a UID with MediaProvider; but this is fine, since
// those processes anyway share the same rights as MediaProvider.
return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
}
- if (mIsFuseEnabled && (mDownloadsAuthorityAppId == UserHandle.getAppId(uid)
+ if ((mDownloadsAuthorityAppId == UserHandle.getAppId(uid)
|| mExternalStorageAuthorityAppId == UserHandle.getAppId(uid))) {
// DownloadManager can write in app-private directories on behalf of apps;
// give it write access to Android/
@@ -4286,7 +4213,7 @@ class StorageManagerService extends IStorageManager.Stub
final boolean hasMtp = mIPackageManager.checkUidPermission(ACCESS_MTP, uid) ==
PERMISSION_GRANTED;
- if (mIsFuseEnabled && hasMtp) {
+ if (hasMtp) {
ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName,
0, UserHandle.getUserId(uid));
if (ai != null && ai.isSignedWithPlatformKey()) {
@@ -4749,27 +4676,25 @@ class StorageManagerService extends IStorageManager.Stub
public void onAppOpsChanged(int code, int uid, @Nullable String packageName, int mode) {
final long token = Binder.clearCallingIdentity();
try {
- if (mIsFuseEnabled) {
- // When using FUSE, we may need to kill the app if the op changes
- switch(code) {
- case OP_REQUEST_INSTALL_PACKAGES:
- // Always kill regardless of op change, to remount apps /storage
+ // When using FUSE, we may need to kill the app if the op changes
+ switch(code) {
+ case OP_REQUEST_INSTALL_PACKAGES:
+ // Always kill regardless of op change, to remount apps /storage
+ killAppForOpChange(code, uid);
+ return;
+ case OP_MANAGE_EXTERNAL_STORAGE:
+ if (mode != MODE_ALLOWED) {
+ // Only kill if op is denied, to lose external_storage gid
+ // Killing when op is granted to pickup the gid automatically,
+ // results in a bad UX, especially since the gid only gives access
+ // to unreliable volumes, USB OTGs that are rarely mounted. The app
+ // will get the external_storage gid on next organic restart.
killAppForOpChange(code, uid);
- return;
- case OP_MANAGE_EXTERNAL_STORAGE:
- if (mode != MODE_ALLOWED) {
- // Only kill if op is denied, to lose external_storage gid
- // Killing when op is granted to pickup the gid automatically,
- // results in a bad UX, especially since the gid only gives access
- // to unreliable volumes, USB OTGs that are rarely mounted. The app
- // will get the external_storage gid on next organic restart.
- killAppForOpChange(code, uid);
- }
- return;
- case OP_LEGACY_STORAGE:
- updateLegacyStorageApps(packageName, uid, mode == MODE_ALLOWED);
- return;
- }
+ }
+ return;
+ case OP_LEGACY_STORAGE:
+ updateLegacyStorageApps(packageName, uid, mode == MODE_ALLOWED);
+ return;
}
if (mode == MODE_ALLOWED && (code == OP_READ_EXTERNAL_STORAGE
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 4ff9eb11c142..72f29b431880 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -43,6 +43,7 @@ import android.os.IBinder;
import android.os.IExternalVibratorService;
import android.os.IVibratorService;
import android.os.IVibratorStateListener;
+import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
@@ -70,6 +71,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.InputDevice;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -134,7 +136,7 @@ public class VibratorService extends IVibratorService.Stub
private final SparseArray<VibrationEffect> mFallbackEffects;
private final SparseArray<Integer> mProcStatesCache = new SparseArray<>();
private final WorkSource mTmpWorkSource = new WorkSource();
- private final Handler mH = new Handler();
+ private final Handler mH;
private final Object mLock = new Object();
private final Context mContext;
@@ -147,6 +149,7 @@ public class VibratorService extends IVibratorService.Stub
private Vibrator mVibrator;
private SettingsObserver mSettingObserver;
+ private final NativeWrapper mNativeWrapper;
private volatile VibrateThread mThread;
// mInputDeviceVibrators lock should be acquired after mLock, if both are
@@ -208,7 +211,12 @@ public class VibratorService extends IVibratorService.Stub
}
};
- private class Vibration implements IBinder.DeathRecipient {
+ /**
+ * Holder for a vibration to be played. This class can be shared with native methods for
+ * hardware callback support.
+ */
+ @VisibleForTesting
+ public final class Vibration implements IBinder.DeathRecipient {
public final IBinder token;
// Start time in CLOCK_BOOTTIME base.
public final long startTime;
@@ -248,9 +256,9 @@ public class VibratorService extends IVibratorService.Stub
}
}
- // Called by native
- @SuppressWarnings("unused")
- private void onComplete() {
+ /** Callback for when vibration is complete, to be called by native. */
+ @VisibleForTesting
+ public void onComplete() {
synchronized (mLock) {
if (this == mCurrentVibration) {
doCancelVibrateLocked();
@@ -354,15 +362,23 @@ public class VibratorService extends IVibratorService.Stub
}
VibratorService(Context context) {
- vibratorInit();
+ this(context, new Injector());
+ }
+
+ @VisibleForTesting
+ VibratorService(Context context, Injector injector) {
+ mNativeWrapper = injector.getNativeWrapper();
+ mH = injector.createHandler(Looper.myLooper());
+
+ mNativeWrapper.vibratorInit();
// Reset the hardware to a default state, in case this is a runtime
// restart instead of a fresh boot.
- vibratorOff();
+ mNativeWrapper.vibratorOff();
- mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
- mSupportsExternalControl = vibratorSupportsExternalControl();
- mSupportedEffects = asList(vibratorGetSupportedEffects());
- mCapabilities = vibratorGetCapabilities();
+ mSupportsAmplitudeControl = mNativeWrapper.vibratorSupportsAmplitudeControl();
+ mSupportsExternalControl = mNativeWrapper.vibratorSupportsExternalControl();
+ mSupportedEffects = asList(mNativeWrapper.vibratorGetSupportedEffects());
+ mCapabilities = mNativeWrapper.vibratorGetCapabilities();
mContext = context;
PowerManager pm = context.getSystemService(PowerManager.class);
@@ -419,7 +435,7 @@ public class VibratorService extends IVibratorService.Stub
mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_FACTOR_HIGH));
mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_FACTOR_VERY_HIGH));
- ServiceManager.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
+ injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
}
private VibrationEffect createEffectFromResource(int resId) {
@@ -642,7 +658,7 @@ public class VibratorService extends IVibratorService.Stub
if (effect == null) {
synchronized (mLock) {
mAlwaysOnEffects.delete(alwaysOnId);
- vibratorAlwaysOnDisable(alwaysOnId);
+ mNativeWrapper.vibratorAlwaysOnDisable(alwaysOnId);
}
} else {
if (!verifyVibrationEffect(effect)) {
@@ -1198,11 +1214,11 @@ public class VibratorService extends IVibratorService.Stub
private void updateAlwaysOnLocked(int id, Vibration vib) {
final int intensity = getCurrentIntensityLocked(vib);
if (!shouldVibrate(vib, intensity)) {
- vibratorAlwaysOnDisable(id);
+ mNativeWrapper.vibratorAlwaysOnDisable(id);
} else {
final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
final int strength = intensityToEffectStrength(intensity);
- vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
+ mNativeWrapper.vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
}
}
@@ -1238,7 +1254,7 @@ public class VibratorService extends IVibratorService.Stub
//synchronized (mInputDeviceVibrators) {
// return !mInputDeviceVibrators.isEmpty() || vibratorExists();
//}
- return vibratorExists();
+ return mNativeWrapper.vibratorExists();
}
private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) {
@@ -1262,7 +1278,7 @@ public class VibratorService extends IVibratorService.Stub
// Note: ordering is important here! Many haptic drivers will reset their
// amplitude when enabled, so we always have to enable first, then set the
// amplitude.
- vibratorOn(millis);
+ mNativeWrapper.vibratorOn(millis);
doVibratorSetAmplitude(amplitude);
}
}
@@ -1273,7 +1289,7 @@ public class VibratorService extends IVibratorService.Stub
private void doVibratorSetAmplitude(int amplitude) {
if (mSupportsAmplitudeControl) {
- vibratorSetAmplitude(amplitude);
+ mNativeWrapper.vibratorSetAmplitude(amplitude);
}
}
@@ -1291,7 +1307,7 @@ public class VibratorService extends IVibratorService.Stub
mInputDeviceVibrators.get(i).cancel();
}
} else {
- vibratorOff();
+ mNativeWrapper.vibratorOff();
}
}
} finally {
@@ -1310,7 +1326,7 @@ public class VibratorService extends IVibratorService.Stub
}
// Input devices don't support prebaked effect, so skip trying it with them.
if (!usingInputDeviceVibrators) {
- long duration = vibratorPerformEffect(prebaked.getId(),
+ long duration = mNativeWrapper.vibratorPerformEffect(prebaked.getId(),
prebaked.getEffectStrength(), vib,
hasCapability(IVibrator.CAP_PERFORM_CALLBACK));
long timeout = duration;
@@ -1363,7 +1379,7 @@ public class VibratorService extends IVibratorService.Stub
PrimitiveEffect[] primitiveEffects =
composed.getPrimitiveEffects().toArray(new PrimitiveEffect[0]);
- vibratorPerformComposedEffect(primitiveEffects, vib);
+ mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib);
// Composed effects don't actually give us an estimated duration, so we just guess here.
noteVibratorOnLocked(vib.uid, 10 * primitiveEffects.length);
@@ -1454,7 +1470,7 @@ public class VibratorService extends IVibratorService.Stub
}
}
mVibratorUnderExternalControl = externalControl;
- vibratorSetExternalControl(externalControl);
+ mNativeWrapper.vibratorSetExternalControl(externalControl);
}
private void dumpInternal(PrintWriter pw) {
@@ -1688,6 +1704,100 @@ public class VibratorService extends IVibratorService.Stub
}
}
+ /** Wrapper around the static-native methods of {@link VibratorService} for tests. */
+ @VisibleForTesting
+ public static class NativeWrapper {
+
+ /** Checks if vibrator exists on device. */
+ public boolean vibratorExists() {
+ return VibratorService.vibratorExists();
+ }
+
+ /** Initializes connection to vibrator HAL service. */
+ public void vibratorInit() {
+ VibratorService.vibratorInit();
+ }
+
+ /** Turns vibrator on for given time. */
+ public void vibratorOn(long milliseconds) {
+ VibratorService.vibratorOn(milliseconds);
+ }
+
+ /** Turns vibrator off. */
+ public void vibratorOff() {
+ VibratorService.vibratorOff();
+ }
+
+ /** Returns true if vibrator supports {@link #vibratorSetAmplitude(int)}. */
+ public boolean vibratorSupportsAmplitudeControl() {
+ return VibratorService.vibratorSupportsAmplitudeControl();
+ }
+
+ /** Sets the amplitude for the vibrator to run. */
+ public void vibratorSetAmplitude(int amplitude) {
+ VibratorService.vibratorSetAmplitude(amplitude);
+ }
+
+ /** Returns all predefined effects supported by the device vibrator. */
+ public int[] vibratorGetSupportedEffects() {
+ return VibratorService.vibratorGetSupportedEffects();
+ }
+
+ /** Turns vibrator on to perform one of the supported effects. */
+ public long vibratorPerformEffect(long effect, long strength, Vibration vibration,
+ boolean withCallback) {
+ return VibratorService.vibratorPerformEffect(effect, strength, vibration, withCallback);
+ }
+
+ /** Turns vibrator on to perform one of the supported composed effects. */
+ public void vibratorPerformComposedEffect(
+ VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration) {
+ VibratorService.vibratorPerformComposedEffect(effect, vibration);
+ }
+
+ /** Returns true if vibrator supports {@link #vibratorSetExternalControl(boolean)}. */
+ public boolean vibratorSupportsExternalControl() {
+ return VibratorService.vibratorSupportsExternalControl();
+ }
+
+ /** Enabled the device vibrator to be controlled by another service. */
+ public void vibratorSetExternalControl(boolean enabled) {
+ VibratorService.vibratorSetExternalControl(enabled);
+ }
+
+ /** Returns all capabilities of the device vibrator. */
+ public long vibratorGetCapabilities() {
+ return VibratorService.vibratorGetCapabilities();
+ }
+
+ /** Enable always-on vibration with given id and effect. */
+ public void vibratorAlwaysOnEnable(long id, long effect, long strength) {
+ VibratorService.vibratorAlwaysOnEnable(id, effect, strength);
+ }
+
+ /** Disable always-on vibration for given id. */
+ public void vibratorAlwaysOnDisable(long id) {
+ VibratorService.vibratorAlwaysOnDisable(id);
+ }
+ }
+
+ /** Point of injection for test dependencies */
+ @VisibleForTesting
+ static class Injector {
+
+ NativeWrapper getNativeWrapper() {
+ return new NativeWrapper();
+ }
+
+ Handler createHandler(Looper looper) {
+ return new Handler(looper);
+ }
+
+ void addService(String name, IBinder service) {
+ ServiceManager.addService(name, service);
+ }
+ }
+
BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f00527d91436..25e6eb6e943f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -232,7 +232,6 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerInternal;
-import android.location.LocationManager;
import android.media.audiofx.AudioEffect;
import android.net.Proxy;
import android.net.Uri;
@@ -3318,6 +3317,9 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public boolean setProcessMemoryTrimLevel(String process, int userId, int level)
throws RemoteException {
+ if (!isCallerShell()) {
+ throw new SecurityException("Only shell can call it");
+ }
synchronized (this) {
final ProcessRecord app = findProcessLocked(process, userId, "setProcessMemoryTrimLevel");
if (app == null) {
@@ -15860,7 +15862,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|| Intent.ACTION_FACTORY_RESET.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
- || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
|| TelephonyManager.ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE.equals(action)
|| SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)
|| AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION.equals(action)
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 5124c4a4797e..a2eea1348d5c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -470,22 +470,23 @@ public final class BroadcastQueue {
// if this receiver was slow, impose deferral policy on the app. This will kick in
// when processNextBroadcastLocked() next finds this uid as a receiver identity.
if (!r.timeoutExempt) {
- if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
+ // r.curApp can be null if finish has raced with process death - benign
+ // edge case, and we just ignore it because we're already cleaning up
+ // as expected.
+ if (r.curApp != null
+ && mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
// Core system packages are exempt from deferral policy
if (!UserHandle.isCore(r.curApp.uid)) {
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1)
+ " was slow: " + receiver + " br=" + r);
}
- if (r.curApp != null) {
- mDispatcher.startDeferring(r.curApp.uid);
- } else {
- Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r);
- }
+ mDispatcher.startDeferring(r.curApp.uid);
} else {
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "Core uid " + r.curApp.uid
- + " receiver was slow but not deferring: " + receiver + " br=" + r);
+ + " receiver was slow but not deferring: "
+ + receiver + " br=" + r);
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 04089e3a6c30..ebff0691c1f7 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -110,7 +110,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.RuntimeInit;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -155,9 +154,6 @@ public final class ProcessList {
static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
"persist.sys.vold_app_data_isolation_enabled";
- // A system property to control if fuse is enabled.
- static final String ANDROID_FUSE_ENABLED = "persist.sys.fuse";
-
// The minimum time we allow between crashes, for us to consider this
// application to be bad and stop and its services and reject broadcasts.
static final int MIN_CRASH_INTERVAL = 60 * 1000;
@@ -719,13 +715,8 @@ public final class ProcessList {
// want some apps enabled while some apps disabled
mAppDataIsolationEnabled =
SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
- boolean fuseEnabled = SystemProperties.getBoolean(ANDROID_FUSE_ENABLED, false);
- boolean voldAppDataIsolationEnabled = SystemProperties.getBoolean(
- ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true);
- if (!fuseEnabled && voldAppDataIsolationEnabled) {
- Slog.e(TAG, "Fuse is not enabled while vold app data isolation is enabled");
- }
- mVoldAppDataIsolationEnabled = fuseEnabled && voldAppDataIsolationEnabled;
+ mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
+ ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
mAppDataIsolationWhitelistedApps = new ArrayList<>(
SystemConfig.getInstance().getAppDataIsolationWhitelistedApps());
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4fd9ae256592..c8e4ee02e603 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1320,6 +1320,11 @@ public class AudioService extends IAudioService.Stub
device, caller, true /*hasModifyAudioSettings*/);
}
mStreamStates[streamType].checkFixedVolumeDevices();
+
+ // Unmute streams if device is full volume
+ if (mFullVolumeDevices.contains(device)) {
+ mStreamStates[streamType].mute(false);
+ }
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index 466465e0a3f5..68cc8845ec5c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -47,12 +47,17 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T>
private final VibrationEffect mSuccessVibrationEffect;
private final VibrationEffect mErrorVibrationEffect;
- AcquisitionClient(@NonNull Context context, @NonNull IBinder token,
- @NonNull ClientMonitorCallbackConverter listener, int userId,
+ /**
+ * Stops the HAL operation specific to the ClientMonitor subclass.
+ */
+ protected abstract void stopHalOperation();
+
+ AcquisitionClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId, int statsModality,
int statsAction, int statsClient) {
- super(context, token, listener, userId, owner, cookie, sensorId, statsModality, statsAction,
- statsClient);
+ super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId, statsModality,
+ statsAction, statsClient);
mPowerManager = context.getSystemService(PowerManager.class);
mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
@@ -78,7 +83,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T>
} catch (RemoteException e) {
Slog.w(TAG, "Failed to invoke sendError", e);
}
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
/**
@@ -110,7 +115,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T>
}
} catch (RemoteException e) {
Slog.w(TAG, "Failed to invoke sendAcquired", e);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index a9cefbaf8ac0..df836d599e26 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -52,12 +52,13 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> {
protected boolean mAuthAttempted;
- public AuthenticationClient(@NonNull Context context, @NonNull IBinder token,
- @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
- boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
- int sensorId, boolean isStrongBiometric, int statsModality, int statsClient,
- @NonNull TaskStackListener taskStackListener, @NonNull LockoutTracker lockoutTracker) {
- super(context, token, listener, targetUserId, owner, cookie, sensorId,
+ public AuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
+ int targetUserId, long operationId, boolean restricted, @NonNull String owner,
+ int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric,
+ int statsModality, int statsClient, @NonNull TaskStackListener taskStackListener,
+ @NonNull LockoutTracker lockoutTracker) {
+ super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
mIsStrongBiometric = isStrongBiometric;
mOperationId = operationId;
@@ -179,7 +180,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> {
}
} catch (RemoteException e) {
Slog.e(TAG, "Unable to notify listener, finishing", e);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
@@ -187,8 +188,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> {
* Start authentication
*/
@Override
- public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
- super.start(daemon, finishCallback);
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
final @LockoutTracker.LockoutMode int lockoutMode =
mLockoutTracker.getLockoutModeForUser(getTargetUserId());
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java
index a784b4b57eea..9f5abd873b4f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java
@@ -34,17 +34,12 @@ import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricService;
-import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.fingerprint.Fingerprint;
import android.os.Binder;
-import android.os.Bundle;
-import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.IHwBinder;
-import android.os.IRemoteCallback;
import android.os.Looper;
-import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -82,11 +77,9 @@ public abstract class BiometricServiceBase<T> extends SystemService
private final Context mContext;
private final String mKeyguardPackage;
protected final IActivityTaskManager mActivityTaskManager;
- private final PowerManager mPowerManager;
protected final BiometricTaskStackListener mTaskStackListener =
new BiometricTaskStackListener();
private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
- private final ArrayList<LockoutResetMonitor> mLockoutMonitors = new ArrayList<>();
protected final IStatusBarService mStatusBarService;
protected final Map<Integer, Long> mAuthenticatorIds =
@@ -109,21 +102,14 @@ public abstract class BiometricServiceBase<T> extends SystemService
}
};
- protected final ClientMonitor.FinishCallback mClientFinishCallback = clientMonitor -> {
- if (clientMonitor instanceof RemovalConsumer) {
- // When the last biometric of a group is removed, update the authenticator id.
- // Note that 1) multiple ClientMonitors may be cause onRemoved (e.g. internal cleanup),
- // and 2) updateActiveGroup updates/relies on global state, so there's no good way to
- // compartmentalize this yet.
- final int userId = clientMonitor.getTargetUserId();
- if (!hasEnrolledBiometrics(userId)) {
- Slog.d(getTag(), "Last biometric removed for user: " + userId
- + ", updating active group");
- updateActiveGroup(userId);
- }
- }
-
+ protected final ClientMonitor.FinishCallback mClientFinishCallback =
+ (clientMonitor, success) -> {
removeClient(clientMonitor);
+ // When enrollment finishes, update this group's authenticator id, as the HAL has
+ // already generated a new authenticator id when the new biometric is enrolled.
+ if (clientMonitor instanceof EnrollClient) {
+ updateActiveGroup(clientMonitor.getTargetUserId());
+ }
};
private IBiometricService mBiometricService;
@@ -263,65 +249,6 @@ public abstract class BiometricServiceBase<T> extends SystemService
}
}
-
-
- private final class LockoutResetMonitor implements IBinder.DeathRecipient {
- private static final long WAKELOCK_TIMEOUT_MS = 2000;
- private final IBiometricServiceLockoutResetCallback mCallback;
- private final PowerManager.WakeLock mWakeLock;
-
- public LockoutResetMonitor(IBiometricServiceLockoutResetCallback callback) {
- mCallback = callback;
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- "lockout reset callback");
- try {
- mCallback.asBinder().linkToDeath(LockoutResetMonitor.this, 0);
- } catch (RemoteException e) {
- Slog.w(getTag(), "caught remote exception in linkToDeath", e);
- }
- }
-
- public void sendLockoutReset() {
- if (mCallback != null) {
- try {
- mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
- mCallback.onLockoutReset(new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- releaseWakelock();
- }
- });
- } catch (DeadObjectException e) {
- Slog.w(getTag(), "Death object while invoking onLockoutReset: ", e);
- mHandler.post(mRemoveCallbackRunnable);
- } catch (RemoteException e) {
- Slog.w(getTag(), "Failed to invoke onLockoutReset: ", e);
- releaseWakelock();
- }
- }
- }
-
- private final Runnable mRemoveCallbackRunnable = new Runnable() {
- @Override
- public void run() {
- releaseWakelock();
- removeLockoutResetCallback(LockoutResetMonitor.this);
- }
- };
-
- @Override
- public void binderDied() {
- Slog.e(getTag(), "Lockout reset callback binder died");
- mHandler.post(mRemoveCallbackRunnable);
- }
-
- private void releaseWakelock() {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- }
- }
-
/**
* Initializes the system service.
* <p>
@@ -341,7 +268,6 @@ public abstract class BiometricServiceBase<T> extends SystemService
mKeyguardPackage = keyguardComponent != null ? keyguardComponent.getPackageName() : null;
mAppOps = context.getSystemService(AppOpsManager.class);
mActivityTaskManager = ActivityTaskManager.getService();
- mPowerManager = mContext.getSystemService(PowerManager.class);
mPerformanceTracker = PerformanceTracker.getInstanceForSensorId(getSensorId());
}
@@ -452,15 +378,7 @@ public abstract class BiometricServiceBase<T> extends SystemService
}
final EnrollClient enrollClient = (EnrollClient) client;
-
- if (enrollClient.onEnrollResult(identifier, remaining)) {
- removeClient(enrollClient);
- // When enrollment finishes, update this group's authenticator id, as the HAL has
- // already generated a new authenticator id when the new biometric is enrolled.
- if (identifier instanceof Fingerprint) {
- updateActiveGroup(((Fingerprint)identifier).getGroupId());
- }
- }
+ enrollClient.onEnrollResult(identifier, remaining);
}
protected void handleError(int error, int vendorCode) {
@@ -630,7 +548,8 @@ public abstract class BiometricServiceBase<T> extends SystemService
});
}
- protected void cleanupInternal(InternalCleanupClient<T> client) {
+ protected void cleanupInternal(
+ InternalCleanupClient<? extends BiometricAuthenticator.Identifier, T> client) {
mHandler.post(() -> {
if (DEBUG) {
Slog.v(getTag(), "Cleaning up templates for user("
@@ -647,19 +566,6 @@ public abstract class BiometricServiceBase<T> extends SystemService
startClient(client, true /* initiatedByClient */);
}
- protected void addLockoutResetCallback(IBiometricServiceLockoutResetCallback callback) {
- if (callback == null) {
- Slog.w(getTag(), "Null LockoutResetCallback");
- return;
- }
- mHandler.post(() -> {
- final LockoutResetMonitor monitor = new LockoutResetMonitor(callback);
- if (!mLockoutMonitors.contains(monitor)) {
- mLockoutMonitors.add(monitor);
- }
- });
- }
-
/**
* Helper methods.
*/
@@ -816,7 +722,7 @@ public abstract class BiometricServiceBase<T> extends SystemService
return;
}
- final T daemon = getDaemon();
+ final T daemon = mCurrentClient.getFreshDaemon();
if (daemon == null) {
Slog.e(getTag(), "Daemon null, unable to start: "
+ mCurrentClient.getClass().getSimpleName());
@@ -825,7 +731,7 @@ public abstract class BiometricServiceBase<T> extends SystemService
return;
}
- mCurrentClient.start(daemon, mClientFinishCallback);
+ mCurrentClient.start(mClientFinishCallback);
notifyClientActiveCallbacks(true);
}
@@ -931,12 +837,6 @@ public abstract class BiometricServiceBase<T> extends SystemService
doTemplateCleanupForUser(userId);
}
- protected void notifyLockoutResetMonitors() {
- for (int i = 0; i < mLockoutMonitors.size(); i++) {
- mLockoutMonitors.get(i).sendLockoutReset();
- }
- }
-
private void listenForUserSwitches() {
try {
ActivityManager.getService().registerUserSwitchObserver(
@@ -951,8 +851,4 @@ public abstract class BiometricServiceBase<T> extends SystemService
Slog.w(getTag(), "Failed to listen for user switching event" ,e);
}
}
-
- private void removeLockoutResetCallback(LockoutResetMonitor monitor) {
- mLockoutMonitors.remove(monitor);
- }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
index 5a2d63d667db..3f301ccb602e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
@@ -47,11 +47,23 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
* implementation.
*
* @param clientMonitor Reference of the ClientMonitor that finished.
+ * @param success True if the operation completed successfully.
*/
- void onClientFinished(ClientMonitor clientMonitor);
+ void onClientFinished(ClientMonitor clientMonitor, boolean success);
+ }
+
+ /**
+ * Interface that allows ClientMonitor subclasses to retrieve a fresh instance to the HAL.
+ */
+ public interface LazyDaemon<T> {
+ /**
+ * @return A fresh instance to the biometric HAL
+ */
+ T getDaemon();
}
@NonNull private final Context mContext;
+ @NonNull protected final LazyDaemon<T> mLazyDaemon;
private final int mTargetUserId;
@NonNull private final String mOwner;
private final int mSensorId; // sensorId as configured by the framework
@@ -63,11 +75,11 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
private final int mCookie;
boolean mAlreadyDone;
- @NonNull protected T mDaemon;
@NonNull protected FinishCallback mFinishCallback;
/**
* @param context system_server context
+ * @param lazyDaemon pointer for lazy retrieval of the HAL
* @param token a unique token for the client
* @param listener recipient of related events (e.g. authentication)
* @param userId target user id for operation
@@ -78,12 +90,13 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
* @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants
* @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants
*/
- public ClientMonitor(@NonNull Context context, @Nullable IBinder token,
- @Nullable ClientMonitorCallbackConverter listener, int userId, @NonNull String owner,
- int cookie, int sensorId, int statsModality, int statsAction,
+ public ClientMonitor(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+ @Nullable IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
+ @NonNull String owner, int cookie, int sensorId, int statsModality, int statsAction,
int statsClient) {
super(statsModality, statsAction, statsClient);
mContext = context;
+ mLazyDaemon = lazyDaemon;
mToken = token;
mListener = listener;
mTargetUserId = userId;
@@ -107,18 +120,16 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
/**
* Invoked if the scheduler is unable to start the ClientMonitor (for example the HAL is null).
* If such a problem is detected, the scheduler will not invoke
- * {@link #start(Object, FinishCallback)}.
+ * {@link #start(FinishCallback)}.
*/
public abstract void unableToStart();
/**
* Starts the ClientMonitor's lifecycle. Invokes {@link #startHalOperation()} when internal book
* keeping is complete.
- * @param daemon reference to the HAL
* @param finishCallback invoked when the operation is complete (succeeds, fails, etc)
*/
- public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
- mDaemon = daemon;
+ public void start(@NonNull FinishCallback finishCallback) {
mFinishCallback = finishCallback;
}
@@ -127,11 +138,6 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
*/
protected abstract void startHalOperation();
- /**
- * Stops the HAL operation specific to the ClientMonitor subclass.
- */
- protected abstract void stopHalOperation();
-
public boolean isAlreadyDone() {
return mAlreadyDone;
}
@@ -190,4 +196,8 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
public final int getSensorId() {
return mSensorId;
}
+
+ public final T getFreshDaemon() {
+ return mLazyDaemon.getDaemon();
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index 6637ede62b80..a3d96778d177 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -41,54 +41,46 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> {
private long mEnrollmentStartTimeMs;
private boolean mAlreadyCancelled;
- public EnrollClient(@NonNull Context context, @NonNull IBinder token,
- @NonNull ClientMonitorCallbackConverter listener, int userId,
+ public EnrollClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
int timeoutSec, int statsModality, int sensorId,
boolean shouldVibrate) {
- super(context, token, listener, userId, owner, 0 /* cookie */, sensorId, statsModality,
- BiometricsProtoEnums.ACTION_ENROLL, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
+ statsModality, BiometricsProtoEnums.ACTION_ENROLL,
+ BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricUtils = utils;
mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length);
mTimeoutSec = timeoutSec;
mShouldVibrate = shouldVibrate;
}
- public boolean onEnrollResult(BiometricAuthenticator.Identifier identifier,
- int remaining) {
- if (remaining == 0) {
- mBiometricUtils.addBiometricForUser(getContext(), getTargetUserId(), identifier);
- logOnEnrolled(getTargetUserId(),
- System.currentTimeMillis() - mEnrollmentStartTimeMs,
- true /* enrollSuccessful */);
- }
- notifyUserActivity();
- return sendEnrollResult(identifier, remaining);
- }
-
- /*
- * @return true if we're done.
- */
- private boolean sendEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) {
+ public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) {
if (mShouldVibrate) {
vibrateSuccess();
}
+ final ClientMonitorCallbackConverter listener = getListener();
try {
- final ClientMonitorCallbackConverter listener = getListener();
if (listener != null) {
listener.onEnrollResult(identifier, remaining);
}
- return remaining == 0;
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to notify EnrollResult:", e);
- return true;
+ Slog.e(TAG, "Remote exception", e);
}
+
+ if (remaining == 0) {
+ mBiometricUtils.addBiometricForUser(getContext(), getTargetUserId(), identifier);
+ logOnEnrolled(getTargetUserId(), System.currentTimeMillis() - mEnrollmentStartTimeMs,
+ true /* enrollSuccessful */);
+ mFinishCallback.onClientFinished(this, true /* success */);
+ }
+ notifyUserActivity();
}
@Override
- public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
- super.start(daemon, finishCallback);
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
mEnrollmentStartTimeMs = System.currentTimeMillis();
startHalOperation();
diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
index 12584cfa7af3..dad5cad1ed8d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
@@ -29,9 +29,10 @@ public abstract class GenerateChallengeClient<T> extends ClientMonitor<T> {
protected long mChallenge;
- public GenerateChallengeClient(Context context, IBinder token,
- ClientMonitorCallbackConverter listener, String owner, int sensorId) {
- super(context, token, listener, 0 /* userId */, owner, 0 /* cookie */, sensorId,
+ public GenerateChallengeClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
+ @NonNull String owner, int sensorId) {
+ super(context, lazyDaemon, token, listener, 0 /* userId */, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN);
}
@@ -46,20 +47,16 @@ public abstract class GenerateChallengeClient<T> extends ClientMonitor<T> {
}
@Override
- public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
- super.start(daemon, finishCallback);
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
startHalOperation();
try {
getListener().onChallengeGenerated(mChallenge);
+ mFinishCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
- mFinishCallback.onClientFinished(this);
- }
-
- @Override
- protected void stopHalOperation() {
- // Not supported for GenerateChallenge
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
index f3ade65d6748..6d7b0fd3d5f1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
@@ -27,6 +27,7 @@ import com.android.internal.util.FrameworkStatsLog;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* Wraps {@link InternalEnumerateClient} and {@link RemovalClient}. Keeps track of all the
@@ -37,8 +38,8 @@ import java.util.List;
* 2) The HAL and Framework are not in sync, and
* {@link #onRemoved(BiometricAuthenticator.Identifier, int)} returns true/
*/
-public abstract class InternalCleanupClient<T> extends ClientMonitor<T>
- implements EnumerateConsumer, RemovalConsumer {
+public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Identifier, T>
+ extends ClientMonitor<T> implements EnumerateConsumer, RemovalConsumer {
private static final String TAG = "Biometrics/InternalCleanupClient";
@@ -57,10 +58,11 @@ public abstract class InternalCleanupClient<T> extends ClientMonitor<T>
private final ArrayList<UserTemplate> mUnknownHALTemplates = new ArrayList<>();
private final BiometricUtils mBiometricUtils;
- private final List<? extends BiometricAuthenticator.Identifier> mEnrolledList;
+ private final Map<Integer, Long> mAuthenticatorIds;
+ private final List<S> mEnrolledList;
private ClientMonitor<T> mCurrentTask;
- private final FinishCallback mEnumerateFinishCallback = clientMonitor -> {
+ private final FinishCallback mEnumerateFinishCallback = (clientMonitor, success) -> {
final List<BiometricAuthenticator.Identifier> unknownHALTemplates =
((InternalEnumerateClient<T>) mCurrentTask).getUnknownHALTemplates();
@@ -75,45 +77,46 @@ public abstract class InternalCleanupClient<T> extends ClientMonitor<T>
if (mUnknownHALTemplates.isEmpty()) {
// No unknown HAL templates. Unknown framework templates are already cleaned up in
// InternalEnumerateClient. Finish this client.
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, success);
} else {
startCleanupUnknownHalTemplates();
}
};
- private final FinishCallback mRemoveFinishCallback = clientMonitor -> {
- mFinishCallback.onClientFinished(this);
+ private final FinishCallback mRemoveFinishCallback = (clientMonitor, success) -> {
+ mFinishCallback.onClientFinished(this, success);
};
- protected abstract InternalEnumerateClient<T> getEnumerateClient(Context context, IBinder token,
- int userId, String owner,
- List<? extends BiometricAuthenticator.Identifier> enrolledList, BiometricUtils utils,
- int sensorId);
+ protected abstract InternalEnumerateClient<T> getEnumerateClient(Context context,
+ LazyDaemon<T> lazyDaemon, IBinder token, int userId, String owner,
+ List<S> enrolledList, BiometricUtils utils, int sensorId);
- protected abstract RemovalClient<T> getRemovalClient(Context context, IBinder token,
- int biometricId, int userId, String owner, BiometricUtils utils, int sensorId);
+ protected abstract RemovalClient<T> getRemovalClient(Context context, LazyDaemon<T> lazyDaemon,
+ IBinder token, int biometricId, int userId, String owner, BiometricUtils utils,
+ int sensorId, Map<Integer, Long> authenticatorIds);
- protected InternalCleanupClient(@NonNull Context context, int userId,
- @NonNull String owner, int sensorId, int statsModality,
- @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
- @NonNull BiometricUtils utils) {
- super(context, null /* token */, null /* ClientMonitorCallbackConverter */,
+ protected InternalCleanupClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+ int userId, @NonNull String owner, int sensorId, int statsModality,
+ @NonNull List<S> enrolledList, @NonNull BiometricUtils utils,
+ @NonNull Map<Integer, Long> authenticatorIds) {
+ super(context, lazyDaemon, null /* token */, null /* ClientMonitorCallbackConverter */,
userId, owner, 0 /* cookie */, sensorId, statsModality,
BiometricsProtoEnums.ACTION_ENUMERATE, BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricUtils = utils;
+ mAuthenticatorIds = authenticatorIds;
mEnrolledList = enrolledList;
}
private void startCleanupUnknownHalTemplates() {
UserTemplate template = mUnknownHALTemplates.get(0);
mUnknownHALTemplates.remove(template);
- mCurrentTask = getRemovalClient(getContext(), getToken(),
+ mCurrentTask = getRemovalClient(getContext(), mLazyDaemon, getToken(),
template.mIdentifier.getBiometricId(), template.mUserId,
- getContext().getPackageName(), mBiometricUtils, getSensorId());
+ getContext().getPackageName(), mBiometricUtils, getSensorId(), mAuthenticatorIds);
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
mStatsModality,
BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
- mCurrentTask.start(mDaemon, mRemoveFinishCallback);
+ mCurrentTask.start(mRemoveFinishCallback);
}
@Override
@@ -122,13 +125,13 @@ public abstract class InternalCleanupClient<T> extends ClientMonitor<T>
}
@Override
- public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
- super.start(daemon, finishCallback);
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
// Start enumeration. Removal will start if necessary, when enumeration is completed.
- mCurrentTask = getEnumerateClient(getContext(), getToken(), getTargetUserId(),
+ mCurrentTask = getEnumerateClient(getContext(), mLazyDaemon, getToken(), getTargetUserId(),
getOwnerString(), mEnrolledList, mBiometricUtils, getSensorId());
- mCurrentTask.start(daemon, mEnumerateFinishCallback);
+ mCurrentTask.start(mEnumerateFinishCallback);
}
@Override
@@ -138,11 +141,6 @@ public abstract class InternalCleanupClient<T> extends ClientMonitor<T>
}
@Override
- protected void stopHalOperation() {
- // Internal cleanup's cannot be stopped.
- }
-
- @Override
public void onRemoved(BiometricAuthenticator.Identifier identifier, int remaining) {
if (!(mCurrentTask instanceof RemovalClient)) {
Slog.e(TAG, "onRemoved received during client: "
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
index 9ce271c656c8..3f73cd56e6c3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
@@ -43,13 +43,13 @@ public abstract class InternalEnumerateClient<T> extends ClientMonitor<T>
// List of templates to remove from the HAL
private List<BiometricAuthenticator.Identifier> mUnknownHALTemplates = new ArrayList<>();
- protected InternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId,
- @NonNull String owner,
+ protected InternalEnumerateClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+ @NonNull IBinder token, int userId, @NonNull String owner,
@NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
@NonNull BiometricUtils utils, int sensorId, int statsModality) {
// Internal enumerate does not need to send results to anyone. Cleanup (enumerate + remove)
// is all done internally.
- super(context, token, null /* ClientMonitorCallbackConverter */, userId, owner,
+ super(context, lazyDaemon, token, null /* ClientMonitorCallbackConverter */, userId, owner,
0 /* cookie */, sensorId, statsModality, BiometricsProtoEnums.ACTION_ENUMERATE,
BiometricsProtoEnums.CLIENT_UNKNOWN);
mEnrolledList = enrolledList;
@@ -62,7 +62,7 @@ public abstract class InternalEnumerateClient<T> extends ClientMonitor<T>
handleEnumeratedTemplate(identifier);
if (remaining == 0) {
doTemplateCleanup();
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, true /* success */);
}
}
@@ -72,8 +72,8 @@ public abstract class InternalEnumerateClient<T> extends ClientMonitor<T>
}
@Override
- public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
- super.start(daemon, finishCallback);
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
// The biometric template ids will be removed when we get confirmation from the HAL
startHalOperation();
diff --git a/services/core/java/com/android/server/biometrics/sensors/LockoutResetTracker.java b/services/core/java/com/android/server/biometrics/sensors/LockoutResetTracker.java
new file mode 100644
index 000000000000..9bb5c6e77332
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/LockoutResetTracker.java
@@ -0,0 +1,122 @@
+/*
+ * 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.biometrics.sensors;
+
+import android.content.Context;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.ArrayList;
+
+/**
+ * Allows clients (such as keyguard) to register for notifications on when biometric lockout
+ * ends.
+ */
+public class LockoutResetTracker implements IBinder.DeathRecipient {
+
+ private static final String TAG = "LockoutResetTracker";
+
+ private final Context mContext;
+ private final ArrayList<ClientCallback> mClientCallbacks;
+
+ private static class ClientCallback {
+ private static final long WAKELOCK_TIMEOUT_MS = 2000;
+
+ private final String mOpPackageName;
+ private final IBiometricServiceLockoutResetCallback mCallback;
+ private final PowerManager.WakeLock mWakeLock;
+
+ ClientCallback(Context context, IBiometricServiceLockoutResetCallback callback,
+ String opPackageName) {
+ final PowerManager pm = context.getSystemService(PowerManager.class);
+ mOpPackageName = opPackageName;
+ mCallback = callback;
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "LockoutResetMonitor:SendLockoutReset");
+ }
+
+ void sendLockoutReset() {
+ if (mCallback != null) {
+ try {
+ mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
+ mCallback.onLockoutReset(new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) {
+ releaseWakelock();
+ }
+ });
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
+ releaseWakelock();
+ }
+ }
+ }
+
+ private void releaseWakelock() {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ }
+ }
+
+ public LockoutResetTracker(Context context) {
+ mContext = context;
+ mClientCallbacks = new ArrayList<>();
+ }
+
+ public void addCallback(IBiometricServiceLockoutResetCallback callback, String opPackageName) {
+ if (callback == null) {
+ Slog.w(TAG, "Callback from : " + opPackageName + " is null");
+ return;
+ }
+
+ mClientCallbacks.add(new ClientCallback(mContext, callback, opPackageName));
+ try {
+ callback.asBinder().linkToDeath(this, 0 /* flags */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to link to death", e);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ // Do nothing, handled below
+ }
+
+ @Override
+ public void binderDied(IBinder who) {
+ Slog.e(TAG, "Callback binder died: " + who);
+ for (ClientCallback callback : mClientCallbacks) {
+ if (callback.mCallback.asBinder().equals(who)) {
+ Slog.e(TAG, "Removing dead callback for: " + callback.mOpPackageName);
+ callback.releaseWakelock();
+ mClientCallbacks.remove(callback);
+ }
+ }
+ }
+
+ public void notifyLockoutResetCallbacks() {
+ for (ClientCallback callback : mClientCallbacks) {
+ callback.sendLockoutReset();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
index b734516322e4..1c49bcdbadf4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
@@ -24,6 +24,8 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import java.util.Map;
+
/**
* A class to keep track of the remove state for a given client.
*/
@@ -33,14 +35,18 @@ public abstract class RemovalClient<T> extends ClientMonitor<T> implements Remov
protected final int mBiometricId;
private final BiometricUtils mBiometricUtils;
+ private final Map<Integer, Long> mAuthenticatorIds;
- public RemovalClient(@NonNull Context context, @NonNull IBinder token,
- @NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId,
- @NonNull String owner, @NonNull BiometricUtils utils, int sensorId, int statsModality) {
- super(context, token, listener, userId, owner, 0 /* cookie */, sensorId, statsModality,
- BiometricsProtoEnums.ACTION_REMOVE, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ public RemovalClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
+ int biometricId, int userId, @NonNull String owner, @NonNull BiometricUtils utils,
+ int sensorId, @NonNull Map<Integer, Long> authenticatorIds, int statsModality) {
+ super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
+ statsModality, BiometricsProtoEnums.ACTION_REMOVE,
+ BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricId = biometricId;
mBiometricUtils = utils;
+ mAuthenticatorIds = authenticatorIds;
}
@Override
@@ -49,8 +55,8 @@ public abstract class RemovalClient<T> extends ClientMonitor<T> implements Remov
}
@Override
- public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
- super.start(daemon, finishCallback);
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
// The biometric template ids will be removed when we get confirmation from the HAL
startHalOperation();
@@ -72,7 +78,14 @@ public abstract class RemovalClient<T> extends ClientMonitor<T> implements Remov
}
if (remaining == 0) {
- mFinishCallback.onClientFinished(this);
+ if (mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty()) {
+ Slog.d(TAG, "Last biometric removed for user: " + getTargetUserId());
+ // When the last biometric of a group is removed, update the authenticator id.
+ // Note that multiple ClientMonitors may be cause onRemoved (e.g. internal
+ // cleanup).
+ mAuthenticatorIds.put(getTargetUserId(), 0L);
+ }
+ mFinishCallback.onClientFinished(this, true /* success */);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
index e00396b054e6..b78ee49826f2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
@@ -23,10 +23,11 @@ import android.os.IBinder;
public abstract class RevokeChallengeClient<T> extends ClientMonitor<T> {
- public RevokeChallengeClient(Context context, IBinder token, String owner, int sensorId) {
- super(context, token, null /* listener */, 0 /* userId */, owner, 0 /* cookie */, sensorId,
- BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
- BiometricsProtoEnums.CLIENT_UNKNOWN);
+ public RevokeChallengeClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+ @NonNull IBinder token, @NonNull String owner, int sensorId) {
+ super(context, lazyDaemon, token, null /* listener */, 0 /* userId */, owner,
+ 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
}
@Override
@@ -35,15 +36,10 @@ public abstract class RevokeChallengeClient<T> extends ClientMonitor<T> {
}
@Override
- public void start(@NonNull T daemon, @NonNull FinishCallback finishCallback) {
- super.start(daemon, finishCallback);
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
startHalOperation();
- mFinishCallback.onClientFinished(this);
- }
-
- @Override
- protected void stopHalOperation() {
- // Not supported for RevokeChallenge
+ mFinishCallback.onClientFinished(this, true /* success */);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java
index a54357e922d2..118cadc9f9fa 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java
@@ -62,13 +62,14 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
private int mLastAcquire;
- FaceAuthenticationClient(@NonNull Context context, @NonNull IBinder token,
+ FaceAuthenticationClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient,
@NonNull TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker, @NonNull UsageStats usageStats) {
- super(context, token, listener, targetUserId, operationId, restricted,
+ super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FACE, statsClient, taskStackListener,
lockoutTracker);
@@ -89,22 +90,22 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
@Override
protected void startHalOperation() {
try {
- mDaemon.authenticate(mOperationId);
+ getFreshDaemon().authenticate(mOperationId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting auth", e);
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
@Override
protected void stopHalOperation() {
try {
- mDaemon.cancel();
+ getFreshDaemon().cancel();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting cancel", e);
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
@@ -132,7 +133,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
// 1) Authenticated == true
// 2) Error occurred
// 3) Authenticated == false
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, true /* success */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java
index b63b39e3cf6c..4f9f46aff4c0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java
@@ -51,13 +51,14 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
@NonNull private final int[] mEnrollIgnoreList;
@NonNull private final int[] mEnrollIgnoreListVendor;
- FaceEnrollClient(@NonNull Context context, @NonNull IBinder token,
- @NonNull ClientMonitorCallbackConverter listener, int userId,
+ FaceEnrollClient(@NonNull Context context, @NonNull LazyDaemon<IBiometricsFace> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
@NonNull int[] disabledFeatures, int timeoutSec, @Nullable NativeHandle surfaceHandle,
int sensorId) {
- super(context, token, listener, userId, hardwareAuthToken, owner, utils, timeoutSec,
- BiometricsProtoEnums.MODALITY_FACE, sensorId, false /* shouldVibrate */);
+ super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
+ timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId,
+ false /* shouldVibrate */);
mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
mSurfaceHandle = surfaceHandle;
mEnrollIgnoreList = getContext().getResources()
@@ -89,36 +90,36 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
}
android.hardware.biometrics.face.V1_1.IBiometricsFace daemon11 =
- android.hardware.biometrics.face.V1_1.IBiometricsFace.castFrom(mDaemon);
+ android.hardware.biometrics.face.V1_1.IBiometricsFace.castFrom(getFreshDaemon());
try {
final int status;
if (daemon11 != null) {
status = daemon11.enroll_1_1(token, mTimeoutSec, disabledFeatures, mSurfaceHandle);
} else if (mSurfaceHandle == null) {
- status = mDaemon.enroll(token, mTimeoutSec, disabledFeatures);
+ status = getFreshDaemon().enroll(token, mTimeoutSec, disabledFeatures);
} else {
Slog.e(TAG, "enroll(): surface is only supported in @1.1 HAL");
status = BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS;
}
if (status != Status.OK) {
onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enroll", e);
onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
@Override
protected void stopHalOperation() {
try {
- mDaemon.cancel();
+ getFreshDaemon().cancel();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting cancel", e);
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
index 72188a516d65..67f2712d0b9d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
@@ -36,15 +36,16 @@ public class FaceGenerateChallengeClient extends GenerateChallengeClient<IBiomet
private static final String TAG = "FaceGenerateChallengeClient";
private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
- FaceGenerateChallengeClient(@NonNull Context context, @NonNull IBinder token,
+ FaceGenerateChallengeClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId) {
- super(context, token, listener, owner, sensorId);
+ super(context, lazyDaemon, token, listener, owner, sensorId);
}
@Override
protected void startHalOperation() {
try {
- mChallenge = mDaemon.generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
+ mChallenge = getFreshDaemon().generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
} catch (RemoteException e) {
Slog.e(TAG, "generateChallenge failed", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java
index 227d817e31ff..ce57cb7686ed 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java
@@ -40,10 +40,10 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> {
private final int mFeature;
private final int mFaceId;
- FaceGetFeatureClient(@NonNull Context context, @NonNull IBinder token,
- @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner,
- int sensorId, int feature, int faceId) {
- super(context, token, listener, userId, owner, 0 /* cookie */, sensorId,
+ FaceGetFeatureClient(@NonNull Context context, @NonNull LazyDaemon<IBiometricsFace> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
+ @NonNull String owner, int sensorId, int feature, int faceId) {
+ super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN);
mFeature = feature;
@@ -61,24 +61,20 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> {
}
@Override
- public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) {
- super.start(daemon, finishCallback);
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
startHalOperation();
}
@Override
protected void startHalOperation() {
try {
- final OptionalBool result = mDaemon.getFeature(mFeature, mFaceId);
+ final OptionalBool result = getFreshDaemon().getFeature(mFeature, mFaceId);
getListener().onFeatureGet(result.status == Status.OK, mFeature, result.value);
+ mFinishCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to getFeature", e);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
- mFinishCallback.onClientFinished(this);
- }
-
- @Override
- protected void stopHalOperation() {
- // Not supported for GetFeature
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java
index 388baa226dee..93f35f4c90cd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java
@@ -18,9 +18,9 @@ package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
+import android.hardware.face.Face;
import android.os.IBinder;
import com.android.server.biometrics.sensors.BiometricUtils;
@@ -29,36 +29,40 @@ import com.android.server.biometrics.sensors.InternalEnumerateClient;
import com.android.server.biometrics.sensors.RemovalClient;
import java.util.List;
+import java.util.Map;
/**
* Face-specific internal cleanup client supporting the
* {@link android.hardware.biometrics.face.V1_0} and {@link android.hardware.biometrics.face.V1_1}
* HIDL interfaces.
*/
-class FaceInternalCleanupClient extends InternalCleanupClient<IBiometricsFace> {
+class FaceInternalCleanupClient extends InternalCleanupClient<Face, IBiometricsFace> {
- FaceInternalCleanupClient(@NonNull Context context, int userId, @NonNull String owner,
- int sensorId, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
- @NonNull BiometricUtils utils) {
- super(context, userId, owner, sensorId, BiometricsProtoEnums.MODALITY_FACE, enrolledList,
- utils);
+ FaceInternalCleanupClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, int userId, @NonNull String owner,
+ int sensorId, @NonNull List<Face> enrolledList, @NonNull BiometricUtils utils,
+ @NonNull Map<Integer, Long> authenticatorIds) {
+ super(context, lazyDaemon, userId, owner, sensorId, BiometricsProtoEnums.MODALITY_FACE,
+ enrolledList, utils, authenticatorIds);
}
@Override
protected InternalEnumerateClient<IBiometricsFace> getEnumerateClient(Context context,
- IBinder token, int userId, String owner,
- List<? extends BiometricAuthenticator.Identifier> enrolledList,
- BiometricUtils utils, int sensorId) {
- return new FaceInternalEnumerateClient(context, token, userId, owner, enrolledList, utils,
- sensorId);
+ LazyDaemon<IBiometricsFace> lazyDaemon, IBinder token, int userId, String owner,
+ List<Face> enrolledList, BiometricUtils utils, int sensorId) {
+ return new FaceInternalEnumerateClient(context, lazyDaemon, token, userId, owner,
+ enrolledList, utils, sensorId);
}
@Override
- protected RemovalClient<IBiometricsFace> getRemovalClient(Context context, IBinder token,
- int biometricId, int userId, String owner, BiometricUtils utils, int sensorId) {
+ protected RemovalClient<IBiometricsFace> getRemovalClient(Context context,
+ LazyDaemon<IBiometricsFace> lazyDaemon, IBinder token,
+ int biometricId, int userId, String owner, BiometricUtils utils, int sensorId,
+ Map<Integer, Long> authenticatorIds) {
// Internal remove does not need to send results to anyone. Cleanup (enumerate + remove)
// is all done internally.
- return new FaceRemovalClient(context, token, null /* ClientMonitorCallbackConverter */,
- biometricId, userId, owner, utils, sensorId);
+ return new FaceRemovalClient(context, lazyDaemon, token,
+ null /* ClientMonitorCallbackConverter */, biometricId, userId, owner, utils,
+ sensorId, authenticatorIds);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java
index c6749c5713d9..f25242ee9b85 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java
@@ -18,9 +18,9 @@ package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
+import android.hardware.face.Face;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -38,31 +38,21 @@ import java.util.List;
class FaceInternalEnumerateClient extends InternalEnumerateClient<IBiometricsFace> {
private static final String TAG = "FaceInternalEnumerateClient";
- FaceInternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId,
- @NonNull String owner,
- @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
- @NonNull BiometricUtils utils, int sensorId) {
- super(context, token, userId, owner, enrolledList, utils, sensorId,
+ FaceInternalEnumerateClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token, int userId,
+ @NonNull String owner, @NonNull List<Face> enrolledList, @NonNull BiometricUtils utils,
+ int sensorId) {
+ super(context, lazyDaemon, token, userId, owner, enrolledList, utils, sensorId,
BiometricsProtoEnums.MODALITY_FACE);
}
@Override
protected void startHalOperation() {
try {
- mDaemon.enumerate();
+ getFreshDaemon().enumerate();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enumerate", e);
- mFinishCallback.onClientFinished(this);
- }
- }
-
- @Override
- protected void stopHalOperation() {
- try {
- mDaemon.cancel();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when requesting cancel", e);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java
index b0ee9810a49b..00d5f500b241 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java
@@ -28,6 +28,8 @@ import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.RemovalClient;
+import java.util.Map;
+
/**
* Face-specific removal client supporting the {@link android.hardware.biometrics.face.V1_0}
* and {@link android.hardware.biometrics.face.V1_1} HIDL interfaces.
@@ -35,30 +37,21 @@ import com.android.server.biometrics.sensors.RemovalClient;
class FaceRemovalClient extends RemovalClient<IBiometricsFace> {
private static final String TAG = "FaceRemovalClient";
- FaceRemovalClient(@NonNull Context context, @NonNull IBinder token,
- @NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId,
- @NonNull String owner, @NonNull BiometricUtils utils, int sensorId) {
- super(context, token, listener, biometricId, userId, owner, utils, sensorId,
- BiometricsProtoEnums.MODALITY_FACE);
+ FaceRemovalClient(@NonNull Context context, @NonNull LazyDaemon<IBiometricsFace> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
+ int biometricId, int userId, @NonNull String owner, @NonNull BiometricUtils utils,
+ int sensorId, @NonNull Map<Integer, Long> authenticatorIds) {
+ super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId,
+ authenticatorIds, BiometricsProtoEnums.MODALITY_FACE);
}
@Override
protected void startHalOperation() {
try {
- mDaemon.remove(mBiometricId);
+ getFreshDaemon().remove(mBiometricId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting remove", e);
- mFinishCallback.onClientFinished(this);
- }
- }
-
- @Override
- protected void stopHalOperation() {
- try {
- mDaemon.cancel();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when requesting cancel", e);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java
index 441cb14f6600..69070da0491e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java
@@ -37,10 +37,11 @@ public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> {
private final ArrayList<Byte> mHardwareAuthToken;
- FaceResetLockoutClient(@NonNull Context context, int userId, String owner, int sensorId,
- byte[] hardwareAuthToken) {
- super(context, null /* token */, null /* listener */, userId, owner, 0 /* cookie */,
- sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
+ FaceResetLockoutClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, int userId, String owner, int sensorId,
+ @NonNull byte[] hardwareAuthToken) {
+ super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
+ 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
mHardwareAuthToken = new ArrayList<>();
@@ -55,24 +56,19 @@ public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> {
}
@Override
- public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) {
- super.start(daemon, finishCallback);
-
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
startHalOperation();
}
@Override
protected void startHalOperation() {
try {
- mDaemon.resetLockout(mHardwareAuthToken);
+ getFreshDaemon().resetLockout(mHardwareAuthToken);
+ mFinishCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to reset lockout", e);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
- mFinishCallback.onClientFinished(this);
- }
-
- @Override
- protected void stopHalOperation() {
- // Not supported for resetLockout
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java
index 992a678d8205..a10c573f34fc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java
@@ -33,15 +33,16 @@ public class FaceRevokeChallengeClient extends RevokeChallengeClient<IBiometrics
private static final String TAG = "FaceRevokeChallengeClient";
- FaceRevokeChallengeClient(@NonNull Context context, @NonNull IBinder token,
+ FaceRevokeChallengeClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token,
@NonNull String owner, int sensorId) {
- super(context, token, owner, sensorId);
+ super(context, lazyDaemon, token, owner, sensorId);
}
@Override
protected void startHalOperation() {
try {
- mDaemon.revokeChallenge();
+ getFreshDaemon().revokeChallenge();
} catch (RemoteException e) {
Slog.e(TAG, "revokeChallenge failed", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 050fba28043e..a7f82202ca3e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -25,7 +25,6 @@ import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.UserInfo;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -60,6 +59,7 @@ import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.EnrollClient;
import com.android.server.biometrics.sensors.GenerateChallengeClient;
+import com.android.server.biometrics.sensors.LockoutResetTracker;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.RemovalClient;
@@ -97,6 +97,9 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
static final String NOTIFICATION_TAG = "FaceService";
static final int NOTIFICATION_ID = 1;
+ private final LockoutResetTracker mLockoutResetTracker;
+ private final ClientMonitor.LazyDaemon<IBiometricsFace> mLazyDaemon;
+
/**
* Receives the incoming binder calls from FaceManager.
*/
@@ -113,7 +116,7 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
checkPermission(MANAGE_BIOMETRIC);
final GenerateChallengeClient client = new FaceGenerateChallengeClient(getContext(),
- token, new ClientMonitorCallbackConverter(receiver), opPackageName,
+ mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), opPackageName,
getSensorId());
generateChallengeInternal(client);
}
@@ -122,8 +125,8 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
public void revokeChallenge(IBinder token, String owner) {
checkPermission(MANAGE_BIOMETRIC);
- final RevokeChallengeClient client = new FaceRevokeChallengeClient(getContext(), token,
- owner, getSensorId());
+ final RevokeChallengeClient client = new FaceRevokeChallengeClient(getContext(),
+ mLazyDaemon, token, owner, getSensorId());
// TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks.
if (getCurrentClient() == null) {
@@ -149,7 +152,7 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
UserHandle.CURRENT);
});
- final EnrollClient client = new FaceEnrollClient(getContext(), token,
+ final EnrollClient client = new FaceEnrollClient(getContext(), mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, getBiometricUtils(), disabledFeatures, ENROLL_TIMEOUT_SEC,
convertSurfaceToNativeHandle(surface), getSensorId());
@@ -180,11 +183,11 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
final boolean restricted = isRestricted();
final int statsClient = isKeyguard(opPackageName) ? BiometricsProtoEnums.CLIENT_KEYGUARD
: BiometricsProtoEnums.CLIENT_UNKNOWN;
- final AuthenticationClient client = new FaceAuthenticationClient(getContext(), token,
- new ClientMonitorCallbackConverter(receiver), userId, opId, restricted,
- opPackageName, 0 /* cookie */, false /* requireConfirmation */, getSensorId(),
- isStrongBiometric(), statsClient, mTaskStackListener, mLockoutTracker,
- mUsageStats);
+ final AuthenticationClient client = new FaceAuthenticationClient(getContext(),
+ mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId, opId,
+ restricted, opPackageName, 0 /* cookie */, false /* requireConfirmation */,
+ getSensorId(), isStrongBiometric(), statsClient, mTaskStackListener,
+ mLockoutTracker, mUsageStats);
authenticateInternal(client, opPackageName);
}
@@ -197,11 +200,11 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
updateActiveGroup(userId);
final boolean restricted = true; // BiometricPrompt is always restricted
- final AuthenticationClient client = new FaceAuthenticationClient(getContext(), token,
- new ClientMonitorCallbackConverter(sensorReceiver), userId, opId, restricted,
- opPackageName, cookie, requireConfirmation, getSensorId(), isStrongBiometric(),
- BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, mTaskStackListener,
- mLockoutTracker, mUsageStats);
+ final AuthenticationClient client = new FaceAuthenticationClient(getContext(),
+ mLazyDaemon, token, new ClientMonitorCallbackConverter(sensorReceiver), userId,
+ opId, restricted, opPackageName, cookie, requireConfirmation, getSensorId(),
+ isStrongBiometric(), BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+ mTaskStackListener, mLockoutTracker, mUsageStats);
authenticateInternal(client, opPackageName, callingUid, callingPid,
callingUserId);
}
@@ -238,16 +241,19 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
return;
}
- final RemovalClient client = new FaceRemovalClient(getContext(), token,
+ final RemovalClient client = new FaceRemovalClient(getContext(), mLazyDaemon, token,
new ClientMonitorCallbackConverter(receiver), faceId, userId, opPackageName,
- getBiometricUtils(), getSensorId());
+ getBiometricUtils(), getSensorId(), mAuthenticatorIds);
removeInternal(client);
}
@Override
- public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback) {
+ public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback,
+ final String opPackageName) {
checkPermission(USE_BIOMETRIC_INTERNAL);
- FaceService.super.addLockoutResetCallback(callback);
+ mHandler.post(() -> {
+ mLockoutResetTracker.addCallback(callback, opPackageName);
+ });
}
@Override // Binder call
@@ -340,7 +346,8 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
updateActiveGroup(userId);
final FaceResetLockoutClient client = new FaceResetLockoutClient(getContext(),
- userId, getContext().getOpPackageName(), getSensorId(), hardwareAuthToken);
+ mLazyDaemon, userId, getContext().getOpPackageName(), getSensorId(),
+ hardwareAuthToken);
startClient(client, true /* initiatedByClient */);
});
}
@@ -364,8 +371,8 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
final int faceId = getFirstTemplateForUser(mCurrentUserId);
final FaceSetFeatureClient client = new FaceSetFeatureClient(getContext(),
- token, new ClientMonitorCallbackConverter(receiver), userId, opPackageName,
- getSensorId(), feature, enabled, hardwareAuthToken, faceId);
+ mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
+ opPackageName, getSensorId(), feature, enabled, hardwareAuthToken, faceId);
startClient(client, true /* initiatedByClient */);
});
@@ -391,9 +398,9 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
// TODO: Support multiple faces
final int faceId = getFirstTemplateForUser(mCurrentUserId);
- final FaceGetFeatureClient client = new FaceGetFeatureClient(getContext(), token,
- new ClientMonitorCallbackConverter(receiver), userId, opPackageName,
- getSensorId(), feature, faceId);
+ final FaceGetFeatureClient client = new FaceGetFeatureClient(getContext(),
+ mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
+ opPackageName, getSensorId(), feature, faceId);
startClient(client, true /* initiatedByClient */);
});
@@ -539,7 +546,7 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
mHandler.post(() -> {
if (duration == 0) {
- notifyLockoutResetMonitors();
+ mLockoutResetTracker.notifyLockoutResetCallbacks();
}
});
}
@@ -547,6 +554,8 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
public FaceService(Context context) {
super(context);
+ mLazyDaemon = FaceService.this::getFaceDaemon;
+ mLockoutResetTracker = new LockoutResetTracker(context);
mLockoutTracker = new LockoutHalImpl();
mUsageStats = new UsageStats(context);
mNotificationManager = getContext().getSystemService(NotificationManager.class);
@@ -673,7 +682,7 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
@Override
protected List<Face> getEnrolledTemplates(int userId) {
- return getBiometricUtils().getBiometricsForUser(getContext(), userId);
+ return FaceUtils.getInstance().getBiometricsForUser(getContext(), userId);
}
@Override
@@ -693,10 +702,10 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
@Override
protected void doTemplateCleanupForUser(int userId) {
- final List<? extends BiometricAuthenticator.Identifier> enrolledList =
- getEnrolledTemplates(userId);
- final FaceInternalCleanupClient client = new FaceInternalCleanupClient(getContext(), userId,
- getContext().getOpPackageName(), getSensorId(), enrolledList, getBiometricUtils());
+ final List<Face> enrolledList = getEnrolledTemplates(userId);
+ final FaceInternalCleanupClient client = new FaceInternalCleanupClient(getContext(),
+ mLazyDaemon, userId, getContext().getOpPackageName(), getSensorId(), enrolledList,
+ getBiometricUtils(), mAuthenticatorIds);
cleanupInternal(client);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java
index 91f63e185ff8..e7d041a11ccb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java
@@ -43,11 +43,11 @@ public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> {
private final ArrayList<Byte> mHardwareAuthToken;
private final int mFaceId;
- FaceSetFeatureClient(@NonNull Context context, @NonNull IBinder token,
- @NonNull ClientMonitorCallbackConverter listener, int userId,
+ FaceSetFeatureClient(@NonNull Context context, @NonNull LazyDaemon<IBiometricsFace> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int sensorId, int feature, boolean enabled,
byte[] hardwareAuthToken, int faceId) {
- super(context, token, listener, userId, owner, 0 /* cookie */, sensorId,
+ super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN);
mFeature = feature;
@@ -70,25 +70,22 @@ public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> {
}
@Override
- public void start(@NonNull IBiometricsFace daemon, @NonNull FinishCallback finishCallback) {
- super.start(daemon, finishCallback);
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
startHalOperation();
- mFinishCallback.onClientFinished(this);
}
@Override
protected void startHalOperation() {
try {
- final int result = mDaemon.setFeature(mFeature, mEnabled, mHardwareAuthToken, mFaceId);
+ final int result = getFreshDaemon()
+ .setFeature(mFeature, mEnabled, mHardwareAuthToken, mFaceId);
getListener().onFeatureSet(result == Status.OK, mFeature);
+ mFinishCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to set feature: " + mFeature + " to enabled: " + mEnabled, e);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
-
- @Override
- protected void stopHalOperation() {
- // Not supported for SetFeature
- }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java
index ba89d51b1f61..b01b8564466b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java
@@ -47,13 +47,14 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
private final LockoutFrameworkImpl mLockoutFrameworkImpl;
- FingerprintAuthenticationClient(@NonNull Context context, @NonNull IBinder token,
+ FingerprintAuthenticationClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
int sensorId, boolean isStrongBiometric, @Nullable Surface surface, int statsClient,
@NonNull TaskStackListener taskStackListener,
@NonNull LockoutFrameworkImpl lockoutTracker) {
- super(context, token, listener, targetUserId, operationId, restricted,
+ super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
lockoutTracker);
@@ -72,7 +73,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
if (authenticated) {
resetFailedAttempts(getTargetUserId());
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, true /* success */);
} else {
final @LockoutTracker.LockoutMode int lockoutMode =
mLockoutFrameworkImpl.getLockoutModeForUser(getTargetUserId());
@@ -83,7 +84,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
? BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
: BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
onError(errorCode, 0 /* vendorCode */);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, true /* success */);
}
}
}
@@ -102,24 +103,24 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
protected void startHalOperation() {
try {
// GroupId was never used. In fact, groupId is always the same as userId.
- mDaemon.authenticate(mOperationId, getTargetUserId());
+ getFreshDaemon().authenticate(mOperationId, getTargetUserId());
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting auth", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
@Override
protected void stopHalOperation() {
try {
- mDaemon.cancel();
+ getFreshDaemon().cancel();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting cancel", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java
index 34681c38808b..1d56882c0fd2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java
@@ -38,36 +38,38 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
private static final String TAG = "FingerprintEnrollClient";
- FingerprintEnrollClient(@NonNull Context context, @NonNull IBinder token,
+ FingerprintEnrollClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
int timeoutSec, int sensorId) {
- super(context, token, listener, userId, hardwareAuthToken, owner, utils, timeoutSec,
- BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId, true /* shouldVibrate */);
+ super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
+ timeoutSec, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
+ true /* shouldVibrate */);
}
@Override
protected void startHalOperation() {
try {
// GroupId was never used. In fact, groupId is always the same as userId.
- mDaemon.enroll(mHardwareAuthToken, getTargetUserId(), mTimeoutSec);
+ getFreshDaemon().enroll(mHardwareAuthToken, getTargetUserId(), mTimeoutSec);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enroll", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
@Override
protected void stopHalOperation() {
try {
- mDaemon.cancel();
+ getFreshDaemon().cancel();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting cancel", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java
index 2fa433305070..8fb8c992268d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java
@@ -36,15 +36,16 @@ public class FingerprintGenerateChallengeClient
private static final String TAG = "FingerprintGenerateChallengeClient";
- FingerprintGenerateChallengeClient(@NonNull Context context, @NonNull IBinder token,
+ FingerprintGenerateChallengeClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId) {
- super(context, token, listener, owner, sensorId);
+ super(context, lazyDaemon, token, listener, owner, sensorId);
}
@Override
protected void startHalOperation() {
try {
- mChallenge = mDaemon.preEnroll();
+ mChallenge = getFreshDaemon().preEnroll();
} catch (RemoteException e) {
Slog.e(TAG, "preEnroll failed", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java
index 71e76703b9d5..1d72c2e0a2ca 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.fingerprint.Fingerprint;
import android.os.IBinder;
import com.android.server.biometrics.sensors.BiometricUtils;
@@ -29,37 +30,43 @@ import com.android.server.biometrics.sensors.InternalEnumerateClient;
import com.android.server.biometrics.sensors.RemovalClient;
import java.util.List;
+import java.util.Map;
/**
* Fingerprint-specific internal cleanup client supporting the
* {@link android.hardware.biometrics.fingerprint.V2_1} and
* {@link android.hardware.biometrics.fingerprint.V2_2} HIDL interfaces.
*/
-class FingerprintInternalCleanupClient extends InternalCleanupClient<IBiometricsFingerprint> {
+class FingerprintInternalCleanupClient
+ extends InternalCleanupClient<Fingerprint, IBiometricsFingerprint> {
- FingerprintInternalCleanupClient(@NonNull Context context,int userId, @NonNull String owner,
- int sensorId, @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
- @NonNull BiometricUtils utils) {
- super(context, userId, owner, sensorId, BiometricsProtoEnums.MODALITY_FINGERPRINT,
- enrolledList, utils);
+ FingerprintInternalCleanupClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, int userId,
+ @NonNull String owner, int sensorId, @NonNull List<Fingerprint> enrolledList,
+ @NonNull BiometricUtils utils, @NonNull Map<Integer, Long> authenticatorIds) {
+ super(context, lazyDaemon, userId, owner, sensorId,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT, enrolledList, utils, authenticatorIds);
}
@Override
protected InternalEnumerateClient<IBiometricsFingerprint> getEnumerateClient(
- Context context, IBinder token, int userId, String owner,
- List<? extends BiometricAuthenticator.Identifier> enrolledList, BiometricUtils utils,
+ Context context, LazyDaemon<IBiometricsFingerprint> lazyDaemon, IBinder token,
+ int userId, String owner,
+ List<Fingerprint> enrolledList, BiometricUtils utils,
int sensorId) {
- return new FingerprintInternalEnumerateClient(context, token, userId, owner, enrolledList,
- utils, sensorId);
+ return new FingerprintInternalEnumerateClient(context, lazyDaemon, token, userId, owner,
+ enrolledList, utils, sensorId);
}
@Override
- protected RemovalClient<IBiometricsFingerprint> getRemovalClient(Context context, IBinder token,
- int biometricId, int userId, String owner, BiometricUtils utils, int sensorId) {
+ protected RemovalClient<IBiometricsFingerprint> getRemovalClient(Context context,
+ LazyDaemon<IBiometricsFingerprint> lazyDaemon, IBinder token,
+ int biometricId, int userId, String owner, BiometricUtils utils, int sensorId,
+ Map<Integer, Long> authenticatorIds) {
// Internal remove does not need to send results to anyone. Cleanup (enumerate + remove)
// is all done internally.
- return new FingerprintRemovalClient(context, token,
+ return new FingerprintRemovalClient(context, lazyDaemon, token,
null /* ClientMonitorCallbackConverter */, biometricId, userId, owner, utils,
- sensorId);
+ sensorId, authenticatorIds);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java
index ba412e3956ce..240c3c56f75e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java
@@ -18,9 +18,9 @@ package com.android.server.biometrics.sensors.fingerprint;
import android.annotation.NonNull;
import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.fingerprint.Fingerprint;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -38,31 +38,21 @@ import java.util.List;
class FingerprintInternalEnumerateClient extends InternalEnumerateClient<IBiometricsFingerprint> {
private static final String TAG = "FingerprintInternalEnumerateClient";
- FingerprintInternalEnumerateClient(@NonNull Context context, @NonNull IBinder token, int userId,
- @NonNull String owner,
- @NonNull List<? extends BiometricAuthenticator.Identifier> enrolledList,
+ FingerprintInternalEnumerateClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
+ int userId, @NonNull String owner, @NonNull List<Fingerprint> enrolledList,
@NonNull BiometricUtils utils, int sensorId) {
- super(context, token, userId, owner, enrolledList, utils, sensorId,
+ super(context, lazyDaemon, token, userId, owner, enrolledList, utils, sensorId,
BiometricsProtoEnums.MODALITY_FINGERPRINT);
}
@Override
protected void startHalOperation() {
try {
- mDaemon.enumerate();
+ getFreshDaemon().enumerate();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enumerate", e);
- mFinishCallback.onClientFinished(this);
- }
- }
-
- @Override
- protected void stopHalOperation() {
- try {
- mDaemon.cancel();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when requesting cancel", e);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java
index 6d7e76162029..a9336ef6a6c2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java
@@ -28,6 +28,8 @@ import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.RemovalClient;
+import java.util.Map;
+
/**
* Fingerprint-specific removal client supporting the
* {@link android.hardware.biometrics.fingerprint.V2_1} and
@@ -36,31 +38,23 @@ import com.android.server.biometrics.sensors.RemovalClient;
class FingerprintRemovalClient extends RemovalClient<IBiometricsFingerprint> {
private static final String TAG = "FingerprintRemovalClient";
- FingerprintRemovalClient(@NonNull Context context, @NonNull IBinder token,
+ FingerprintRemovalClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId,
- @NonNull String owner, @NonNull BiometricUtils utils, int sensorId) {
- super(context, token, listener, biometricId, userId, owner, utils, sensorId,
- BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ @NonNull String owner, @NonNull BiometricUtils utils, int sensorId,
+ @NonNull Map<Integer, Long> authenticatorIds) {
+ super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId,
+ authenticatorIds, BiometricsProtoEnums.MODALITY_FINGERPRINT);
}
@Override
protected void startHalOperation() {
try {
// GroupId was never used. In fact, groupId is always the same as userId.
- mDaemon.remove(getTargetUserId(), mBiometricId);
+ getFreshDaemon().remove(getTargetUserId(), mBiometricId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting remove", e);
- mFinishCallback.onClientFinished(this);
- }
- }
-
- @Override
- protected void stopHalOperation() {
- try {
- mDaemon.cancel();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when requesting cancel", e);
- mFinishCallback.onClientFinished(this);
+ mFinishCallback.onClientFinished(this, false /* success */);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java
index ccbea31d7c48..882660e7a618 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java
@@ -35,15 +35,16 @@ public class FingerprintRevokeChallengeClient
private static final String TAG = "FingerprintRevokeChallengeClient";
- FingerprintRevokeChallengeClient(@NonNull Context context, @NonNull IBinder token,
+ FingerprintRevokeChallengeClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
@NonNull String owner, int sensorId) {
- super(context, token, owner, sensorId);
+ super(context, lazyDaemon, token, owner, sensorId);
}
@Override
protected void startHalOperation() {
try {
- mDaemon.postEnroll();
+ getFreshDaemon().postEnroll();
} catch (RemoteException e) {
Slog.e(TAG, "revokeChallenge/postEnroll failed", e);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index d2a25dba7936..b05400a0e426 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -29,7 +29,6 @@ import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -64,9 +63,11 @@ import com.android.server.biometrics.fingerprint.PerformanceStatsProto;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BiometricServiceBase;
import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.EnrollClient;
import com.android.server.biometrics.sensors.GenerateChallengeClient;
+import com.android.server.biometrics.sensors.LockoutResetTracker;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.RemovalClient;
@@ -82,7 +83,6 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -97,6 +97,10 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
private static final boolean DEBUG = true;
private static final String FP_DATA_DIR = "fpdata";
+ private final LockoutResetTracker mLockoutResetTracker;
+ private final ClientMonitor.LazyDaemon<IBiometricsFingerprint> mLazyDaemon;
+ private final GestureAvailabilityTracker mGestureAvailabilityTracker;
+
/**
* Receives the incoming binder calls from FingerprintManager.
*/
@@ -113,7 +117,7 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
checkPermission(MANAGE_FINGERPRINT);
final GenerateChallengeClient client = new FingerprintGenerateChallengeClient(
- getContext(), token, new ClientMonitorCallbackConverter(receiver),
+ getContext(), mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver),
opPackageName, getSensorId());
generateChallengeInternal(client);
}
@@ -123,7 +127,7 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
checkPermission(MANAGE_FINGERPRINT);
final RevokeChallengeClient client = new FingerprintRevokeChallengeClient(getContext(),
- token, owner, getSensorId());
+ mLazyDaemon, token, owner, getSensorId());
revokeChallengeInternal(client);
}
@@ -134,8 +138,8 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
checkPermission(MANAGE_FINGERPRINT);
updateActiveGroup(userId);
- final EnrollClient client = new FingerprintEnrollClient(getContext(), token,
- new ClientMonitorCallbackConverter(receiver), userId, cryptoToken,
+ final EnrollClient client = new FingerprintEnrollClient(getContext(), mLazyDaemon,
+ token, new ClientMonitorCallbackConverter(receiver), userId, cryptoToken,
opPackageName, getBiometricUtils(), ENROLL_TIMEOUT_SEC, getSensorId());
enrollInternal(client, userId);
@@ -165,9 +169,10 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
final int statsClient = isKeyguard(opPackageName) ? BiometricsProtoEnums.CLIENT_KEYGUARD
: BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER;
final AuthenticationClient client = new FingerprintAuthenticationClient(getContext(),
- token, new ClientMonitorCallbackConverter(receiver), userId, opId, restricted,
- opPackageName, 0 /* cookie */, false /* requireConfirmation */, getSensorId(),
- isStrongBiometric, surface, statsClient, mTaskStackListener, mLockoutTracker);
+ mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId, opId,
+ restricted, opPackageName, 0 /* cookie */, false /* requireConfirmation */,
+ getSensorId(), isStrongBiometric, surface, statsClient, mTaskStackListener,
+ mLockoutTracker);
authenticateInternal(client, opPackageName);
}
@@ -175,14 +180,14 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
public void prepareForAuthentication(IBinder token, long opId, int userId,
IBiometricSensorReceiver sensorReceiver, String opPackageName,
int cookie, int callingUid, int callingPid, int callingUserId,
- Surface surface) throws RemoteException {
+ Surface surface) {
checkPermission(MANAGE_BIOMETRIC);
updateActiveGroup(userId);
final boolean restricted = true; // BiometricPrompt is always restricted
final AuthenticationClient client = new FingerprintAuthenticationClient(getContext(),
- token, new ClientMonitorCallbackConverter(sensorReceiver), userId, opId,
- restricted, opPackageName, cookie, false /* requireConfirmation */,
+ mLazyDaemon, token, new ClientMonitorCallbackConverter(sensorReceiver), userId,
+ opId, restricted, opPackageName, cookie, false /* requireConfirmation */,
getSensorId(), isStrongBiometric(), surface,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, mTaskStackListener,
mLockoutTracker);
@@ -223,17 +228,19 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
return;
}
- final RemovalClient client = new FingerprintRemovalClient(getContext(), token,
- new ClientMonitorCallbackConverter(receiver), fingerId, userId, opPackageName,
- getBiometricUtils(), getSensorId());
+ final RemovalClient client = new FingerprintRemovalClient(getContext(), mLazyDaemon,
+ token, new ClientMonitorCallbackConverter(receiver), fingerId, userId,
+ opPackageName, getBiometricUtils(), getSensorId(), mAuthenticatorIds);
removeInternal(client);
}
@Override
- public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback)
- throws RemoteException {
+ public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback,
+ final String opPackageName) {
checkPermission(USE_BIOMETRIC_INTERNAL);
- FingerprintService.super.addLockoutResetCallback(callback);
+ mHandler.post(() -> {
+ mLockoutResetTracker.addCallback(callback, opPackageName);
+ });
}
@Override // Binder call
@@ -350,13 +357,13 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
@Override
public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
checkPermission(MANAGE_FINGERPRINT);
- mClientActiveCallbacks.add(callback);
+ mGestureAvailabilityTracker.registerCallback(callback);
}
@Override
public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
checkPermission(MANAGE_FINGERPRINT);
- mClientActiveCallbacks.remove(callback);
+ mGestureAvailabilityTracker.removeCallback(callback);
}
@Override // Binder call
@@ -464,17 +471,11 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
}
private final LockoutFrameworkImpl mLockoutTracker;
- private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
- new CopyOnWriteArrayList<>();
private IUdfpsOverlayController mUdfpsOverlayController;
@GuardedBy("this")
private IBiometricsFingerprint mDaemon;
- private final LockoutFrameworkImpl.LockoutResetCallback mLockoutResetCallback = userId -> {
- notifyLockoutResetMonitors();
- };
-
/**
* Receives callbacks from the HAL.
*/
@@ -550,7 +551,13 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
public FingerprintService(Context context) {
super(context);
- mLockoutTracker = new LockoutFrameworkImpl(context, mLockoutResetCallback);
+ mLazyDaemon = FingerprintService.this::getFingerprintDaemon;
+ mGestureAvailabilityTracker = new GestureAvailabilityTracker();
+ mLockoutResetTracker = new LockoutResetTracker(context);
+ final LockoutFrameworkImpl.LockoutResetCallback lockoutResetCallback = userId -> {
+ mLockoutResetTracker.notifyLockoutResetCallbacks();
+ };
+ mLockoutTracker = new LockoutFrameworkImpl(context, lockoutResetCallback);
}
@Override
@@ -677,20 +684,12 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
if (userId != UserHandle.getCallingUserId()) {
checkPermission(INTERACT_ACROSS_USERS);
}
- return getBiometricUtils().getBiometricsForUser(getContext(), userId);
+ return FingerprintUtils.getInstance().getBiometricsForUser(getContext(), userId);
}
@Override
protected void notifyClientActiveCallbacks(boolean isActive) {
- List<IFingerprintClientActiveCallback> callbacks = mClientActiveCallbacks;
- for (int i = 0; i < callbacks.size(); i++) {
- try {
- callbacks.get(i).onClientActiveChanged(isActive);
- } catch (RemoteException re) {
- // If the remote is dead, stop notifying it
- mClientActiveCallbacks.remove(callbacks.get(i));
- }
- }
+ mGestureAvailabilityTracker.notifyClientActiveCallbacks(isActive);
}
@Override
@@ -705,11 +704,10 @@ public class FingerprintService extends BiometricServiceBase<IBiometricsFingerpr
@Override
protected void doTemplateCleanupForUser(int userId) {
- final List<? extends BiometricAuthenticator.Identifier> enrolledList =
- getEnrolledTemplates(userId);
+ final List<Fingerprint> enrolledList = getEnrolledTemplates(userId);
final FingerprintInternalCleanupClient client = new FingerprintInternalCleanupClient(
- getContext(), userId, getContext().getOpPackageName(), getSensorId(), enrolledList,
- getBiometricUtils());
+ getContext(), mLazyDaemon, userId, getContext().getOpPackageName(), getSensorId(),
+ enrolledList, getBiometricUtils(), mAuthenticatorIds);
cleanupInternal(client);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/GestureAvailabilityTracker.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/GestureAvailabilityTracker.java
new file mode 100644
index 000000000000..6292ecf0e207
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/GestureAvailabilityTracker.java
@@ -0,0 +1,50 @@
+/*
+ * 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.biometrics.sensors.fingerprint;
+
+import android.hardware.fingerprint.IFingerprintClientActiveCallback;
+import android.os.RemoteException;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Keeps track of sensor gesture availability (e.g. swipe), and notifies clients when its
+ * availability changes
+ */
+class GestureAvailabilityTracker {
+ private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks =
+ new CopyOnWriteArrayList<>();
+
+ void registerCallback(IFingerprintClientActiveCallback callback) {
+ mClientActiveCallbacks.add(callback);
+ }
+
+ void removeCallback(IFingerprintClientActiveCallback callback) {
+ mClientActiveCallbacks.remove(callback);
+ }
+
+ void notifyClientActiveCallbacks(boolean isActive) {
+ for (IFingerprintClientActiveCallback callback : mClientActiveCallbacks) {
+ try {
+ callback.onClientActiveChanged(isActive);
+ } catch (RemoteException re) {
+ // If the remote is dead, stop notifying it
+ mClientActiveCallbacks.remove(callback);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index c5aa8d5361ec..a75a80a606eb 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -82,6 +82,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
private final PackageManager mPackageManager;
private final UserManager mUserManager;
private final INetd mNetd;
+ private final Dependencies mDeps;
// Values are User IDs.
@GuardedBy("this")
@@ -102,10 +103,30 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
@GuardedBy("this")
private final Set<Integer> mAllApps = new HashSet<>();
- public PermissionMonitor(Context context, INetd netd) {
+ /**
+ * Dependencies of PermissionMonitor, for injection in tests.
+ */
+ @VisibleForTesting
+ public static class Dependencies {
+ /**
+ * Get device first sdk version.
+ */
+ public int getDeviceFirstSdkInt() {
+ return Build.VERSION.FIRST_SDK_INT;
+ }
+ }
+
+ public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) {
+ this(context, netd, new Dependencies());
+ }
+
+ @VisibleForTesting
+ PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd,
+ @NonNull final Dependencies deps) {
mPackageManager = context.getPackageManager();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mNetd = netd;
+ mDeps = deps;
}
// Intended to be called only once at startup, after the system is ready. Installs a broadcast
@@ -186,11 +207,6 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
@VisibleForTesting
- protected int getDeviceFirstSdkInt() {
- return Build.VERSION.FIRST_SDK_INT;
- }
-
- @VisibleForTesting
boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
return false;
@@ -212,7 +228,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
if (app.applicationInfo != null) {
// Backward compatibility for b/114245686, on devices that launched before Q daemons
// and apps running as the system UID are exempted from this check.
- if (app.applicationInfo.uid == SYSTEM_UID && getDeviceFirstSdkInt() < VERSION_Q) {
+ if (app.applicationInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q) {
return true;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 70f0399d1070..05cf40a091b6 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -120,6 +120,11 @@ public abstract class InputMethodManagerInternal {
public abstract void reportImeControl(@Nullable IBinder windowToken);
/**
+ * Destroys the IME surface.
+ */
+ public abstract void removeImeSurface();
+
+ /**
* Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing.
*/
private static final InputMethodManagerInternal NOP =
@@ -166,6 +171,10 @@ public abstract class InputMethodManagerInternal {
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
}
+
+ @Override
+ public void removeImeSurface() {
+ }
};
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 15e8a92ba0e4..d8ee32e7bd74 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -211,6 +211,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
static final int MSG_INITIALIZE_IME = 1040;
static final int MSG_CREATE_SESSION = 1050;
static final int MSG_REMOVE_IME_SURFACE = 1060;
+ static final int MSG_REMOVE_IME_SURFACE_FROM_WINDOW = 1061;
static final int MSG_START_INPUT = 2000;
@@ -2128,6 +2129,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public void onInputMethodFinishInput() throws RemoteException {
mCallback.onInputMethodFinishInput();
}
+
+ @Override
+ public void onInlineSuggestionsSessionInvalidated() throws RemoteException {
+ mCallback.onInlineSuggestionsSessionInvalidated();
+ }
}
/**
@@ -4000,6 +4006,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mHandler.sendMessage(mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
}
+ @Override
+ public void removeImeSurfaceFromWindow(IBinder windowToken) {
+ // No permission check, because we'll only execute the request if the calling window is
+ // also the current IME client.
+ mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
+ }
+
@BinderThread
private void notifyUserAction(@NonNull IBinder token) {
if (DEBUG) {
@@ -4273,11 +4286,27 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return true;
}
case MSG_REMOVE_IME_SURFACE: {
- try {
- if (mEnabledSession != null && mEnabledSession.session != null) {
- mEnabledSession.session.removeImeSurface();
+ synchronized (mMethodMap) {
+ try {
+ if (mEnabledSession != null && mEnabledSession.session != null
+ && !mShowRequested) {
+ mEnabledSession.session.removeImeSurface();
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ return true;
+ }
+ case MSG_REMOVE_IME_SURFACE_FROM_WINDOW: {
+ IBinder windowToken = (IBinder) msg.obj;
+ synchronized (mMethodMap) {
+ try {
+ if (windowToken == mCurFocusedWindow
+ && mEnabledSession != null && mEnabledSession.session != null) {
+ mEnabledSession.session.removeImeSurface();
+ }
+ } catch (RemoteException e) {
}
- } catch (RemoteException e) {
}
return true;
}
@@ -5111,6 +5140,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public void reportImeControl(@Nullable IBinder windowToken) {
mService.reportImeControl(windowToken);
}
+
+ @Override
+ public void removeImeSurface() {
+ mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
+ }
}
@BinderThread
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 23392db0690d..2516e289f099 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -226,6 +226,11 @@ public final class MultiClientInputMethodManagerService {
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
}
+
+ @Override
+ public void removeImeSurface() {
+ reportNotSupported();
+ }
});
}
@@ -1482,6 +1487,12 @@ public final class MultiClientInputMethodManagerService {
@BinderThread
@Override
+ public void removeImeSurfaceFromWindow(IBinder windowToken) {
+ reportNotSupported();
+ }
+
+ @BinderThread
+ @Override
public boolean showSoftInput(
IInputMethodClient client, IBinder token, int flags,
ResultReceiver resultReceiver) {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 5c1d1826b88a..f69c8239762d 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -25,7 +25,6 @@ import static android.location.LocationManager.EXTRA_PROVIDER_ENABLED;
import static android.location.LocationManager.EXTRA_PROVIDER_NAME;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
-import static android.location.LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION;
import static android.location.LocationManager.KEY_LOCATION_CHANGED;
import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
import static android.location.LocationManager.MODE_CHANGED_ACTION;
@@ -1222,21 +1221,10 @@ public class LocationManagerService extends ILocationManager.Stub {
false);
// Now update monitoring of high power requests only.
- boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
mOpHighPowerMonitoring = updateMonitoring(
requestingHighPowerLocation,
mOpHighPowerMonitoring,
true);
- if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
- long identity = Binder.clearCallingIdentity();
- try {
- // Send an intent to notify that a high power request has been added/removed.
- Intent intent = new Intent(HIGH_POWER_REQUEST_CHANGE_ACTION);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
}
private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
diff --git a/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java b/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java
index 70d83a9dd7dd..631dbbf0f1fd 100644
--- a/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java
@@ -27,7 +27,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.location.LocationManager;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
@@ -582,17 +581,9 @@ class GnssVisibilityControl {
mAppOps.finishOp(AppOpsManager.OP_MONITOR_LOCATION, uid, proxyAppPkgName);
mAppOps.finishOp(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, uid, proxyAppPkgName);
}
- sendHighPowerMonitoringBroadcast();
return true;
}
- private void sendHighPowerMonitoringBroadcast() {
- // Send an intent to notify that a high power request has been added/removed so that
- // the SystemUi checks the state of AppOps and updates the location icon accordingly.
- Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- }
-
private void handleEmergencyNfwNotification(NfwNotification nfwNotification) {
boolean isPermissionMismatched = false;
if (!nfwNotification.isRequestAccepted()) {
diff --git a/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java b/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java
index 78af79b533d8..a95383695ae8 100644
--- a/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java
+++ b/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java
@@ -16,12 +16,8 @@
package com.android.server.location.util;
-import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
-
import android.app.AppOpsManager;
import android.content.Context;
-import android.content.Intent;
-import android.location.LocationManager;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
@@ -66,22 +62,13 @@ public class SystemAppOpsHelper extends AppOpsHelper {
long identity = Binder.clearCallingIdentity();
try {
- boolean allowed = mAppOps.startOpNoThrow(
+ return mAppOps.startOpNoThrow(
appOp,
callerIdentity.getUid(),
callerIdentity.getPackageName(),
false,
callerIdentity.getAttributionTag(),
callerIdentity.getListenerId()) == AppOpsManager.MODE_ALLOWED;
-
- if (allowed && appOp == OP_MONITOR_HIGH_POWER_LOCATION) {
- // notify of possible location icon change
- mContext.sendBroadcast(
- new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION).addFlags(
- Intent.FLAG_RECEIVER_FOREGROUND));
- }
-
- return allowed;
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -98,13 +85,6 @@ public class SystemAppOpsHelper extends AppOpsHelper {
callerIdentity.getUid(),
callerIdentity.getPackageName(),
callerIdentity.getAttributionTag());
-
- if (appOp == OP_MONITOR_HIGH_POWER_LOCATION) {
- // notify of possible location icon change
- mContext.sendBroadcast(
- new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION).addFlags(
- Intent.FLAG_RECEIVER_FOREGROUND));
- }
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 7b767b86f0d4..c4581c88f49e 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -155,7 +155,7 @@ class LockSettingsShellCommand extends ShellCommand {
pw.println(" set-pin [--old <CREDENTIAL>] [--user USER_ID] <PIN>");
pw.println(" Sets the lock screen as PIN, using the given PIN to unlock.");
pw.println("");
- pw.println(" set-pin [--old <CREDENTIAL>] [--user USER_ID] <PASSWORD>");
+ pw.println(" set-password [--old <CREDENTIAL>] [--user USER_ID] <PASSWORD>");
pw.println(" Sets the lock screen as password, using the given PASSOWRD to unlock.");
pw.println("");
pw.println(" sp [--old <CREDENTIAL>] [--user USER_ID]");
diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
index 55e0795f8b50..b9822fcb096a 100644
--- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
+++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
@@ -26,12 +26,12 @@ import android.os.Message;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.IntArray;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -104,7 +104,7 @@ class AudioPlayerStateMonitor {
// TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID.
@GuardedBy("mLock")
@SuppressWarnings("WeakerAccess") /* synthetic access */
- final IntArray mSortedAudioPlaybackClientUids = new IntArray();
+ final List<Integer> mSortedAudioPlaybackClientUids = new ArrayList<>();
static AudioPlayerStateMonitor getInstance(Context context) {
synchronized (AudioPlayerStateMonitor.class) {
@@ -145,8 +145,8 @@ class AudioPlayerStateMonitor {
* audio/video) The UID whose audio is currently playing comes first, then the UID whose audio
* playback becomes active at the last comes next.
*/
- public IntArray getSortedAudioPlaybackClientUids() {
- IntArray sortedAudioPlaybackClientUids = new IntArray();
+ public List<Integer> getSortedAudioPlaybackClientUids() {
+ List<Integer> sortedAudioPlaybackClientUids = new ArrayList();
synchronized (mLock) {
sortedAudioPlaybackClientUids.addAll(mSortedAudioPlaybackClientUids);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index dbf1abc0ca70..0f6748366e16 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -50,7 +50,6 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.util.Log;
-import android.util.Slog;
import android.view.KeyEvent;
import com.android.server.LocalServices;
@@ -996,7 +995,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
}
return true;
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
+ Log.e(TAG, "Remote failure in sendMediaRequest.", e);
}
return false;
}
@@ -1013,7 +1012,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
}
return true;
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
+ Log.e(TAG, "Remote failure in sendMediaRequest.", e);
}
return false;
}
@@ -1023,7 +1022,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onCommand(packageName, pid, uid, command, args, cb);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in sendCommand.", e);
+ Log.e(TAG, "Remote failure in sendCommand.", e);
}
}
@@ -1032,7 +1031,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onCustomAction(packageName, pid, uid, action, args);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in sendCustomAction.", e);
+ Log.e(TAG, "Remote failure in sendCustomAction.", e);
}
}
@@ -1040,7 +1039,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onPrepare(packageName, pid, uid);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in prepare.", e);
+ Log.e(TAG, "Remote failure in prepare.", e);
}
}
@@ -1049,7 +1048,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onPrepareFromMediaId(packageName, pid, uid, mediaId, extras);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in prepareFromMediaId.", e);
+ Log.e(TAG, "Remote failure in prepareFromMediaId.", e);
}
}
@@ -1058,7 +1057,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onPrepareFromSearch(packageName, pid, uid, query, extras);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in prepareFromSearch.", e);
+ Log.e(TAG, "Remote failure in prepareFromSearch.", e);
}
}
@@ -1066,7 +1065,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onPrepareFromUri(packageName, pid, uid, uri, extras);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in prepareFromUri.", e);
+ Log.e(TAG, "Remote failure in prepareFromUri.", e);
}
}
@@ -1074,7 +1073,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onPlay(packageName, pid, uid);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in play.", e);
+ Log.e(TAG, "Remote failure in play.", e);
}
}
@@ -1083,7 +1082,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onPlayFromMediaId(packageName, pid, uid, mediaId, extras);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in playFromMediaId.", e);
+ Log.e(TAG, "Remote failure in playFromMediaId.", e);
}
}
@@ -1092,7 +1091,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onPlayFromSearch(packageName, pid, uid, query, extras);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in playFromSearch.", e);
+ Log.e(TAG, "Remote failure in playFromSearch.", e);
}
}
@@ -1100,7 +1099,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onPlayFromUri(packageName, pid, uid, uri, extras);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in playFromUri.", e);
+ Log.e(TAG, "Remote failure in playFromUri.", e);
}
}
@@ -1108,7 +1107,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onSkipToTrack(packageName, pid, uid, id);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in skipToTrack", e);
+ Log.e(TAG, "Remote failure in skipToTrack", e);
}
}
@@ -1116,7 +1115,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onPause(packageName, pid, uid);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in pause.", e);
+ Log.e(TAG, "Remote failure in pause.", e);
}
}
@@ -1124,7 +1123,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onStop(packageName, pid, uid);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in stop.", e);
+ Log.e(TAG, "Remote failure in stop.", e);
}
}
@@ -1132,7 +1131,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onNext(packageName, pid, uid);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in next.", e);
+ Log.e(TAG, "Remote failure in next.", e);
}
}
@@ -1140,7 +1139,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onPrevious(packageName, pid, uid);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in previous.", e);
+ Log.e(TAG, "Remote failure in previous.", e);
}
}
@@ -1148,7 +1147,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onFastForward(packageName, pid, uid);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in fastForward.", e);
+ Log.e(TAG, "Remote failure in fastForward.", e);
}
}
@@ -1156,7 +1155,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onRewind(packageName, pid, uid);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in rewind.", e);
+ Log.e(TAG, "Remote failure in rewind.", e);
}
}
@@ -1164,7 +1163,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onSeekTo(packageName, pid, uid, pos);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in seekTo.", e);
+ Log.e(TAG, "Remote failure in seekTo.", e);
}
}
@@ -1172,7 +1171,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onRate(packageName, pid, uid, rating);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in rate.", e);
+ Log.e(TAG, "Remote failure in rate.", e);
}
}
@@ -1180,7 +1179,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onSetPlaybackSpeed(packageName, pid, uid, speed);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in setPlaybackSpeed.", e);
+ Log.e(TAG, "Remote failure in setPlaybackSpeed.", e);
}
}
@@ -1194,7 +1193,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
mCb.onAdjustVolume(packageName, pid, uid, direction);
}
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in adjustVolume.", e);
+ Log.e(TAG, "Remote failure in adjustVolume.", e);
}
}
@@ -1202,7 +1201,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
try {
mCb.onSetVolumeTo(packageName, pid, uid, value);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in setVolumeTo.", e);
+ Log.e(TAG, "Remote failure in setVolumeTo.", e);
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 375804a395ef..9a83242a5955 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -75,7 +75,6 @@ import android.provider.Settings;
import android.speech.RecognizerIntent;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.KeyEvent;
@@ -1140,7 +1139,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
return sessionBinder;
} catch (Exception e) {
- Slog.w(TAG, "Exception in creating a new session", e);
+ Log.w(TAG, "Exception in creating a new session", e);
throw e;
} finally {
Binder.restoreCallingIdentity(token);
@@ -1351,7 +1350,7 @@ public class MediaSessionService extends SystemService implements Monitor {
if (!isUserSetupComplete()) {
// Global media key handling can have the side-effect of starting new
// activities which is undesirable while setup is in progress.
- Slog.i(TAG, "Not dispatching media key event because user "
+ Log.i(TAG, "Not dispatching media key event because user "
+ "setup is in progress.");
return;
}
@@ -1361,7 +1360,7 @@ public class MediaSessionService extends SystemService implements Monitor {
if (isGlobalPriorityActive && uid != Process.SYSTEM_UID) {
// Prevent dispatching key event through reflection while the global
// priority session is active.
- Slog.i(TAG, "Only the system can dispatch media key event "
+ Log.i(TAG, "Only the system can dispatch media key event "
+ "to the global priority session.");
return;
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index b678c8962a21..953aae44d6a7 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -22,7 +22,6 @@ import android.media.Session2Token;
import android.media.session.MediaSession;
import android.os.Debug;
import android.os.UserHandle;
-import android.util.IntArray;
import android.util.Log;
import android.util.SparseArray;
@@ -190,7 +189,8 @@ class MediaSessionStack {
if (DEBUG) {
Log.d(TAG, "updateMediaButtonSessionIfNeeded, callers=" + Debug.getCallers(2));
}
- IntArray audioPlaybackUids = mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids();
+ List<Integer> audioPlaybackUids =
+ mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids();
for (int i = 0; i < audioPlaybackUids.size(); i++) {
int audioPlaybackUid = audioPlaybackUids.get(i);
MediaSessionRecordImpl mediaButtonSession = findMediaButtonSession(audioPlaybackUid);
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 951f462ed201..592db83b8721 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -77,6 +77,8 @@ public abstract class ApexManager {
public static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
static final int MATCH_FACTORY_PACKAGE = 1 << 1;
+ private static final String VNDK_APEX_MODULE_NAME_PREFIX = "com.android.vndk.";
+
private static final Singleton<ApexManager> sApexManagerSingleton =
new Singleton<ApexManager>() {
@Override
@@ -342,8 +344,17 @@ public abstract class ApexManager {
public abstract boolean destroyDeSnapshots(int rollbackId);
/**
+ * Deletes snapshots of the credential encrypted apex data directories for the specified user,
+ * for the given rollback id as long as the user is credential unlocked.
+ *
+ * @return boolean true if the delete was successful
+ */
+ public abstract boolean destroyCeSnapshots(int userId, int rollbackId);
+
+ /**
* Deletes snapshots of the credential encrypted apex data directories for the specified user,
- * where the rollback id is not included in {@code retainRollbackIds}.
+ * where the rollback id is not included in {@code retainRollbackIds} as long as the user is
+ * credential unlocked.
*
* @return boolean true if the delete was successful
*/
@@ -526,7 +537,9 @@ public abstract class ApexManager {
activePackagesSet.add(packageInfo.packageName);
}
if (ai.isFactory) {
- if (factoryPackagesSet.contains(packageInfo.packageName)) {
+ // Don't throw when the duplicating APEX is VNDK APEX
+ if (factoryPackagesSet.contains(packageInfo.packageName)
+ && !ai.moduleName.startsWith(VNDK_APEX_MODULE_NAME_PREFIX)) {
throw new IllegalStateException(
"Two factory packages have the same name: "
+ packageInfo.packageName);
@@ -875,6 +888,17 @@ public abstract class ApexManager {
}
@Override
+ public boolean destroyCeSnapshots(int userId, int rollbackId) {
+ try {
+ waitForApexService().destroyCeSnapshots(userId, rollbackId);
+ return true;
+ } catch (Exception e) {
+ Slog.e(TAG, e.getMessage(), e);
+ return false;
+ }
+ }
+
+ @Override
public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) {
try {
waitForApexService().destroyCeSnapshotsNotSpecified(userId, retainRollbackIds);
@@ -1136,6 +1160,11 @@ public abstract class ApexManager {
}
@Override
+ public boolean destroyCeSnapshots(int userId, int rollbackId) {
+ return true;
+ }
+
+ @Override
public boolean destroyCeSnapshotsNotSpecified(int userId, int[] retainRollbackIds) {
return true;
}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 3a203d52edbe..c3c2e5e65103 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -708,12 +708,15 @@ public class AppsFilter {
return ret;
}
+ /**
+ * This method recomputes all component / intent-based visibility and is intended to match the
+ * relevant logic of {@link #addPackageInternal(PackageSetting, ArrayMap)}
+ */
private void recomputeComponentVisibility(ArrayMap<String, PackageSetting> existingSettings) {
mQueriesViaComponent.clear();
for (int i = existingSettings.size() - 1; i >= 0; i--) {
PackageSetting setting = existingSettings.valueAt(i);
- if (setting.pkg == null
- || mForceQueryable.contains(setting.appId)) {
+ if (setting.pkg == null || requestsQueryAllPackages(setting.pkg)) {
continue;
}
for (int j = existingSettings.size() - 1; j >= 0; j--) {
@@ -721,7 +724,7 @@ public class AppsFilter {
continue;
}
final PackageSetting otherSetting = existingSettings.valueAt(j);
- if (otherSetting.pkg == null) {
+ if (otherSetting.pkg == null || mForceQueryable.contains(otherSetting.appId)) {
continue;
}
if (canQueryViaComponents(setting.pkg, otherSetting.pkg, mProtectedBroadcasts)) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 2df4a920d5c2..eddab76de5ee 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -18,6 +18,7 @@ package com.android.server.pm;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.Nullable;
import android.content.Context;
@@ -42,10 +43,9 @@ import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
/**
* A service for A/B OTA dexopting.
@@ -123,15 +123,20 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
}
final List<PackageSetting> important;
final List<PackageSetting> others;
+ Predicate<PackageSetting> isPlatformPackage = pkgSetting ->
+ PLATFORM_PACKAGE_NAME.equals(pkgSetting.pkg.getPackageName());
synchronized (mPackageManagerService.mLock) {
// Important: the packages we need to run with ab-ota compiler-reason.
important = PackageManagerServiceUtils.getPackagesForDexopt(
mPackageManagerService.mSettings.mPackages.values(), mPackageManagerService,
DEBUG_DEXOPT);
+ // Remove Platform Package from A/B OTA b/160735835.
+ important.removeIf(isPlatformPackage);
// Others: we should optimize this with the (first-)boot compiler-reason.
others = new ArrayList<>(mPackageManagerService.mSettings.mPackages.values());
others.removeAll(important);
others.removeIf(PackageManagerServiceUtils.REMOVE_IF_NULL_PKG);
+ others.removeIf(isPlatformPackage);
// Pre-size the array list by over-allocating by a factor of 1.5.
mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2);
@@ -147,7 +152,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
throw new IllegalStateException("Found a core app that's not important");
}
mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.pkg, pkgSetting,
- PackageManagerService.REASON_FIRST_BOOT));
+ PackageManagerService.REASON_FIRST_BOOT));
}
completeSize = mDexoptCommands.size();
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index e355bb9f6e60..30b1c2c93a45 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Pair;
@@ -27,6 +28,8 @@ import com.android.server.pm.parsing.pkg.ParsedPackage;
import java.io.File;
import java.util.Set;
+
+
// TODO: Move to .parsing sub-package
@VisibleForTesting
public interface PackageAbiHelper {
@@ -34,7 +37,8 @@ public interface PackageAbiHelper {
* Derive and get the location of native libraries for the given package,
* which varies depending on where and how the package was installed.
*/
- NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, PackageSetting pkgSetting,
+ @NonNull
+ NativeLibraryPaths deriveNativeLibraryPaths(AndroidPackage pkg, boolean isUpdatedSystemApp,
File appLib32InstallDir);
/**
@@ -51,7 +55,7 @@ public interface PackageAbiHelper {
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
*/
Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg, boolean isUpdatedSystemApp,
- String cpuAbiOverride, boolean extractLibs) throws PackageManagerException;
+ String cpuAbiOverride) throws PackageManagerException;
/**
* Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index fc58968a7325..8af7e1f4f6d1 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -131,16 +131,16 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
}
@Override
- public NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, PackageSetting pkgSetting,
- File appLib32InstallDir) {
+ public NativeLibraryPaths deriveNativeLibraryPaths(AndroidPackage pkg,
+ boolean isUpdatedSystemApp, File appLib32InstallDir) {
// Trying to derive the paths, thus need the raw ABI info from the parsed package, and the
// current state in PackageSetting is irrelevant.
- return getNativeLibraryPaths(new Abis(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi()),
+ return deriveNativeLibraryPaths(new Abis(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi()),
appLib32InstallDir, pkg.getCodePath(), pkg.getBaseCodePath(), pkg.isSystem(),
- pkgSetting.getPkgState().isUpdatedSystemApp());
+ isUpdatedSystemApp);
}
- private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis,
+ private static NativeLibraryPaths deriveNativeLibraryPaths(final Abis abis,
final File appLib32InstallDir, final String codePath, final String sourceDir,
final boolean isSystemApp, final boolean isUpdatedSystemApp) {
final File codeFile = new File(codePath);
@@ -296,22 +296,19 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
@Override
public Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg,
- boolean isUpdatedSystemApp, String cpuAbiOverride, boolean extractLibs)
+ boolean isUpdatedSystemApp, String cpuAbiOverride)
throws PackageManagerException {
// Give ourselves some initial paths; we'll come back for another
// pass once we've determined ABI below.
String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(pkg);
String pkgRawSecondaryCpuAbi = AndroidPackageUtils.getRawSecondaryCpuAbi(pkg);
- final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(
+ final NativeLibraryPaths initialLibraryPaths = deriveNativeLibraryPaths(
new Abis(pkgRawPrimaryCpuAbi, pkgRawSecondaryCpuAbi),
PackageManagerService.sAppLib32InstallDir, pkg.getCodePath(),
pkg.getBaseCodePath(), pkg.isSystem(),
isUpdatedSystemApp);
- // We shouldn't attempt to extract libs from system app when it was not updated.
- if (pkg.isSystem() && !isUpdatedSystemApp) {
- extractLibs = false;
- }
+ final boolean extractLibs = shouldExtractLibs(pkg, isUpdatedSystemApp);
final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
@@ -455,11 +452,21 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
return new Pair<>(abis,
- getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
+ deriveNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
pkg.getCodePath(), pkg.getBaseCodePath(), pkg.isSystem(),
isUpdatedSystemApp));
}
+ private boolean shouldExtractLibs(AndroidPackage pkg, boolean isUpdatedSystemApp) {
+ // We shouldn't extract libs if the package is a library or if extractNativeLibs=false
+ boolean extractLibs = !AndroidPackageUtils.isLibrary(pkg) && pkg.isExtractNativeLibs();
+ // We shouldn't attempt to extract libs from system app when it was not updated.
+ if (pkg.isSystem() && !isUpdatedSystemApp) {
+ extractLibs = false;
+ }
+ return extractLibs;
+ }
+
/**
* Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
* i.e, so that all packages can be run inside a single process if required.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 07f756771326..312dcddd577d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -84,6 +84,8 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
+import com.android.server.SystemService;
+import com.android.server.SystemServiceManager;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -201,6 +203,27 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
};
+ private static final class Lifecycle extends SystemService {
+ private final PackageInstallerService mPackageInstallerService;
+
+ Lifecycle(Context context, PackageInstallerService service) {
+ super(context);
+ mPackageInstallerService = service;
+ }
+
+ @Override
+ public void onStart() {
+ // no-op
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mPackageInstallerService.onBroadcastReady();
+ }
+ }
+ }
+
public PackageInstallerService(Context context, PackageManagerService pm,
Supplier<PackageParser2> apexParserSupplier) {
mContext = context;
@@ -222,6 +245,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mApexManager = ApexManager.getInstance();
mStagingManager = new StagingManager(this, context, apexParserSupplier);
+
+ LocalServices.getService(SystemServiceManager.class).startService(
+ new Lifecycle(context, this));
}
boolean okToSendBroadcasts() {
@@ -259,6 +285,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
+ private void onBroadcastReady() {
+ // Broadcasts are not sent while we restore sessions on boot, since no processes would be
+ // ready to listen to them. From now on, it is safe to send broadcasts which otherwise will
+ // be rejected by ActivityManagerService if its systemReady() is not completed.
+ mOkToSendBroadcasts = true;
+ }
+
void restoreAndApplyStagedSessionIfNeeded() {
List<PackageInstallerSession> stagedSessionsToRestore = new ArrayList<>();
synchronized (mSessions) {
@@ -281,16 +314,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
mStagingManager.restoreSession(session, isDeviceUpgrading);
}
- // Broadcasts are not sent while we restore sessions on boot, since no processes would be
- // ready to listen to them. From now on, we greedily assume that broadcasts requests are
- // safe to send out. The worst that can happen is that a broadcast is attempted before
- // ActivityManagerService completes its own systemReady(), in which case it will be rejected
- // with an otherwise harmless exception.
- // A more appropriate way to do this would be to wait until the correct boot phase is
- // reached, but since we are not a SystemService we can't override onBootPhase.
- // Waiting on the BOOT_COMPLETED broadcast can take several minutes, so that's not a viable
- // way either.
- mOkToSendBroadcasts = true;
}
@GuardedBy("mSessions")
@@ -592,12 +615,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
- if (mBypassNextStagedInstallerCheck) {
- mBypassNextStagedInstallerCheck = false;
- } else if (params.isStaged
- && !isCalledBySystemOrShell(callingUid)
- && !isWhitelistedStagedInstaller(requestedInstallerPackageName)) {
- throw new SecurityException("Installer not allowed to commit staged install");
+ if (params.isStaged && !isCalledBySystemOrShell(callingUid)) {
+ if (mBypassNextStagedInstallerCheck) {
+ mBypassNextStagedInstallerCheck = false;
+ } else if (!isStagedInstallerAllowed(requestedInstallerPackageName)) {
+ throw new SecurityException("Installer not allowed to commit staged install");
+ }
}
if (!params.isMultiPackage) {
@@ -729,7 +752,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
|| callingUid == Process.SHELL_UID;
}
- private boolean isWhitelistedStagedInstaller(String installerName) {
+ private boolean isStagedInstallerAllowed(String installerName) {
return SystemConfig.getInstance().getWhitelistedStagedInstallers().contains(installerName);
}
@@ -869,7 +892,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
@Override
public ParceledListSlice<SessionInfo> getStagedSessions() {
- return mStagingManager.getSessions(Binder.getCallingUid());
+ final List<SessionInfo> result = new ArrayList<>();
+ synchronized (mSessions) {
+ for (int i = 0; i < mSessions.size(); i++) {
+ final PackageInstallerSession session = mSessions.valueAt(i);
+ if (session.isStaged() && !session.isDestroyed()) {
+ result.add(session.generateInfoForCaller(false, Binder.getCallingUid()));
+ }
+ }
+ }
+ return new ParceledListSlice<>(result);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index daf7f72b2ee7..9f3db704253e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11492,15 +11492,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride, pkgSetting);
+ final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
- final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
- packageAbiHelper.derivePackageAbi(parsedPackage,
- pkgSetting.getPkgState().isUpdatedSystemApp(), cpuAbiOverride,
- extractNativeLibs);
+ packageAbiHelper.derivePackageAbi(parsedPackage, isUpdatedSystemApp,
+ cpuAbiOverride);
derivedAbi.first.applyTo(parsedPackage);
derivedAbi.second.applyTo(parsedPackage);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -11510,15 +11509,15 @@ public class PackageManagerService extends IPackageManager.Stub
// structure. Try to detect abi based on directory structure.
String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage);
- if (parsedPackage.isSystem() && !pkgSetting.getPkgState().isUpdatedSystemApp() &&
- pkgRawPrimaryCpuAbi == null) {
+ if (parsedPackage.isSystem() && !isUpdatedSystemApp
+ && pkgRawPrimaryCpuAbi == null) {
final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
parsedPackage);
abis.applyTo(parsedPackage);
abis.applyTo(pkgSetting);
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
- packageAbiHelper.getNativeLibraryPaths(parsedPackage, pkgSetting,
- sAppLib32InstallDir);
+ packageAbiHelper.deriveNativeLibraryPaths(parsedPackage,
+ isUpdatedSystemApp, sAppLib32InstallDir);
nativeLibraryPaths.applyTo(parsedPackage);
}
} else {
@@ -11529,8 +11528,8 @@ public class PackageManagerService extends IPackageManager.Stub
.setSecondaryCpuAbi(secondaryCpuAbiFromSettings);
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
- packageAbiHelper.getNativeLibraryPaths(parsedPackage,
- pkgSetting, sAppLib32InstallDir);
+ packageAbiHelper.deriveNativeLibraryPaths(parsedPackage,
+ isUpdatedSystemApp, sAppLib32InstallDir);
nativeLibraryPaths.applyTo(parsedPackage);
if (DEBUG_ABI_SELECTION) {
@@ -11555,7 +11554,7 @@ public class PackageManagerService extends IPackageManager.Stub
// ABIs we determined during compilation, but the path will depend on the final
// package path (after the rename away from the stage path).
final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
- packageAbiHelper.getNativeLibraryPaths(parsedPackage, pkgSetting,
+ packageAbiHelper.deriveNativeLibraryPaths(parsedPackage, isUpdatedSystemApp,
sAppLib32InstallDir);
nativeLibraryPaths.applyTo(parsedPackage);
}
@@ -17485,7 +17484,6 @@ public class PackageManagerService extends IPackageManager.Stub
scanFlags |= SCAN_NO_DEX;
try {
- final boolean extractNativeLibs = !AndroidPackageUtils.isLibrary(parsedPackage);
PackageSetting pkgSetting;
synchronized (mLock) {
pkgSetting = mSettings.getPackageLPr(pkgName);
@@ -17500,7 +17498,7 @@ public class PackageManagerService extends IPackageManager.Stub
final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
- abiOverride, extractNativeLibs);
+ abiOverride);
derivedAbi.first.applyTo(parsedPackage);
derivedAbi.second.applyTo(parsedPackage);
} catch (PackageManagerException pme) {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 53a3904ed8c1..14da9aa14470 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -38,7 +38,6 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
-import android.content.pm.ParceledListSlice;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
@@ -184,20 +183,6 @@ public class StagingManager {
mApexManager.markBootCompleted();
}
- ParceledListSlice<PackageInstaller.SessionInfo> getSessions(int callingUid) {
- final List<PackageInstaller.SessionInfo> result = new ArrayList<>();
- synchronized (mStagedSessions) {
- for (int i = 0; i < mStagedSessions.size(); i++) {
- final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
- if (stagedSession.isDestroyed()) {
- continue;
- }
- result.add(stagedSession.generateInfoForCaller(false /*icon*/, callingUid));
- }
- }
- return new ParceledListSlice<>(result);
- }
-
/**
* Validates the signature used to sign the container of the new apex package
*
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index 88938b204f6c..c8e36481c738 100644
--- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -206,6 +206,16 @@ public class AppDataRollbackHelper {
}
/**
+ * Deletes snapshots of the credential encrypted apex data directories for the specified user,
+ * for the given rollback id. This method will be a no-op if the user is not unlocked.
+ */
+ public void destroyApexCeSnapshots(int userId, int rollbackId) {
+ if (!isUserCredentialLocked(userId)) {
+ mApexManager.destroyCeSnapshots(userId, rollbackId);
+ }
+ }
+
+ /**
* Commits the pending backups and restores for a given {@code userId} and {@code rollback}. If
* the rollback has a pending backup, it is updated with a mapping from {@code userId} to inode
* of the CE user data snapshot.
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index c3477804fb64..2db6043f1c0a 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -42,6 +42,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.ext.SdkExtensions;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -61,9 +62,9 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.function.Consumer;
-
/**
* Information about a rollback available for a set of atomically installed packages.
*
@@ -699,11 +700,13 @@ class Rollback {
void delete(AppDataRollbackHelper dataHelper) {
assertInWorkerThread();
boolean containsApex = false;
+ Set<Integer> apexUsers = new ArraySet<>();
for (PackageRollbackInfo pkgInfo : info.getPackages()) {
+ List<Integer> snapshottedUsers = pkgInfo.getSnapshottedUsers();
if (pkgInfo.isApex()) {
containsApex = true;
+ apexUsers.addAll(snapshottedUsers);
} else {
- List<Integer> snapshottedUsers = pkgInfo.getSnapshottedUsers();
for (int i = 0; i < snapshottedUsers.size(); i++) {
// Destroy app data snapshot.
int userId = snapshottedUsers.get(i);
@@ -714,6 +717,9 @@ class Rollback {
}
if (containsApex) {
dataHelper.destroyApexDeSnapshots(info.getRollbackId());
+ for (int user : apexUsers) {
+ dataHelper.destroyApexCeSnapshots(user, info.getRollbackId());
+ }
}
RollbackStore.deleteRollback(this);
diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java
index 37df5481d3c4..6dc1d6921dbb 100644
--- a/services/core/java/com/android/server/storage/StorageSessionController.java
+++ b/services/core/java/com/android/server/storage/StorageSessionController.java
@@ -53,16 +53,14 @@ public final class StorageSessionController {
private final Context mContext;
@GuardedBy("mLock")
private final SparseArray<StorageUserConnection> mConnections = new SparseArray<>();
- private final boolean mIsFuseEnabled;
private volatile ComponentName mExternalStorageServiceComponent;
private volatile String mExternalStorageServicePackageName;
private volatile int mExternalStorageServiceAppId;
private volatile boolean mIsResetting;
- public StorageSessionController(Context context, boolean isFuseEnabled) {
+ public StorageSessionController(Context context) {
mContext = Objects.requireNonNull(context);
- mIsFuseEnabled = isFuseEnabled;
}
/**
@@ -361,6 +359,6 @@ public final class StorageSessionController {
}
private boolean shouldHandle(@Nullable VolumeInfo vol) {
- return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
+ return !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
}
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 32f8da8d4a77..3406bd99c883 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -28,6 +28,7 @@ import android.database.ContentObserver;
import android.os.Binder;
import android.os.Handler;
import android.provider.Settings;
+import android.util.IndentingPrintWriter;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
@@ -139,7 +140,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
@Nullable String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- mTimeDetectorStrategy.dump(pw, args);
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
+ mTimeDetectorStrategy.dump(ipw, args);
+ ipw.flush();
}
private void enforceSuggestTelephonyTimePermission() {
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 9a39d2418994..e943978cfc14 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -17,25 +17,25 @@
package com.android.server.timedetector;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.os.TimestampedValue;
+import android.util.IndentingPrintWriter;
-import java.io.PrintWriter;
+import com.android.server.timezonedetector.Dumpable;
/**
* The interface for the class that implements the time detection algorithm used by the
* {@link TimeDetectorService}.
*
* <p>Most calls will be handled by a single thread but that is not true for all calls. For example
- * {@link #dump(PrintWriter, String[])}) may be called on a different thread so implementations must
- * handle thread safety.
+ * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread so
+ * implementations must handle thread safety.
*
* @hide
*/
-public interface TimeDetectorStrategy {
+public interface TimeDetectorStrategy extends Dumpable {
/**
* The interface used by the strategy to interact with the surrounding service.
@@ -94,9 +94,6 @@ public interface TimeDetectorStrategy {
/** Handle the auto-time setting being toggled on or off. */
void handleAutoTimeDetectionChanged();
- /** Dump debug information. */
- void dump(@NonNull PrintWriter pw, @Nullable String[] args);
-
// Utility methods below are to be moved to a better home when one becomes more obvious.
/**
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index ceb548551635..fe0e82e66093 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -24,16 +24,15 @@ import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.os.TimestampedValue;
+import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.server.timezonedetector.ArrayMapWithHistory;
import com.android.server.timezonedetector.ReferenceWithHistory;
-import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -203,8 +202,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
@Override
- public synchronized void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
- IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ public synchronized void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
ipw.println("TimeDetectorStrategy:");
ipw.increaseIndent(); // level 1
@@ -232,7 +230,6 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
ipw.decreaseIndent(); // level 2
ipw.decreaseIndent(); // level 1
- ipw.flush();
}
@GuardedBy("this")
diff --git a/services/core/java/com/android/server/timezonedetector/ArrayMapWithHistory.java b/services/core/java/com/android/server/timezonedetector/ArrayMapWithHistory.java
index 3274f0e1112f..d6fdddf4ee43 100644
--- a/services/core/java/com/android/server/timezonedetector/ArrayMapWithHistory.java
+++ b/services/core/java/com/android/server/timezonedetector/ArrayMapWithHistory.java
@@ -20,10 +20,10 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArrayMap;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
/**
* A partial decorator for {@link ArrayMap} that records historic values for each mapping for
diff --git a/services/core/java/com/android/server/timezonedetector/Dumpable.java b/services/core/java/com/android/server/timezonedetector/Dumpable.java
index 58a5a0b517f8..5603c38bd0ae 100644
--- a/services/core/java/com/android/server/timezonedetector/Dumpable.java
+++ b/services/core/java/com/android/server/timezonedetector/Dumpable.java
@@ -15,24 +15,27 @@
*/
package com.android.server.timezonedetector;
-import java.io.PrintWriter;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.IndentingPrintWriter;
/** An interface for components that can write their internal state to dumpsys logs. */
public interface Dumpable {
/** Dump internal state. */
- void dump(PrintWriter pw, String[] args);
+ void dump(@NonNull IndentingPrintWriter pw, @Nullable String[] args);
/**
* An interface that can be used expose when one component allows another to be registered so
* that it is dumped at the same time.
*/
- interface Dumpee {
+ interface Container {
/**
* Registers the supplied {@link Dumpable}. When the implementation is dumped
- * {@link Dumpable#dump(PrintWriter, String[])} should be called on the {@code dumpable}.
+ * {@link Dumpable#dump(IndentingPrintWriter, String[])} should be called on the
+ * {@code dumpable}.
*/
- void addDumpable(Dumpable dumpable);
+ void addDumpable(@NonNull Dumpable dumpable);
}
}
diff --git a/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java b/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
index 165419a7a38b..b63df05ad7a1 100644
--- a/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
+++ b/services/core/java/com/android/server/timezonedetector/ReferenceWithHistory.java
@@ -19,8 +19,7 @@ package com.android.server.timezonedetector;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-
-import com.android.internal.util.IndentingPrintWriter;
+import android.util.IndentingPrintWriter;
import java.util.ArrayDeque;
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
index d833586dc2dd..3d9ec6475a8b 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternal.java
@@ -24,7 +24,7 @@ import android.annotation.NonNull;
*
* @hide
*/
-public interface TimeZoneDetectorInternal extends Dumpable.Dumpee {
+public interface TimeZoneDetectorInternal extends Dumpable.Container {
/**
* Suggests the current time zone, determined using geolocation, to the detector. The
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
index d8db1ba0eb43..4464f7d136e3 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorInternalImpl.java
@@ -49,7 +49,7 @@ public final class TimeZoneDetectorInternalImpl implements TimeZoneDetectorInter
}
@Override
- public void addDumpable(Dumpable dumpable) {
+ public void addDumpable(@NonNull Dumpable dumpable) {
mTimeZoneDetectorStrategy.addDumpable(dumpable);
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index bb4f56d76943..d9415ce81636 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -36,6 +36,7 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -118,7 +119,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
new ContentObserver(handler) {
public void onChange(boolean selfChange) {
- service.handleAutoTimeZoneDetectionChanged();
+ service.handleAutoTimeZoneConfigChanged();
}
});
return service;
@@ -272,12 +273,14 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
@Nullable String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- mTimeZoneDetectorStrategy.dump(pw, args);
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
+ mTimeZoneDetectorStrategy.dump(ipw, args);
+ ipw.flush();
}
/** Internal method for handling the auto time zone configuration being changed. */
@VisibleForTesting
- public void handleAutoTimeZoneDetectionChanged() {
+ public void handleAutoTimeZoneConfigChanged() {
mHandler.post(mTimeZoneDetectorStrategy::handleAutoTimeZoneConfigChanged);
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index 497ff3efc4b8..f947a6554412 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -21,8 +21,7 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
-
-import java.io.PrintWriter;
+import android.util.IndentingPrintWriter;
/**
* The interface for the class that implements the time detection algorithm used by the
@@ -32,12 +31,12 @@ import java.io.PrintWriter;
* and what to set it to.
*
* <p>Most calls will be handled by a single thread but that is not true for all calls. For example
- * {@link #dump(PrintWriter, String[])}) may be called on a different thread so implementations must
- * handle thread safety.
+ * {@link #dump(IndentingPrintWriter, String[])}) may be called on a different thread so
+ * implementations mustvhandle thread safety.
*
* @hide
*/
-public interface TimeZoneDetectorStrategy extends Dumpable.Dumpee {
+public interface TimeZoneDetectorStrategy extends Dumpable, Dumpable.Container {
/** A listener for strategy events. */
interface StrategyListener {
@@ -91,9 +90,4 @@ public interface TimeZoneDetectorStrategy extends Dumpable.Dumpee {
* Called when there has been a change to the automatic time zone detection configuration.
*/
void handleAutoTimeZoneConfigChanged();
-
- /**
- * Dumps internal state such as field values.
- */
- void dump(PrintWriter pw, String[] args);
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index ab9a773d3b8c..9c36c3921e3e 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -32,14 +32,13 @@ import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
import android.content.Context;
+import android.util.IndentingPrintWriter;
import android.util.LocalLog;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -517,7 +516,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
}
@Override
- public synchronized void addDumpable(Dumpable dumpable) {
+ public synchronized void addDumpable(@NonNull Dumpable dumpable) {
mDumpables.add(dumpable);
}
@@ -525,8 +524,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
* Dumps internal state such as field values.
*/
@Override
- public synchronized void dump(PrintWriter pw, String[] args) {
- IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ public synchronized void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
ipw.println("TimeZoneDetectorStrategy:");
ipw.increaseIndent(); // level 1
@@ -549,7 +547,6 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat
for (Dumpable dumpable : mDumpables) {
dumpable.dump(ipw, args);
}
- ipw.flush();
}
/**
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 5f6323369d0a..f5eed30a19bf 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -114,7 +114,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
private static final boolean DEBUG = false;
private static final String TAG = "UriGrantsManagerService";
// Maximum number of persisted Uri grants a package is allowed
- private static final int MAX_PERSISTED_URI_GRANTS = 128;
+ private static final int MAX_PERSISTED_URI_GRANTS = 512;
private static final boolean ENABLE_DYNAMIC_PERMISSIONS = true;
private final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index f5d68031b493..ecba3f9c27c4 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1357,7 +1357,12 @@ final class AccessibilityController {
addedWindows.clear();
// Gets the top focused display Id and window token for supporting multi-display.
- topFocusedDisplayId = mService.mRoot.getTopFocusedDisplayContent().getDisplayId();
+ // If this top focused display is an embedded one, using its parent display as the
+ // top focused display.
+ final DisplayContent topFocusedDisplayContent =
+ mService.mRoot.getTopFocusedDisplayContent();
+ topFocusedDisplayId = isEmbeddedDisplay(topFocusedDisplayContent) ? mDisplayId
+ : topFocusedDisplayContent.getDisplayId();
topFocusedWindowToken = topFocusedWindowState.mClient.asBinder();
}
mCallback.onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2d50012ed580..a87fe615e4df 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4605,8 +4605,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
- final boolean behindFullscreenActivity = stack.checkBehindFullscreenActivity(
- this, null /* handleBehindFullscreenActivity */);
+ final boolean behindFullscreenActivity = !stack.shouldBeVisible(null /* starting */)
+ || stack.getOccludingActivityAbove(this) != null;
return shouldBeVisible(behindFullscreenActivity, false /* ignoringKeyguard */);
}
@@ -7516,22 +7516,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
- * @return {@code true} if this is the resumed activity on its current display, {@code false}
+ * @return {@code true} if this is the focused activity on its current display, {@code false}
* otherwise.
*/
- boolean isResumedActivityOnDisplay() {
+ boolean isFocusedActivityOnDisplay() {
final DisplayContent display = getDisplay();
if (display == null) {
return false;
}
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- final ActivityRecord resumedActivity = taskDisplayArea.getFocusedActivity();
- if (resumedActivity != null) {
- return resumedActivity == this;
- }
- }
- return false;
+ return display.forAllTaskDisplayAreas(taskDisplayArea ->
+ taskDisplayArea.getFocusedActivity() == this);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 3a24abd02064..ea9aab71bcb0 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -328,81 +328,6 @@ class ActivityStack extends Task {
}
}
- private final CheckBehindFullscreenActivityHelper mCheckBehindFullscreenActivityHelper =
- new CheckBehindFullscreenActivityHelper();
- private class CheckBehindFullscreenActivityHelper {
- private boolean mAboveTop;
- private boolean mBehindFullscreenActivity;
- private ActivityRecord mToCheck;
- private Consumer<ActivityRecord> mHandleBehindFullscreenActivity;
- private boolean mHandlingOccluded;
-
- private void reset(ActivityRecord toCheck,
- Consumer<ActivityRecord> handleBehindFullscreenActivity) {
- mToCheck = toCheck;
- mHandleBehindFullscreenActivity = handleBehindFullscreenActivity;
- mAboveTop = true;
- mBehindFullscreenActivity = false;
-
- if (!shouldBeVisible(null)) {
- // The stack is not visible, so no activity in it should be displaying a starting
- // window. Mark all activities below top and behind fullscreen.
- mAboveTop = false;
- mBehindFullscreenActivity = true;
- }
-
- mHandlingOccluded = mToCheck == null && mHandleBehindFullscreenActivity != null;
- }
-
- boolean process(ActivityRecord toCheck,
- Consumer<ActivityRecord> handleBehindFullscreenActivity) {
- reset(toCheck, handleBehindFullscreenActivity);
-
- if (!mHandlingOccluded && mBehindFullscreenActivity) {
- return true;
- }
-
- final ActivityRecord topActivity = topRunningActivity();
- final PooledFunction f = PooledLambda.obtainFunction(
- CheckBehindFullscreenActivityHelper::processActivity, this,
- PooledLambda.__(ActivityRecord.class), topActivity);
- forAllActivities(f);
- f.recycle();
-
- return mBehindFullscreenActivity;
- }
-
- /** Returns {@code true} to stop the outer loop and indicate the result is computed. */
- private boolean processActivity(ActivityRecord r, ActivityRecord topActivity) {
- if (mAboveTop) {
- if (r == topActivity) {
- if (r == mToCheck) {
- // It is the top activity in a visible stack.
- mBehindFullscreenActivity = false;
- return true;
- }
- mAboveTop = false;
- }
- mBehindFullscreenActivity |= r.occludesParent();
- return false;
- }
-
- if (mHandlingOccluded) {
- // Iterating through all occluded activities.
- if (mBehindFullscreenActivity) {
- mHandleBehindFullscreenActivity.accept(r);
- }
- } else if (r == mToCheck) {
- return true;
- } else if (mBehindFullscreenActivity) {
- // It is occluded before {@param toCheck} is found.
- return true;
- }
- mBehindFullscreenActivity |= r.occludesParent();
- return false;
- }
- }
-
// TODO: Can we just loop through WindowProcessController#mActivities instead of doing this?
private final RemoveHistoryRecordsForApp mRemoveHistoryRecordsForApp =
new RemoveHistoryRecordsForApp();
@@ -1434,25 +1359,6 @@ class ActivityStack extends Task {
}
}
- /** @see ActivityRecord#cancelInitializing() */
- void cancelInitializingActivities() {
- // We don't want to clear starting window for activities that aren't behind fullscreen
- // activities as we need to display their starting window until they are done initializing.
- checkBehindFullscreenActivity(null /* toCheck */, ActivityRecord::cancelInitializing);
- }
-
- /**
- * If an activity {@param toCheck} is given, this method returns {@code true} if the activity
- * is occluded by any fullscreen activity. If there is no {@param toCheck} and the handling
- * function {@param handleBehindFullscreenActivity} is given, this method will pass all occluded
- * activities to the function.
- */
- boolean checkBehindFullscreenActivity(ActivityRecord toCheck,
- Consumer<ActivityRecord> handleBehindFullscreenActivity) {
- return mCheckBehindFullscreenActivityHelper.process(
- toCheck, handleBehindFullscreenActivity);
- }
-
/**
* Ensure that the top activity in the stack is resumed.
*
@@ -2414,7 +2320,7 @@ class ActivityStack extends Task {
forAllActivities(ActivityRecord::removeLaunchTickRunnable);
}
- private void updateTransitLocked(int transit, ActivityOptions options) {
+ private void updateTransitLocked(int transit, ActivityOptions options, boolean forceOverride) {
if (options != null) {
ActivityRecord r = topRunningActivity();
if (r != null && !r.isState(RESUMED)) {
@@ -2423,7 +2329,8 @@ class ActivityStack extends Task {
ActivityOptions.abort(options);
}
}
- getDisplay().mDisplayContent.prepareAppTransition(transit, false);
+ getDisplay().mDisplayContent.prepareAppTransition(transit, false,
+ 0 /* flags */, forceOverride);
}
final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,
@@ -2443,8 +2350,17 @@ class ActivityStack extends Task {
// nothing to do!
if (noAnimation) {
ActivityOptions.abort(options);
+ } else if (isSingleTaskInstance()) {
+ // When a task is moved front on the display which can only contain one task, start
+ // a special transition.
+ // {@link AppTransitionController#handleAppTransitionReady} later picks up the
+ // transition, and schedules
+ // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is triggered
+ // after contents are drawn on the display.
+ updateTransitLocked(TRANSIT_SHOW_SINGLE_TASK_DISPLAY, options,
+ true /* forceOverride */);
} else {
- updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
+ updateTransitLocked(TRANSIT_TASK_TO_FRONT, options, false /* forceOverride */);
}
return;
}
@@ -2490,9 +2406,13 @@ class ActivityStack extends Task {
mStackSupervisor.mNoAnimActivities.add(r);
}
ActivityOptions.abort(options);
+ } else if (isSingleTaskInstance()) {
+ updateTransitLocked(TRANSIT_SHOW_SINGLE_TASK_DISPLAY, options,
+ true /* forceOverride */);
} else {
- updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
+ updateTransitLocked(TRANSIT_TASK_TO_FRONT, options, false /* forceOverride */);
}
+
// If a new task is moved to the front, then mark the existing top activity as
// supporting
@@ -2646,16 +2566,6 @@ class ActivityStack extends Task {
task.setBounds(task.isResizeable() ? bounds : null);
}
- /**
- * Returns the top-most activity that occludes the given one, or @{code null} if none.
- */
- @Nullable
- private ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
- ActivityRecord top = getActivity((ar) -> ar.occludesParent(),
- true /* traverseTopToBottom */, activity);
- return top != activity ? top : null;
- }
-
boolean willActivityBeVisible(IBinder token) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r == null) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index bf85db2e9700..4e1d789bebd8 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -218,7 +218,6 @@ import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
import android.sysprop.DisplayProperties;
import android.telecom.TelecomManager;
-import android.text.TextUtils;
import android.text.format.TimeMigrationUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1956,7 +1955,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
r.immersive = immersive;
// update associated state if we're frontmost
- if (r.isResumedActivityOnDisplay()) {
+ if (r.isFocusedActivityOnDisplay()) {
if (DEBUG_IMMERSIVE) Slog.d(TAG_IMMERSIVE, "Frontmost changed immersion: "+ r);
applyUpdateLockStateLocked(r);
}
@@ -4007,8 +4006,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
ActivityRecord record = ActivityRecord.isInStackLocked(token);
if (record == null) {
- throw new IllegalArgumentException("reportSizeConfigurations: ActivityRecord not "
- + "found for: " + token);
+ return;
}
record.setSizeConfigurations(horizontalSizeConfiguration,
verticalSizeConfigurations, smallestSizeConfigurations);
@@ -4322,7 +4320,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
r.requestedVrComponent = (enabled) ? packageName : null;
// Update associated state if this activity is currently focused
- if (r.isResumedActivityOnDisplay()) {
+ if (r.isFocusedActivityOnDisplay()) {
applyUpdateVrModeLocked(r);
}
return 0;
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 98522082e1c6..201473e764c7 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -30,6 +30,7 @@ import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA;
+import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
@@ -40,7 +41,9 @@ import com.android.server.policy.WindowManagerPolicy;
import com.android.server.protolog.common.ProtoLog;
import java.util.Comparator;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Predicate;
/**
@@ -139,11 +142,108 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
return DISPLAY_AREA;
}
+ @Override
+ final DisplayArea asDisplayArea() {
+ return this;
+ }
+
+ @Override
void forAllDisplayAreas(Consumer<DisplayArea> callback) {
super.forAllDisplayAreas(callback);
callback.accept(this);
}
+ @Override
+ boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback,
+ boolean traverseTopToBottom) {
+ // Only DisplayArea of Type.ANY may contain TaskDisplayArea as children.
+ if (mType != DisplayArea.Type.ANY) {
+ return false;
+ }
+
+ int childCount = mChildren.size();
+ int i = traverseTopToBottom ? childCount - 1 : 0;
+ while (i >= 0 && i < childCount) {
+ T child = mChildren.get(i);
+ // Only traverse if the child is a DisplayArea.
+ if (child.asDisplayArea() != null && child.asDisplayArea()
+ .forAllTaskDisplayAreas(callback, traverseTopToBottom)) {
+ return true;
+ }
+ i += traverseTopToBottom ? -1 : 1;
+ }
+ return false;
+ }
+
+ @Override
+ void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom) {
+ // Only DisplayArea of Type.ANY may contain TaskDisplayArea as children.
+ if (mType != DisplayArea.Type.ANY) {
+ return;
+ }
+
+ int childCount = mChildren.size();
+ int i = traverseTopToBottom ? childCount - 1 : 0;
+ while (i >= 0 && i < childCount) {
+ T child = mChildren.get(i);
+ // Only traverse if the child is a DisplayArea.
+ if (child.asDisplayArea() != null) {
+ child.asDisplayArea().forAllTaskDisplayAreas(callback, traverseTopToBottom);
+ }
+ i += traverseTopToBottom ? -1 : 1;
+ }
+ }
+
+ @Nullable
+ @Override
+ <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator,
+ @Nullable R initValue, boolean traverseTopToBottom) {
+ // Only DisplayArea of Type.ANY may contain TaskDisplayArea as children.
+ if (mType != DisplayArea.Type.ANY) {
+ return initValue;
+ }
+
+ int childCount = mChildren.size();
+ int i = traverseTopToBottom ? childCount - 1 : 0;
+ R result = initValue;
+ while (i >= 0 && i < childCount) {
+ T child = mChildren.get(i);
+ // Only traverse if the child is a DisplayArea.
+ if (child.asDisplayArea() != null) {
+ result = (R) child.asDisplayArea()
+ .reduceOnAllTaskDisplayAreas(accumulator, result, traverseTopToBottom);
+ }
+ i += traverseTopToBottom ? -1 : 1;
+ }
+ return result;
+ }
+
+ @Nullable
+ @Override
+ <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback,
+ boolean traverseTopToBottom) {
+ // Only DisplayArea of Type.ANY may contain TaskDisplayArea as children.
+ if (mType != DisplayArea.Type.ANY) {
+ return null;
+ }
+
+ int childCount = mChildren.size();
+ int i = traverseTopToBottom ? childCount - 1 : 0;
+ while (i >= 0 && i < childCount) {
+ T child = mChildren.get(i);
+ // Only traverse if the child is a DisplayArea.
+ if (child.asDisplayArea() != null) {
+ R result = (R) child.asDisplayArea()
+ .getItemFromTaskDisplayAreas(callback, traverseTopToBottom);
+ if (result != null) {
+ return result;
+ }
+ }
+ i += traverseTopToBottom ? -1 : 1;
+ }
+ return null;
+ }
+
void setOrganizer(IDisplayAreaOrganizer organizer) {
if (mOrganizer == organizer) return;
IDisplayAreaOrganizer lastOrganizer = mOrganizer;
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index 709e45368b19..a161acaa9cc5 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -63,16 +63,6 @@ public abstract class DisplayAreaPolicy {
*/
public abstract List<DisplayArea<? extends WindowContainer>> getDisplayAreas(int featureId);
- /**
- * @return the number of task display areas on the display.
- */
- public abstract int getTaskDisplayAreaCount();
-
- /**
- * @return the task display area at index.
- */
- public abstract TaskDisplayArea getTaskDisplayAreaAt(int index);
-
/** Provider for platform-default display area policy. */
static final class DefaultProvider implements DisplayAreaPolicy.Provider {
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 3de7b60e68ae..465d089e7904 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -23,20 +23,24 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
+import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import android.annotation.Nullable;
+import android.os.Bundle;
import android.util.ArrayMap;
+import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import com.android.server.policy.WindowManagerPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
+import java.util.Set;
+import java.util.function.BiFunction;
/**
* A builder for instantiating a complex {@link DisplayAreaPolicy}
@@ -70,22 +74,93 @@ import java.util.Objects;
*/
class DisplayAreaPolicyBuilder {
@Nullable private HierarchyBuilder mRootHierarchyBuilder;
+ private ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders = new ArrayList<>();
- /** Defines the root hierarchy. */
+ /**
+ * When a window is created, the policy will use this function to select the
+ * {@link RootDisplayArea} to place that window in. The selected root can be either the one of
+ * the {@link #mRootHierarchyBuilder} or the one of any of the
+ * {@link #mDisplayAreaGroupHierarchyBuilders}.
+ **/
+ @Nullable private BiFunction<WindowToken, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
+
+ /** Defines the root hierarchy for the whole logical display. */
DisplayAreaPolicyBuilder setRootHierarchy(HierarchyBuilder rootHierarchyBuilder) {
- // TODO(b/157683117): Add method to add sub root and root choosing func.
mRootHierarchyBuilder = rootHierarchyBuilder;
return this;
}
+ /**
+ * Defines a DisplayAreaGroup hierarchy. Its root will be added as a child of the root
+ * hierarchy.
+ */
+ DisplayAreaPolicyBuilder addDisplayAreaGroupHierarchy(
+ HierarchyBuilder displayAreaGroupHierarchy) {
+ mDisplayAreaGroupHierarchyBuilders.add(displayAreaGroupHierarchy);
+ return this;
+ }
+
+ /** The policy will use this function to find the root to place windows in. */
+ DisplayAreaPolicyBuilder setSelectRootForWindowFunc(
+ BiFunction<WindowToken, Bundle, RootDisplayArea> selectRootForWindowFunc) {
+ mSelectRootForWindowFunc = selectRootForWindowFunc;
+ return this;
+ }
+
+ /** Makes sure the setting meets the requirement. */
+ private void validate() {
+ if (mRootHierarchyBuilder == null) {
+ throw new IllegalStateException("Root must be set for the display area policy.");
+ }
+
+ boolean containsImeContainer = mRootHierarchyBuilder.mImeContainer != null;
+ boolean containsDefaultTda = containsDefaultTaskDisplayArea(mRootHierarchyBuilder);
+ for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
+ HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
+ if (hierarchyBuilder.mTaskDisplayAreas.isEmpty()) {
+ throw new IllegalStateException(
+ "DisplayAreaGroup must contain at least one TaskDisplayArea.");
+ }
+
+ containsImeContainer = containsImeContainer || hierarchyBuilder.mImeContainer != null;
+ containsDefaultTda = containsDefaultTda
+ || containsDefaultTaskDisplayArea(hierarchyBuilder);
+ }
+
+ if (!containsImeContainer) {
+ throw new IllegalStateException("IME container must be set.");
+ }
+
+ if (!containsDefaultTda) {
+ throw new IllegalStateException("There must be a default TaskDisplayArea.");
+ }
+ }
+
+ /** Checks if the given hierarchy contains the default {@link TaskDisplayArea}. */
+ private static boolean containsDefaultTaskDisplayArea(HierarchyBuilder displayAreaHierarchy) {
+ for (int i = 0; i < displayAreaHierarchy.mTaskDisplayAreas.size(); i++) {
+ if (displayAreaHierarchy.mTaskDisplayAreas.get(i).mFeatureId
+ == FEATURE_DEFAULT_TASK_CONTAINER) {
+ return true;
+ }
+ }
+ return false;
+ }
+
Result build(WindowManagerService wmService) {
- Objects.requireNonNull(mRootHierarchyBuilder,
- "Root must be set for the display area policy.");
- Objects.requireNonNull(mRootHierarchyBuilder.mImeContainer, "Ime must not be null");
- Preconditions.checkCollectionNotEmpty(mRootHierarchyBuilder.mTaskDisplayAreas,
- "TaskDisplayAreas must not be empty");
- mRootHierarchyBuilder.build();
- return new Result(wmService, mRootHierarchyBuilder.mRoot);
+ validate();
+
+ // Attach DA group roots to screen hierarchy before adding windows to group hierarchies.
+ mRootHierarchyBuilder.build(mDisplayAreaGroupHierarchyBuilders);
+ List<RootDisplayArea> displayAreaGroupRoots = new ArrayList<>(
+ mDisplayAreaGroupHierarchyBuilders.size());
+ for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
+ HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
+ hierarchyBuilder.build();
+ displayAreaGroupRoots.add(hierarchyBuilder.mRoot);
+ }
+ return new Result(wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots,
+ mSelectRootForWindowFunc);
}
/**
@@ -131,6 +206,14 @@ class DisplayAreaPolicyBuilder {
/** Builds the {@link DisplayArea} hierarchy below root. */
private void build() {
+ build(null /* displayAreaGroupHierarchyBuilders */);
+ }
+
+ /**
+ * Builds the {@link DisplayArea} hierarchy below root. And adds the roots of those
+ * {@link HierarchyBuilder} as children.
+ */
+ private void build(@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
final WindowManagerPolicy policy = mRoot.mWmService.mPolicy;
final int maxWindowLayerCount = policy.getMaxWindowLayer();
final DisplayArea.Tokens[] displayAreaForLayer =
@@ -215,7 +298,9 @@ class DisplayAreaPolicyBuilder {
if (leafType == LEAF_TYPE_TASK_CONTAINERS) {
// We use the passed in TaskDisplayAreas for task container type of layer.
// Skip creating Tokens even if there is no TDA.
- addTaskDisplayAreasToLayer(areaForLayer[layer]);
+ addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]);
+ addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer],
+ displayAreaGroupHierarchyBuilders);
leafArea.mSkipTokens = true;
} else if (leafType == LEAF_TYPE_IME_CONTAINERS) {
// We use the passed in ImeContainer for ime container type of layer.
@@ -234,11 +319,11 @@ class DisplayAreaPolicyBuilder {
// Notify the root that we have finished attaching all the DisplayAreas. Cache all the
// feature related collections there for fast access.
- mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas, mTaskDisplayAreas);
+ mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);
}
- /** Adds all {@link TaskDisplayArea} to the specified layer */
- private void addTaskDisplayAreasToLayer(PendingArea parentPendingArea) {
+ /** Adds all {@link TaskDisplayArea} to the application layer. */
+ private void addTaskDisplayAreasToApplicationLayer(PendingArea parentPendingArea) {
final int count = mTaskDisplayAreas.size();
for (int i = 0; i < count; i++) {
PendingArea leafArea =
@@ -249,6 +334,24 @@ class DisplayAreaPolicyBuilder {
}
}
+ /** Adds roots of the DisplayAreaGroups to the application layer. */
+ private void addDisplayAreaGroupsToApplicationLayer(
+ DisplayAreaPolicyBuilder.PendingArea parentPendingArea,
+ @Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) {
+ if (displayAreaGroupHierarchyBuilders == null) {
+ return;
+ }
+ final int count = displayAreaGroupHierarchyBuilders.size();
+ for (int i = 0; i < count; i++) {
+ DisplayAreaPolicyBuilder.PendingArea
+ leafArea = new DisplayAreaPolicyBuilder.PendingArea(
+ null /* feature */, APPLICATION_LAYER, parentPendingArea);
+ leafArea.mExisting = displayAreaGroupHierarchyBuilders.get(i).mRoot;
+ leafArea.mMaxLayer = APPLICATION_LAYER;
+ parentPendingArea.mChildren.add(leafArea);
+ }
+ }
+
private static int typeOfLayer(WindowManagerPolicy policy, int layer) {
if (layer == APPLICATION_LAYER) {
return LEAF_TYPE_TASK_CONTAINERS;
@@ -401,9 +504,20 @@ class DisplayAreaPolicyBuilder {
}
static class Result extends DisplayAreaPolicy {
+ final List<RootDisplayArea> mDisplayAreaGroupRoots;
+ final BiFunction<WindowToken, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
- Result(WindowManagerService wmService, RootDisplayArea root) {
+ Result(WindowManagerService wmService, RootDisplayArea root,
+ List<RootDisplayArea> displayAreaGroupRoots,
+ @Nullable BiFunction<WindowToken, Bundle, RootDisplayArea>
+ selectRootForWindowFunc) {
super(wmService, root);
+ mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
+ mSelectRootForWindowFunc = selectRootForWindowFunc == null
+ // Always return the highest level root of the logical display when the func is
+ // not specified.
+ ? (window, options) -> mRoot
+ : selectRootForWindowFunc;
}
@Override
@@ -414,39 +528,38 @@ class DisplayAreaPolicyBuilder {
@VisibleForTesting
DisplayArea.Tokens findAreaForToken(WindowToken token) {
- // TODO(b/157683117): Choose root/sub root from OEM provided func.
- return mRoot.findAreaForToken(token);
+ return mSelectRootForWindowFunc.apply(token, token.mOptions).findAreaForToken(token);
}
@VisibleForTesting
List<Feature> getFeatures() {
- // TODO(b/157683117): Also get feature from sub root.
- return new ArrayList<>(mRoot.mFeatures);
+ Set<Feature> features = new ArraySet<>();
+ features.addAll(mRoot.mFeatures);
+ for (int i = 0; i < mDisplayAreaGroupRoots.size(); i++) {
+ features.addAll(mDisplayAreaGroupRoots.get(i).mFeatures);
+ }
+ return new ArrayList<>(features);
}
@Override
public List<DisplayArea<? extends WindowContainer>> getDisplayAreas(int featureId) {
- // TODO(b/157683117): Also get display areas from sub root.
- List<Feature> features = getFeatures();
+ List<DisplayArea<? extends WindowContainer>> displayAreas = new ArrayList<>();
+ getDisplayAreas(mRoot, featureId, displayAreas);
+ for (int i = 0; i < mDisplayAreaGroupRoots.size(); i++) {
+ getDisplayAreas(mDisplayAreaGroupRoots.get(i), featureId, displayAreas);
+ }
+ return displayAreas;
+ }
+
+ private static void getDisplayAreas(RootDisplayArea root, int featureId,
+ List<DisplayArea<? extends WindowContainer>> displayAreas) {
+ List<Feature> features = root.mFeatures;
for (int i = 0; i < features.size(); i++) {
Feature feature = features.get(i);
if (feature.mId == featureId) {
- return new ArrayList<>(mRoot.mFeatureToDisplayAreas.get(feature));
+ displayAreas.addAll(root.mFeatureToDisplayAreas.get(feature));
}
}
- return new ArrayList<>();
- }
-
- @Override
- public int getTaskDisplayAreaCount() {
- // TODO(b/157683117): Also add TDA from sub root.
- return mRoot.mTaskDisplayAreas.size();
- }
-
- @Override
- public TaskDisplayArea getTaskDisplayAreaAt(int index) {
- // TODO(b/157683117): Get TDA from root/sub root based on their z-order.
- return mRoot.mTaskDisplayAreas.get(index);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4f25609c77dd..0a3b884f79d0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -71,6 +71,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
@@ -910,7 +911,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* @param root {@link RootWindowContainer}
*/
DisplayContent(Display display, RootWindowContainer root) {
- super(root.mWindowManager);
+ super(root.mWindowManager, "DisplayContent", FEATURE_ROOT);
if (mWmService.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists="
@@ -2191,52 +2192,27 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* Returns the topmost stack on the display that is compatible with the input windowing mode and
* activity type. Null is no compatible stack on the display.
*/
+ @Nullable
ActivityStack getStack(int windowingMode, int activityType) {
- for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final ActivityStack stack = getTaskDisplayAreaAt(tdaNdx)
- .getStack(windowingMode, activityType);
- if (stack != null) {
- return stack;
- }
- }
- return null;
- }
-
- protected int getTaskDisplayAreaCount() {
- return mDisplayAreaPolicy.getTaskDisplayAreaCount();
- }
-
- protected TaskDisplayArea getTaskDisplayAreaAt(int index) {
- return mDisplayAreaPolicy.getTaskDisplayAreaAt(index);
+ return getItemFromTaskDisplayAreas(taskDisplayArea ->
+ taskDisplayArea.getStack(windowingMode, activityType));
}
+ @Nullable
ActivityStack getStack(int rootTaskId) {
- for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final ActivityStack stack = getTaskDisplayAreaAt(tdaNdx).getStack(rootTaskId);
- if (stack != null) {
- return stack;
- }
- }
- return null;
+ return getItemFromTaskDisplayAreas(taskDisplayArea ->
+ taskDisplayArea.getStack(rootTaskId));
}
protected int getStackCount() {
- int totalStackCount = 0;
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- totalStackCount += getTaskDisplayAreaAt(i).getStackCount();
- }
- return totalStackCount;
+ return reduceOnAllTaskDisplayAreas((taskDisplayArea, count) ->
+ count + taskDisplayArea.getStackCount(), 0 /* initValue */);
}
@VisibleForTesting
+ @Nullable
ActivityStack getTopStack() {
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getTaskDisplayAreaAt(i).getTopStack();
- if (stack != null) {
- return stack;
- }
- }
- return null;
+ return getItemFromTaskDisplayAreas(TaskDisplayArea::getTopStack);
}
/**
@@ -2536,7 +2512,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* or for cases when multi-instance is not supported yet (like Split-screen, PiP or Recents).
*/
TaskDisplayArea getDefaultTaskDisplayArea() {
- return mDisplayAreaPolicy.getTaskDisplayAreaAt(0);
+ return getItemFromTaskDisplayAreas(taskDisplayArea -> taskDisplayArea,
+ false /* traverseTopToBottom */);
}
void positionDisplayAt(int position, boolean includingParents) {
@@ -2755,9 +2732,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
void prepareFreezingTaskBounds() {
- for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- getTaskDisplayAreaAt(tdaNdx).prepareFreezingTaskBounds();
- }
+ forAllTaskDisplayAreas(TaskDisplayArea::prepareFreezingTaskBounds);
}
void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
@@ -2952,9 +2927,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
pw.println();
pw.println(prefix + "Task display areas in top down Z order:");
- for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- getTaskDisplayAreaAt(tdaNdx).dump(pw, prefix + " ", dumpAll);
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ taskDisplayArea.dump(pw, prefix + " ", dumpAll);
+ });
pw.println();
if (!mExitingTokens.isEmpty()) {
@@ -3519,12 +3494,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- private void updateImeControlTarget() {
+ void updateImeControlTarget() {
mInputMethodControlTarget = computeImeControlTarget();
mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
- final WindowState win = mInputMethodControlTarget != null
- ? mInputMethodControlTarget.getWindow() : null;
+ final WindowState win = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget);
final IBinder token = win != null ? win.mClient.asBinder() : null;
// Note: not allowed to call into IMMS with the WM lock held, hence the post.
mWmService.mH.post(() ->
@@ -3548,6 +3522,17 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null) {
return mRemoteInsetsControlTarget;
} else {
+ // Now, a special case -- if the last target's window is in the process of exiting, but
+ // not removed, keep on the last target to avoid IME flicker.
+ final WindowState cur = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget);
+ if (cur != null && !cur.mRemoved && cur.isDisplayedLw() && cur.isClosing()
+ && !cur.isActivityTypeHome()) {
+ if (DEBUG_INPUT_METHOD) {
+ Slog.v(TAG_WM, "Not changing control while current window"
+ + " is closing and not removed");
+ }
+ return cur;
+ }
// Otherwise, we just use the ime target as received from IME.
return mInputMethodInputTarget;
}
@@ -4126,9 +4111,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
// Initialize state of exiting applications.
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- getTaskDisplayAreaAt(i).setExitingTokensHasVisible(hasVisible);
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ taskDisplayArea.setExitingTokensHasVisible(hasVisible);
+ });
}
void removeExistingTokensIfPossible() {
@@ -4140,9 +4125,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
// Time to remove any exiting applications?
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- getTaskDisplayAreaAt(i).removeExistingAppTokensIfPossible();
- }
+ forAllTaskDisplayAreas(TaskDisplayArea::removeExistingAppTokensIfPossible);
}
@Override
@@ -4466,9 +4449,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
void assignStackOrdering() {
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- getTaskDisplayAreaAt(i).assignStackOrdering(getPendingTransaction());
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ taskDisplayArea.assignStackOrdering(getPendingTransaction());
+ });
}
/**
@@ -5010,13 +4993,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
@Nullable
ActivityStack getFocusedStack() {
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- final ActivityStack stack = getTaskDisplayAreaAt(i).getFocusedStack();
- if (stack != null) {
- return stack;
- }
- }
- return null;
+ return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedStack);
}
/**
@@ -5024,15 +5001,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
*/
void removeStacksInWindowingModes(int... windowingModes) {
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- getTaskDisplayAreaAt(i).removeStacksInWindowingModes(windowingModes);
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ taskDisplayArea.removeStacksInWindowingModes(windowingModes);
+ });
}
void removeStacksWithActivityTypes(int... activityTypes) {
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- getTaskDisplayAreaAt(i).removeStacksWithActivityTypes(activityTypes);
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ taskDisplayArea.removeStacksWithActivityTypes(activityTypes);
+ });
}
ActivityRecord topRunningActivity() {
@@ -5048,15 +5025,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* can be shown on top of the keyguard will be considered.
* @return The top running activity. {@code null} if none is available.
*/
+ @Nullable
ActivityRecord topRunningActivity(boolean considerKeyguardState) {
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- final ActivityRecord activity = getTaskDisplayAreaAt(i)
- .topRunningActivity(considerKeyguardState);
- if (activity != null) {
- return activity;
- }
- }
- return null;
+ return getItemFromTaskDisplayAreas(taskDisplayArea ->
+ taskDisplayArea.topRunningActivity(considerKeyguardState));
}
boolean updateDisplayOverrideConfigurationLocked() {
@@ -5217,18 +5189,17 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void remove() {
mRemoving = true;
- ActivityStack lastReparentedStack = null;
+ ActivityStack lastReparentedStack;
mRootWindowContainer.mStackSupervisor.beginDeferResume();
try {
- int numTaskContainers = getTaskDisplayAreaCount();
- for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) {
- final ActivityStack lastReparentedStackFromArea = getTaskDisplayAreaAt(tdaNdx)
- .remove();
+ lastReparentedStack = reduceOnAllTaskDisplayAreas((taskDisplayArea, stack) -> {
+ final ActivityStack lastReparentedStackFromArea = taskDisplayArea.remove();
if (lastReparentedStackFromArea != null) {
- lastReparentedStack = lastReparentedStackFromArea;
+ return lastReparentedStackFromArea;
}
- }
+ return stack;
+ }, null /* initValue */, false /* traverseTopToBottom */);
} finally {
mRootWindowContainer.mStackSupervisor.endDeferResume();
}
@@ -5255,26 +5226,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
// Check if all task display areas have only the empty home stacks left.
- boolean onlyEmptyHomeStacksLeft = true;
- for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = getTaskDisplayAreaAt(tdaNdx);
+ boolean hasNonEmptyHomeStack = forAllTaskDisplayAreas(taskDisplayArea -> {
if (taskDisplayArea.getStackCount() != 1) {
- onlyEmptyHomeStacksLeft = false;
- break;
+ return true;
}
final ActivityStack stack = taskDisplayArea.getStackAt(0);
- if (!stack.isActivityTypeHome() || stack.hasChild()) {
- onlyEmptyHomeStacksLeft = false;
- break;
- }
- }
- if (onlyEmptyHomeStacksLeft) {
+ return !stack.isActivityTypeHome() || stack.hasChild();
+ });
+ if (!hasNonEmptyHomeStack) {
// Release this display if only empty home stack(s) are left. This display will be
// released along with the stack(s) removal.
- for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final ActivityStack s = getTaskDisplayAreaAt(tdaNdx).getStackAt(0);
- s.removeIfPossible();
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ taskDisplayArea.getStackAt(0).removeIfPossible();
+ });
} else if (getTopStack() == null) {
removeIfPossible();
mRootWindowContainer.mStackSupervisor
@@ -5339,10 +5303,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
mInEnsureActivitiesVisible = true;
try {
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- getTaskDisplayAreaAt(i).ensureActivitiesVisible(starting, configChanges,
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ taskDisplayArea.ensureActivitiesVisible(starting, configChanges,
preserveWindows, notifyClients);
- }
+ });
} finally {
mInEnsureActivitiesVisible = false;
}
@@ -5357,8 +5321,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
void setDisplayToSingleTaskInstance() {
- final int taskDisplayAreaCount = getTaskDisplayAreaCount();
- if (taskDisplayAreaCount > 1) {
+ int tdaCount = reduceOnAllTaskDisplayAreas((taskDisplayArea, count) -> ++count,
+ 0 /* initValue */);
+ if (tdaCount > 1) {
throw new IllegalArgumentException(
"Display already has multiple task display areas. display=" + this);
}
@@ -5581,6 +5546,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mRemoteInsetsController = controller;
}
+ /**
+ * Notifies the remote insets controller that the top focused window has changed.
+ *
+ * @param packageName The name of the package that is open in the top focused window.
+ */
+ void topFocusedWindowChanged(String packageName) {
+ try {
+ mRemoteInsetsController.topFocusedWindowChanged(packageName);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to deliver package in top focused window change", e);
+ }
+ }
+
void notifyInsetsChanged() {
try {
mRemoteInsetsController.insetsChanged(
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 96d10a10aa75..d2f5d2d58006 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -386,11 +386,6 @@ public class DisplayPolicy {
private int mForcingShowNavBarLayer;
private boolean mForceShowSystemBars;
- /**
- * Force the display of system bars regardless of other settings.
- */
- private boolean mForceShowSystemBarsFromExternal;
-
private boolean mShowingDream;
private boolean mLastShowingDream;
private boolean mDreamingLockscreen;
@@ -480,7 +475,6 @@ public class DisplayPolicy {
final Resources r = mContext.getResources();
mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
- mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars);
mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
Context.ACCESSIBILITY_SERVICE);
@@ -698,17 +692,6 @@ public class DisplayPolicy {
return mDockMode;
}
- /**
- * @see WindowManagerService.setForceShowSystemBars
- */
- void setForceShowSystemBars(boolean forceShowSystemBars) {
- mForceShowSystemBarsFromExternal = forceShowSystemBars;
- }
-
- boolean getForceShowSystemBars() {
- return mForceShowSystemBarsFromExternal;
- }
-
public boolean hasNavigationBar() {
return mHasNavigationBar;
}
@@ -3539,8 +3522,7 @@ public class DisplayPolicy {
// We need to force system bars when the docked stack is visible, when the freeform stack
// is focused but also when we are resizing for the transitions when docked stack
// visibility changes.
- mForceShowSystemBars = dockedStackVisible || win.inFreeformWindowingMode() || resizing
- || mForceShowSystemBarsFromExternal;
+ mForceShowSystemBars = dockedStackVisible || win.inFreeformWindowingMode() || resizing;
final boolean forceOpaqueStatusBar = mForceShowSystemBars && !isKeyguardShowing();
// apply translucent bar vis flags
@@ -3915,8 +3897,8 @@ public class DisplayPolicy {
}
pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
- pw.print(prefix); pw.print("mForceShowSystemBarsFromExternal=");
- pw.print(mForceShowSystemBarsFromExternal);
+ pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars");
+ pw.print(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars());
pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
mStatusBarController.dump(pw, prefix);
mNavigationBarController.dump(pw, prefix);
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 8298763c1392..99ee5e121b7a 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -18,13 +18,14 @@ package com.android.server.wm;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
-import android.graphics.PixelFormat;
import android.view.InsetsSource;
import android.view.WindowInsets;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.protolog.common.ProtoLog;
+import java.io.PrintWriter;
+
/**
* Controller for IME inset source on the server. It's called provider as it provides the
* {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
@@ -132,8 +133,17 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
|| (mImeTargetFromIme != null && dcTarget.getParentWindow() == mImeTargetFromIme
&& dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer)
|| mImeTargetFromIme == mDisplayContent.getImeFallback()
- // If IME target is transparent but control target matches requesting window.
- || (controlTarget == mImeTargetFromIme
- && PixelFormat.formatHasAlpha(dcTarget.mAttrs.format));
+ || (!mImeTargetFromIme.isClosing() && controlTarget == mImeTargetFromIme);
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ super.dump(pw, prefix);
+ if (mImeTargetFromIme != null) {
+ pw.print(prefix);
+ pw.print("showImePostLayout pending for mImeTargetFromIme=");
+ pw.print(mImeTargetFromIme);
+ pw.println();
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 3e88566449fe..0216db471843 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,8 +16,6 @@
package com.android.server.wm;
-import static android.os.Process.myPid;
-import static android.os.Process.myUid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
@@ -480,11 +478,18 @@ final class InputMonitor {
mService.getRecentsAnimationController();
final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
&& recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord);
- if (inputWindowHandle == null || w.mRemoved) {
+ final int type = w.mAttrs.type;
+ final boolean isVisible = w.isVisibleLw();
+ if (inputChannel == null || inputWindowHandle == null || w.mRemoved
+ || (w.cantReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
if (w.mWinAnimator.hasSurface()) {
+ // Assign an InputInfo with type to the overlay window which can't receive input
+ // event. This is used to omit Surfaces from occlusion detection.
+ populateOverlayInputInfo(mInvalidInputWindow, w.getName(), type, isVisible);
mInputTransaction.setInputWindowInfo(
w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
mInvalidInputWindow);
+ return;
}
// Skip this window because it cannot possibly receive input.
return;
@@ -492,24 +497,8 @@ final class InputMonitor {
final int flags = w.mAttrs.flags;
final int privateFlags = w.mAttrs.privateFlags;
- final int type = w.mAttrs.type;
- final boolean isVisible = w.isVisibleLw();
-
- // Assign an InputInfo with type to the overlay window which can't receive input event.
- // This is used to omit Surfaces from occlusion detection.
- if (inputChannel == null
- || (w.cantReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
- if (!w.mWinAnimator.hasSurface()) {
- return;
- }
- populateOverlayInputInfo(inputWindowHandle, w.getName(), type, isVisible);
- mInputTransaction.setInputWindowInfo(
- w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
- inputWindowHandle);
- return;
- }
-
final boolean hasFocus = w.isFocused();
+
if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
if (recentsAnimationController.updateInputConsumerForApp(
mRecentsAnimationInputConsumer.mWindowHandle, hasFocus)) {
@@ -582,8 +571,6 @@ final class InputMonitor {
inputWindowHandle.visible = isVisible;
inputWindowHandle.canReceiveKeys = false;
inputWindowHandle.hasFocus = false;
- inputWindowHandle.ownerPid = myPid();
- inputWindowHandle.ownerUid = myUid();
inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
inputWindowHandle.scaleFactor = 1;
inputWindowHandle.layoutParamsFlags =
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index c50f296504fc..3ffc26a7a8ad 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -62,4 +62,8 @@ interface InsetsControlTarget {
return false;
}
+ /** Returns {@code target.getWindow()}, or null if {@code target} is {@code null}. */
+ static WindowState asWindowOrNull(InsetsControlTarget target) {
+ return target != null ? target.getWindow() : null;
+ }
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 254356d673e3..b7287e718bd6 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -46,7 +46,9 @@ import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.WindowInsetsAnimationControlListener;
+import android.view.WindowManager;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.DisplayThread;
@@ -97,12 +99,30 @@ class InsetsPolicy {
private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
private boolean mAnimatingShown;
+ /**
+ * Let remote insets controller control system bars regardless of other settings.
+ */
+ private boolean mRemoteInsetsControllerControlsSystemBars;
private final float[] mTmpFloat9 = new float[9];
InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
mStateController = stateController;
mDisplayContent = displayContent;
mPolicy = displayContent.getDisplayPolicy();
+ mRemoteInsetsControllerControlsSystemBars = mPolicy.getContext().getResources().getBoolean(
+ R.bool.config_remoteInsetsControllerControlsSystemBars);
+ }
+
+ boolean getRemoteInsetsControllerControlsSystemBars() {
+ return mRemoteInsetsControllerControlsSystemBars;
+ }
+
+ /**
+ * Used only for testing.
+ */
+ @VisibleForTesting
+ void setRemoteInsetsControllerControlsSystemBars(boolean controlsSystemBars) {
+ mRemoteInsetsControllerControlsSystemBars = controlsSystemBars;
}
/** Updates the target which can control system bars. */
@@ -256,6 +276,11 @@ class InsetsPolicy {
// Notification shade has control anyways, no reason to force anything.
return focusedWin;
}
+ if (remoteInsetsControllerControlsSystemBars(focusedWin)) {
+ mDisplayContent.mRemoteInsetsControlTarget.topFocusedWindowChanged(
+ focusedWin.mAttrs.packageName);
+ return mDisplayContent.mRemoteInsetsControlTarget;
+ }
if (forceShowsSystemBarsForWindowingMode) {
// Status bar is forcibly shown for the windowing mode which is a steady state.
// We don't want the client to control the status bar, and we will dispatch the real
@@ -285,6 +310,11 @@ class InsetsPolicy {
// Notification shade has control anyways, no reason to force anything.
return focusedWin;
}
+ if (remoteInsetsControllerControlsSystemBars(focusedWin)) {
+ mDisplayContent.mRemoteInsetsControlTarget.topFocusedWindowChanged(
+ focusedWin.mAttrs.packageName);
+ return mDisplayContent.mRemoteInsetsControlTarget;
+ }
if (forceShowsSystemBarsForWindowingMode) {
// Navigation bar is forcibly shown for the windowing mode which is a steady state.
// We don't want the client to control the navigation bar, and we will dispatch the real
@@ -300,6 +330,28 @@ class InsetsPolicy {
return focusedWin;
}
+ /**
+ * Determines whether the remote insets controller should take control of system bars for all
+ * windows.
+ */
+ boolean remoteInsetsControllerControlsSystemBars(@Nullable WindowState focusedWin) {
+ if (focusedWin == null) {
+ return false;
+ }
+ if (!mRemoteInsetsControllerControlsSystemBars) {
+ return false;
+ }
+ if (mDisplayContent == null || mDisplayContent.mRemoteInsetsControlTarget == null) {
+ // No remote insets control target to take control of insets.
+ return false;
+ }
+ // If necessary, auto can control application windows when
+ // config_remoteInsetsControllerControlsSystemBars is set to true. This is useful in cases
+ // where we want to dictate system bar inset state for applications.
+ return focusedWin.getAttrs().type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+ && focusedWin.getAttrs().type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+ }
+
private boolean forceShowsStatusBarTransiently() {
final WindowState win = mPolicy.getStatusBar();
return win != null && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
@@ -321,10 +373,7 @@ class InsetsPolicy {
// We need to force system bars when the docked stack is visible, when the freeform stack
// is visible but also when we are resizing for the transitions when docked stack
// visibility changes.
- return isDockedStackVisible
- || isFreeformStackVisible
- || isResizing
- || mPolicy.getForceShowSystemBars();
+ return isDockedStackVisible || isFreeformStackVisible || isResizing;
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 63083faaddb1..9c978fd0c867 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_INVALID;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -44,6 +45,7 @@ import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowManager;
+import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.protolog.common.ProtoLog;
import java.io.PrintWriter;
@@ -74,7 +76,21 @@ class InsetsStateController {
w.notifyInsetsChanged();
}
};
- private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() { };
+ private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() {
+ @Override
+ public void notifyInsetsControlChanged() {
+ InsetsSourceControl[] controls = getControlsForDispatch(this);
+ if (controls == null) {
+ return;
+ }
+ for (InsetsSourceControl control : controls) {
+ if (control.getType() == ITYPE_IME) {
+ mDisplayContent.mWmService.mH.post(() ->
+ InputMethodManagerInternal.get().removeImeSurface());
+ }
+ }
+ }
+ };
InsetsStateController(DisplayContent displayContent) {
mDisplayContent = displayContent;
@@ -171,6 +187,7 @@ class InsetsStateController {
state = new InsetsState(state);
state.removeSource(ITYPE_STATUS_BAR);
state.removeSource(ITYPE_NAVIGATION_BAR);
+ state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
}
if (aboveIme) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 9c535e4a41d7..76f236534b69 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -40,6 +40,7 @@ import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_SHOWING;
import static com.android.server.wm.KeyguardOccludedProto.DISPLAY_ID;
import static com.android.server.wm.KeyguardOccludedProto.KEYGUARD_OCCLUDED;
+import android.annotation.Nullable;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
@@ -514,9 +515,9 @@ class KeyguardController {
* Only the top non-pinned activity of the focusable stack on each display can control its
* occlusion state.
*/
+ @Nullable
private ActivityStack getStackForControllingOccluding(DisplayContent display) {
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ return display.getItemFromTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
if (stack != null && stack.isFocusableAndVisible()
@@ -524,8 +525,8 @@ class KeyguardController {
return stack;
}
}
- }
- return null;
+ return null;
+ });
}
void dumpStatus(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index c7f78342c829..c255a18190f7 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -359,17 +359,20 @@ class RemoteAnimationController implements DeathRecipient {
RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds,
Rect endBounds, Rect startBounds) {
mWindowContainer = windowContainer;
- mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds);
if (startBounds != null) {
mStartBounds = new Rect(startBounds);
+ mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
+ mStartBounds);
mTmpRect.set(startBounds);
mTmpRect.offsetTo(0, 0);
if (mRemoteAnimationAdapter.getChangeNeedsSnapshot()) {
mThumbnailAdapter =
new RemoteAnimationAdapterWrapper(this, new Point(0, 0), localBounds,
- mTmpRect);
+ mTmpRect, new Rect());
}
} else {
+ mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
+ new Rect(endPos.x, endPos.y, endBounds.right, endBounds.bottom));
mStartBounds = null;
}
}
@@ -407,13 +410,15 @@ class RemoteAnimationController implements DeathRecipient {
final Point mPosition = new Point();
final Rect mLocalBounds;
final Rect mStackBounds = new Rect();
+ final Rect mStartBounds = new Rect();
RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
- Rect localBounds, Rect stackBounds) {
+ Rect localBounds, Rect stackBounds, Rect startBounds) {
mRecord = record;
mPosition.set(position.x, position.y);
mLocalBounds = localBounds;
mStackBounds.set(stackBounds);
+ mStartBounds.set(startBounds);
}
@Override
@@ -427,13 +432,12 @@ class RemoteAnimationController implements DeathRecipient {
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
// Restore position and stack crop until client has a chance to modify it.
- if (mRecord.mStartBounds != null) {
- t.setPosition(animationLeash, mRecord.mStartBounds.left, mRecord.mStartBounds.top);
- t.setWindowCrop(animationLeash, mRecord.mStartBounds.width(),
- mRecord.mStartBounds.height());
+ if (mStartBounds.isEmpty()) {
+ t.setPosition(animationLeash, 0, 0);
+ t.setWindowCrop(animationLeash, -1, -1);
} else {
- t.setPosition(animationLeash, mPosition.x, mPosition.y);
- t.setWindowCrop(animationLeash, mStackBounds.width(), mStackBounds.height());
+ t.setPosition(animationLeash, mStartBounds.left, mStartBounds.top);
+ t.setWindowCrop(animationLeash, mStartBounds.width(), mStartBounds.height());
}
mCapturedLeash = animationLeash;
mCapturedFinishCallback = finishCallback;
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index 9d408540c838..faed7fa99fdd 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
-import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
@@ -44,19 +43,11 @@ class RootDisplayArea extends DisplayArea<DisplayArea> {
/** Mapping from window layer to {@link DisplayArea.Tokens} that holds windows on that layer. */
private DisplayArea.Tokens[] mAreaForLayer;
- /**
- * List of {@link TaskDisplayArea} that are attached to this {@link DisplayArea} hierarchy. The
- * order is the same as their z-order.
- *
- * TODO(b/157683117): Instead of caching the TDAs, always traverse the hierarchy to get them.
- */
- ArrayList<TaskDisplayArea> mTaskDisplayAreas;
-
/** Whether the hierarchy has been built. */
private boolean mHasBuiltHierarchy;
- RootDisplayArea(WindowManagerService wms) {
- super(wms, Type.ANY, "RootDisplayArea", FEATURE_ROOT);
+ RootDisplayArea(WindowManagerService wms, String name, int featureId) {
+ super(wms, Type.ANY, name, featureId);
}
/** Finds the {@link DisplayArea.Tokens} that this type of window should be attached to. */
@@ -73,15 +64,13 @@ class RootDisplayArea extends DisplayArea<DisplayArea> {
/** Callback after {@link DisplayArea} hierarchy has been built. */
void onHierarchyBuilt(ArrayList<Feature> features, DisplayArea.Tokens[] areaForLayer,
- Map<Feature, List<DisplayArea<? extends WindowContainer>>> featureToDisplayAreas,
- ArrayList<TaskDisplayArea> taskDisplayAreas) {
+ Map<Feature, List<DisplayArea<? extends WindowContainer>>> featureToDisplayAreas) {
if (mHasBuiltHierarchy) {
throw new IllegalStateException("Root should only build the hierarchy once");
}
mHasBuiltHierarchy = true;
mFeatures = Collections.unmodifiableList(features);
mAreaForLayer = areaForLayer;
- mTaskDisplayAreas = taskDisplayAreas;
mFeatureToDisplayAreas = featureToDisplayAreas;
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6e2df84e2e96..40f8fab510ba 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1106,9 +1106,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
boolean displayHasContent = false;
ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,
- "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w"
- + ".isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
- w, w.mHasSurface, onScreen, w.isDisplayedLw(), w.mAttrs.userActivityTimeout);
+ "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w"
+ + ".isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
+ w, w.mHasSurface, onScreen, w.isDisplayedLw(), w.mAttrs.userActivityTimeout);
if (w.mHasSurface && onScreen) {
if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) {
mUserActivityTimeout = w.mAttrs.userActivityTimeout;
@@ -1457,16 +1457,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
void startHomeOnEmptyDisplays(String reason) {
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final DisplayContent display = getChildAt(i);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- if (taskDisplayArea.topRunningActivity() == null) {
- startHomeOnTaskDisplayArea(mCurrentUser, reason, taskDisplayArea,
- false /* allowInstrumenting */, false /* fromHomeKey */);
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ if (taskDisplayArea.topRunningActivity() == null) {
+ startHomeOnTaskDisplayArea(mCurrentUser, reason, taskDisplayArea,
+ false /* allowInstrumenting */, false /* fromHomeKey */);
}
- }
+ });
}
boolean startHomeOnDisplay(int userId, String reason, int displayId) {
@@ -1483,13 +1479,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
final DisplayContent display = getDisplayContent(displayId);
- boolean result = false;
- for (int tcNdx = display.getTaskDisplayAreaCount() - 1; tcNdx >= 0; --tcNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tcNdx);
- result |= startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
- allowInstrumenting, fromHomeKey);
- }
- return result;
+ return display.reduceOnAllTaskDisplayAreas((taskDisplayArea, result) ->
+ result | startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea,
+ allowInstrumenting, fromHomeKey),
+ false /* initValue */);
}
/**
@@ -1826,31 +1819,27 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final ArrayList<IBinder> topActivityTokens = new ArrayList<>();
final ActivityStack topFocusedStack = getTopDisplayFocusedStack();
// Traverse all displays.
- for (int dNdx = getChildCount() - 1; dNdx >= 0; dNdx--) {
- final DisplayContent display = getChildAt(dNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea =
- display.getTaskDisplayAreaAt(tdaNdx);
- // Traverse all stacks on a display area.
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- // Get top activity from a visible stack and add it to the list.
- if (stack.shouldBeVisible(null /* starting */)) {
- final ActivityRecord top = stack.getTopNonFinishingActivity();
- if (top != null) {
- if (stack == topFocusedStack) {
- topActivityTokens.add(0, top.appToken);
- } else {
- topActivityTokens.add(top.appToken);
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ // Traverse all stacks on a display area.
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ // Get top activity from a visible stack and add it to the list.
+ if (stack.shouldBeVisible(null /* starting */)) {
+ final ActivityRecord top = stack.getTopNonFinishingActivity();
+ if (top != null) {
+ if (stack == topFocusedStack) {
+ topActivityTokens.add(0, top.appToken);
+ } else {
+ topActivityTokens.add(top.appToken);
}
}
}
}
- }
+ });
return topActivityTokens;
}
+ @Nullable
ActivityStack getTopDisplayFocusedStack() {
for (int i = getChildCount() - 1; i >= 0; --i) {
final ActivityStack focusedStack = getChildAt(i).getFocusedStack();
@@ -1861,6 +1850,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return null;
}
+ @Nullable
ActivityRecord getTopResumedActivity() {
final ActivityStack focusedStack = getTopDisplayFocusedStack();
if (focusedStack == null) {
@@ -1872,18 +1862,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
// The top focused stack might not have a resumed activity yet - look on all displays in
// focus order.
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final DisplayContent display = getChildAt(i);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- final ActivityRecord resumedActivityOnTaskContainer = taskDisplayArea
- .getFocusedActivity();
- if (resumedActivityOnTaskContainer != null) {
- return resumedActivityOnTaskContainer;
- }
- }
- }
- return null;
+ return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedActivity);
}
boolean isTopDisplayFocusedStack(ActivityStack stack) {
@@ -1897,25 +1876,21 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// First, found out what is currently the foreground app, so that we don't blow away the
// previous app if this activity is being hosted by the process that is actually still the
// foreground.
- WindowProcessController fgApp = null;
- for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- if (isTopDisplayFocusedStack(stack)) {
- final ActivityRecord resumedActivity = stack.getResumedActivity();
- if (resumedActivity != null) {
- fgApp = resumedActivity.app;
- } else if (stack.mPausingActivity != null) {
- fgApp = stack.mPausingActivity.app;
- }
- break;
+ WindowProcessController fgApp = reduceOnAllTaskDisplayAreas((taskDisplayArea, app) -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (isTopDisplayFocusedStack(stack)) {
+ final ActivityRecord resumedActivity = stack.getResumedActivity();
+ if (resumedActivity != null) {
+ app = resumedActivity.app;
+ } else if (stack.mPausingActivity != null) {
+ app = stack.mPausingActivity.app;
}
+ break;
}
}
- }
+ return app;
+ }, null /* initValue */);
// Now set this one as the previous process, only if that really makes sense to.
if (r.hasProcess() && fgApp != null && r.app != fgApp
@@ -2024,16 +1999,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mCurrentUser = userId;
mStackSupervisor.mStartingUsers.add(uss);
- for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- stack.switchUser(userId);
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ stack.switchUser(userId);
}
- }
+ });
final int restoreStackId = mUserStackInFront.get(userId);
ActivityStack stack = getStack(restoreStackId);
@@ -2221,6 +2192,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
}
+ @Nullable
ActivityRecord findTask(ActivityRecord r, TaskDisplayArea preferredTaskDisplayArea) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
mTmpFindTaskResult.clear();
@@ -2234,20 +2206,20 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
}
- for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- if (taskDisplayArea == preferredTaskDisplayArea) {
- continue;
- }
+ final ActivityRecord task = getItemFromTaskDisplayAreas(taskDisplayArea -> {
+ if (taskDisplayArea == preferredTaskDisplayArea) {
+ return null;
+ }
- taskDisplayArea.findTaskLocked(r, false /* isPreferredDisplay */,
- mTmpFindTaskResult);
- if (mTmpFindTaskResult.mIdealMatch) {
- return mTmpFindTaskResult.mRecord;
- }
+ taskDisplayArea.findTaskLocked(r, false /* isPreferredDisplay */,
+ mTmpFindTaskResult);
+ if (mTmpFindTaskResult.mIdealMatch) {
+ return mTmpFindTaskResult.mRecord;
}
+ return null;
+ });
+ if (task != null) {
+ return task;
}
if (DEBUG_TASKS && mTmpFindTaskResult.mRecord == null) Slog.d(TAG_TASKS, "No task found");
@@ -2261,24 +2233,20 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished.
*/
int finishTopCrashedActivities(WindowProcessController app, String reason) {
- Task finishedTask = null;
ActivityStack focusedStack = getTopDisplayFocusedStack();
- for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- // It is possible that request to finish activity might also remove its task and
- // stack, so we need to be careful with indexes in the loop and check child count
- // every time.
- for (int stackNdx = 0; stackNdx < taskDisplayArea.getStackCount(); ++stackNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx);
- final Task t = stack.finishTopCrashedActivityLocked(app, reason);
- if (stack == focusedStack || finishedTask == null) {
- finishedTask = t;
- }
+ Task finishedTask = reduceOnAllTaskDisplayAreas((taskDisplayArea, task) -> {
+ // It is possible that request to finish activity might also remove its task and
+ // stack, so we need to be careful with indexes in the loop and check child count
+ // every time.
+ for (int stackNdx = 0; stackNdx < taskDisplayArea.getStackCount(); ++stackNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx);
+ final Task t = stack.finishTopCrashedActivityLocked(app, reason);
+ if (stack == focusedStack || task == null) {
+ task = t;
}
}
- }
+ return task;
+ }, null /* initValue */);
return finishedTask != null ? finishedTask.mTaskId : INVALID_TASK_ID;
}
@@ -2300,33 +2268,36 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- boolean resumedOnDisplay = false;
final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- final ActivityRecord topRunningActivity = stack.topRunningActivity();
- if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
- continue;
- }
- if (stack == targetStack) {
- // Simply update the result for targetStack because the targetStack had
- // already resumed in above. We don't want to resume it again, especially in
- // some cases, it would cause a second launch failure if app process was
- // dead.
- resumedOnDisplay |= result;
- continue;
- }
- if (taskDisplayArea.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {
- // Kick off any lingering app transitions form the MoveTaskToFront
- // operation, but only consider the top task and stack on that display.
- stack.executeAppTransition(targetOptions);
- } else {
- resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
- }
- }
- }
+ final boolean curResult = result;
+ boolean resumedOnDisplay = display.reduceOnAllTaskDisplayAreas(
+ (taskDisplayArea, resumed) -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ final ActivityRecord topRunningActivity = stack.topRunningActivity();
+ if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
+ continue;
+ }
+ if (stack == targetStack) {
+ // Simply update the result for targetStack because the targetStack
+ // had already resumed in above. We don't want to resume it again,
+ // especially in some cases, it would cause a second launch failure
+ // if app process was dead.
+ resumed |= curResult;
+ continue;
+ }
+ if (taskDisplayArea.isTopStack(stack)
+ && topRunningActivity.isState(RESUMED)) {
+ // Kick off any lingering app transitions form the MoveTaskToFront
+ // operation, but only consider the top task and stack on that
+ // display.
+ stack.executeAppTransition(targetOptions);
+ } else {
+ resumed |= topRunningActivity.makeActiveIfNeeded(target);
+ }
+ }
+ return resumed;
+ }, false /* initValue */);
if (!resumedOnDisplay) {
// In cases when there are no valid activities (e.g. device just booted or launcher
// crashed) it's possible that nothing was resumed on a display. Requesting resume
@@ -2360,8 +2331,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
// Set the sleeping state of the stacks on the display.
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ display.forAllTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
if (displayShouldSleep) {
@@ -2375,7 +2345,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// triggered after contents are drawn on the display.
if (display.isSingleTaskInstance()) {
display.mDisplayContent.prepareAppTransition(
- TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false);
+ TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false,
+ 0 /* flags */, true /* forceOverride*/);
}
stack.awakeFromSleepingLocked();
if (display.isSingleTaskInstance()) {
@@ -2399,7 +2370,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
false /* preserveWindows */);
}
}
- }
+ });
}
}
@@ -2500,29 +2471,24 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
ArrayList<ActivityManager.StackInfo> getAllStackInfos(int displayId) {
ArrayList<ActivityManager.StackInfo> list = new ArrayList<>();
if (displayId == INVALID_DISPLAY) {
- for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- list.add(getStackInfo(stack));
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ list.add(getStackInfo(stack));
}
- }
+ });
return list;
}
final DisplayContent display = getDisplayContent(displayId);
if (display == null) {
return list;
}
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ display.forAllTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
list.add(getStackInfo(stack));
}
- }
+ });
return list;
}
@@ -2723,28 +2689,23 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Tries to put all activity stacks to sleep. Returns true if all stacks were
// successfully put to sleep.
boolean putStacksToSleep(boolean allowDelay, boolean shuttingDown) {
- boolean allSleep = true;
- for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- // Stacks and activities could be removed while putting activities to sleep if
- // the app process was gone. This prevents us getting exception by accessing an
- // invalid stack index.
- if (sNdx >= taskDisplayArea.getStackCount()) {
- continue;
- }
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- if (allowDelay) {
- allSleep &= stack.goToSleepIfPossible(shuttingDown);
- } else {
- stack.goToSleep();
- }
+ return reduceOnAllTaskDisplayAreas((taskDisplayArea, result) -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ // Stacks and activities could be removed while putting activities to sleep if
+ // the app process was gone. This prevents us getting exception by accessing an
+ // invalid stack index.
+ if (sNdx >= taskDisplayArea.getStackCount()) {
+ continue;
+ }
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (allowDelay) {
+ result &= stack.goToSleepIfPossible(shuttingDown);
+ } else {
+ stack.goToSleep();
}
}
- }
- return allSleep;
+ return result;
+ }, true /* initValue */);
}
void handleAppCrash(WindowProcessController app) {
@@ -3112,18 +3073,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
boolean handleAppDied(WindowProcessController app) {
- boolean hasVisibleActivities = false;
- for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- hasVisibleActivities |= stack.handleAppDied(app);
- }
+ return reduceOnAllTaskDisplayAreas((taskDisplayArea, result) -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ result |= stack.handleAppDied(app);
}
- }
- return hasVisibleActivities;
+ return result;
+ }, false /* initValue */);
}
void closeSystemDialogActivities(String reason) {
@@ -3240,18 +3196,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
void finishVoiceTask(IVoiceInteractionSession session) {
- for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- int numTaskContainers = display.getTaskDisplayAreaCount();
- for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- final int numStacks = display.getStackCount();
- for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx);
- stack.finishVoiceTask(session);
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ final int numStacks = taskDisplayArea.getStackCount();
+ for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx);
+ stack.finishVoiceTask(session);
}
- }
+ });
}
/**
@@ -3310,48 +3261,50 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
boolean allResumedActivitiesVisible() {
- boolean foundResumed = false;
- for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- final ActivityRecord r = stack.getResumedActivity();
- if (r != null) {
- if (!r.nowVisible) {
- return false;
+ boolean[] foundResumed = {false};
+ final boolean foundInvisibleResumedActivity = forAllTaskDisplayAreas(
+ taskDisplayArea -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ final ActivityRecord r = stack.getResumedActivity();
+ if (r != null) {
+ if (!r.nowVisible) {
+ return true;
+ }
+ foundResumed[0] = true;
}
- foundResumed = true;
}
- }
- }
+ return false;
+ });
+ if (foundInvisibleResumedActivity) {
+ return false;
}
- return foundResumed;
+ return foundResumed[0];
}
boolean allPausedActivitiesComplete() {
- boolean pausing = true;
- for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- final ActivityRecord r = stack.mPausingActivity;
- if (r != null && !r.isState(PAUSED, STOPPED, STOPPING, FINISHING)) {
- if (DEBUG_STATES) {
- Slog.d(TAG_STATES, "allPausedActivitiesComplete: r=" + r
- + " state=" + r.getState());
- pausing = false;
- } else {
- return false;
+ boolean[] pausing = {true};
+ final boolean hasActivityNotCompleted = forAllTaskDisplayAreas(
+ taskDisplayArea -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ final ActivityRecord r = stack.mPausingActivity;
+ if (r != null && !r.isState(PAUSED, STOPPED, STOPPING, FINISHING)) {
+ if (DEBUG_STATES) {
+ Slog.d(TAG_STATES, "allPausedActivitiesComplete: r=" + r
+ + " state=" + r.getState());
+ pausing[0] = false;
+ } else {
+ return true;
+ }
}
}
- }
- }
+ return false;
+ });
+ if (hasActivityNotCompleted) {
+ return false;
}
- return pausing;
+ return pausing[0];
}
/**
@@ -3381,8 +3334,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* <li>The top activity explicitly belongs to {@param userId}.</li>
* <li>The top activity returns a result to an activity belonging to {@param userId}.</li>
* </ul>
- *
- * @return {@code true} if the top activity looks like it belongs to {@param userId}.
*/
private void taskTopActivityIsUser(Task task, @UserIdInt int userId) {
// To handle the case that work app is in the task but just is not the top one.
@@ -3400,15 +3351,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
void cancelInitializingActivities() {
- for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- taskDisplayArea.getStackAt(sNdx).cancelInitializingActivities();
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ // We don't want to clear starting window for activities that aren't occluded
+ // as we need to display their starting window until they are done initializing.
+ taskDisplayArea.getStackAt(sNdx).forAllOccludedActivities(
+ ActivityRecord::cancelInitializing);
}
- }
+ });
}
Task anyTaskForId(int id) {
@@ -3511,24 +3461,20 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
} else {
// Set power mode when the activity's process is different than the current top resumed
// activity on all display areas, or if there are no resumed activities in the system.
- boolean noResumedActivities = true;
- boolean allFocusedProcessesDiffer = true;
- for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) {
- final DisplayContent dc = getChildAt(displayNdx);
- for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
- final ActivityRecord resumedActivity = taskDisplayArea.getFocusedActivity();
- final WindowProcessController resumedActivityProcess =
- resumedActivity == null ? null : resumedActivity.app;
-
- noResumedActivities &= resumedActivityProcess == null;
- if (resumedActivityProcess != null) {
- allFocusedProcessesDiffer &= !resumedActivityProcess.equals(
- targetActivity.app);
- }
+ boolean[] noResumedActivities = {true};
+ boolean[] allFocusedProcessesDiffer = {true};
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ final ActivityRecord resumedActivity = taskDisplayArea.getFocusedActivity();
+ final WindowProcessController resumedActivityProcess =
+ resumedActivity == null ? null : resumedActivity.app;
+
+ noResumedActivities[0] &= resumedActivityProcess == null;
+ if (resumedActivityProcess != null) {
+ allFocusedProcessesDiffer[0] &=
+ !resumedActivityProcess.equals(targetActivity.app);
}
- }
- sendPowerModeLaunch = noResumedActivities || allFocusedProcessesDiffer;
+ });
+ sendPowerModeLaunch = noResumedActivities[0] || allFocusedProcessesDiffer[0];
}
if (sendPowerModeLaunch && mService.mPowerManagerInternal != null) {
@@ -3569,19 +3515,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
} else {
ArrayList<ActivityRecord> activities = new ArrayList<>();
- int numDisplays = getChildCount();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final DisplayContent display = getChildAt(displayNdx);
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
- activities.addAll(stack.getDumpActivitiesLocked(name));
- }
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
+ if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
+ activities.addAll(stack.getDumpActivitiesLocked(name));
}
}
- }
+ });
return activities;
}
}
@@ -3614,46 +3555,43 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
String dumpPackage) {
- boolean printed = false;
- boolean needSep = false;
+ boolean[] printed = {false};
+ boolean[] needSep = {false};
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
DisplayContent displayContent = getChildAt(displayNdx);
- if (printed) {
+ if (printed[0]) {
pw.println();
}
pw.print("Display #"); pw.print(displayContent.mDisplayId);
pw.println(" (activities from top to bottom):");
- for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
+ displayContent.forAllTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
- if (needSep) {
+ if (needSep[0]) {
pw.println();
}
- needSep = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false);
- printed |= needSep;
+ needSep[0] = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false);
+ printed[0] |= needSep[0];
}
- }
- for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx);
- printed |= printThisActivity(pw, taskDisplayArea.getFocusedActivity(),
- dumpPackage, needSep, " Resumed: ", () -> {
- pw.println(" Resumed activities in task display areas"
- + " (from top to bottom):");
- });
- }
+ });
+ displayContent.forAllTaskDisplayAreas(taskDisplayArea -> {
+ printed[0] |= printThisActivity(pw, taskDisplayArea.getFocusedActivity(),
+ dumpPackage, needSep[0], " Resumed: ", () ->
+ pw.println(" Resumed activities in task display areas"
+ + " (from top to bottom):"));
+ });
}
- printed |= dumpHistoryList(fd, pw, mStackSupervisor.mFinishingActivities, " ",
+ printed[0] |= dumpHistoryList(fd, pw, mStackSupervisor.mFinishingActivities, " ",
"Fin", false, !dumpAll,
false, dumpPackage, true,
- () -> { pw.println(" Activities waiting to finish:"); }, null);
- printed |= dumpHistoryList(fd, pw, mStackSupervisor.mStoppingActivities, " ",
+ () -> pw.println(" Activities waiting to finish:"), null);
+ printed[0] |= dumpHistoryList(fd, pw, mStackSupervisor.mStoppingActivities, " ",
"Stop", false, !dumpAll,
false, dumpPackage, true,
- () -> { pw.println(" Activities waiting to stop:"); }, null);
+ () -> pw.println(" Activities waiting to stop:"), null);
- return printed;
+ return printed[0];
}
private final class SleepTokenImpl extends ActivityTaskManagerInternal.SleepToken {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index bcd71c9ba74e..970520aff81f 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3175,6 +3175,33 @@ class Task extends WindowContainer<WindowContainer> {
return false;
}
+ /** Returns the top-most activity that occludes the given one, or {@code null} if none. */
+ @Nullable
+ ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
+ final ActivityRecord top = getActivity(ActivityRecord::occludesParent,
+ true /* traverseTopToBottom */, activity);
+ return top != activity ? top : null;
+ }
+
+ /** Iterates through all occluded activities. */
+ void forAllOccludedActivities(Consumer<ActivityRecord> handleOccludedActivity) {
+ if (!shouldBeVisible(null /* starting */)) {
+ // The stack is invisible so all activities are occluded.
+ forAllActivities(handleOccludedActivity);
+ return;
+ }
+ final ActivityRecord topOccluding = getOccludingActivityAbove(null);
+ if (topOccluding == null) {
+ // No activities are occluded.
+ return;
+ }
+ // Invoke the callback on the activities behind the top occluding activity.
+ forAllActivities(r -> {
+ handleOccludedActivity.accept(r);
+ return false;
+ }, topOccluding, false /* includeBoundary */, true /* traverseTopToBottom */);
+ }
+
@Override
public SurfaceControl.Builder makeAnimationLeash() {
return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 24cf751015c2..8bab106e2f54 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -66,6 +66,9 @@ import com.android.server.protolog.common.ProtoLog;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
/**
* {@link DisplayArea} that represents a section of a screen that contains app window containers.
@@ -375,6 +378,31 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
mAtmService.mStackSupervisor.updateTopResumedActivityIfNeeded();
}
+ @Override
+ boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback,
+ boolean traverseTopToBottom) {
+ return callback.apply(this);
+ }
+
+ @Override
+ void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom) {
+ callback.accept(this);
+ }
+
+ @Nullable
+ @Override
+ <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator,
+ @Nullable R initValue, boolean traverseTopToBottom) {
+ return accumulator.apply(this, initValue);
+ }
+
+ @Nullable
+ @Override
+ <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback,
+ boolean traverseTopToBottom) {
+ return callback.apply(this);
+ }
+
/**
* Assigns a priority number to stack types. This priority defines an order between the types
* of stacks that are added to the task display area.
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 11c20b6d9133..00ddf82d2ba3 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -741,9 +741,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
private void adjustBoundsToAvoidConflictInDisplay(@NonNull DisplayContent display,
@NonNull Rect inOutBounds) {
final List<Rect> taskBoundsToCheck = new ArrayList<>();
- int numTaskContainers = display.getTaskDisplayAreaCount();
- for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ display.forAllTaskDisplayAreas(taskDisplayArea -> {
int numStacks = taskDisplayArea.getStackCount();
for (int sNdx = 0; sNdx < numStacks; ++sNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
@@ -755,7 +753,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
taskBoundsToCheck.add(stack.getChildAt(j).getBounds());
}
}
- }
+ }, false /* traverseTopToBottom */);
adjustBoundsToAvoidConflict(display.getBounds(), taskBoundsToCheck, inOutBounds);
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index f70bf18cdea5..04d134c3649d 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -603,8 +603,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
throw new IllegalArgumentException("Display " + displayId + " doesn't exist");
}
ArrayList<RunningTaskInfo> out = new ArrayList<>();
- for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
+ dc.forAllTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final Task task = taskDisplayArea.getStackAt(sNdx);
if (activityTypes != null
@@ -613,7 +612,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
out.add(task.getTaskInfo());
}
- }
+ });
return out;
}
} finally {
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 132d00ac91c1..c27d0cda22ab 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
@@ -24,6 +25,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIG
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.Nullable;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -44,7 +46,13 @@ class WallpaperWindowToken extends WindowToken {
WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
DisplayContent dc, boolean ownerCanManageAppTokens) {
- super(service, token, TYPE_WALLPAPER, explicit, dc, ownerCanManageAppTokens);
+ this(service, token, explicit, dc, ownerCanManageAppTokens, null /* options */);
+ }
+
+ WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
+ DisplayContent dc, boolean ownerCanManageAppTokens, @Nullable Bundle options) {
+ super(service, token, TYPE_WALLPAPER, explicit, dc, ownerCanManageAppTokens, INVALID_UID,
+ false /* roundedCornerOverlay */, false /* fromClientToken */, options);
dc.mWallpaperController.addWallpaperToken(this);
setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 4de77724bc41..7b92c283ddf2 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -95,6 +95,7 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Set;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -1731,6 +1732,145 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
/**
+ * For all {@link TaskDisplayArea} at or below this container call the callback.
+ * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
+ * returns {@code true}.
+ * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in
+ * terms of z-order, else from bottom-to-top.
+ * @return {@code true} if the search ended before we reached the end of the hierarchy due to
+ * callback returning {@code true}.
+ */
+ boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback,
+ boolean traverseTopToBottom) {
+ int childCount = mChildren.size();
+ int i = traverseTopToBottom ? childCount - 1 : 0;
+ while (i >= 0 && i < childCount) {
+ if (mChildren.get(i).forAllTaskDisplayAreas(callback, traverseTopToBottom)) {
+ return true;
+ }
+ i += traverseTopToBottom ? -1 : 1;
+ }
+ return false;
+ }
+
+ /**
+ * For all {@link TaskDisplayArea} at or below this container call the callback. Traverses from
+ * top to bottom in terms of z-order.
+ * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
+ * returns {@code true}.
+ * @return {@code true} if the search ended before we reached the end of the hierarchy due to
+ * callback returning {@code true}.
+ */
+ boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback) {
+ return forAllTaskDisplayAreas(callback, true /* traverseTopToBottom */);
+ }
+
+ /**
+ * For all {@link TaskDisplayArea} at or below this container call the callback.
+ * @param callback Applies on each {@link TaskDisplayArea} found.
+ * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in
+ * terms of z-order, else from bottom-to-top.
+ */
+ void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom) {
+ int childCount = mChildren.size();
+ int i = traverseTopToBottom ? childCount - 1 : 0;
+ while (i >= 0 && i < childCount) {
+ mChildren.get(i).forAllTaskDisplayAreas(callback, traverseTopToBottom);
+ i += traverseTopToBottom ? -1 : 1;
+ }
+ }
+
+ /**
+ * For all {@link TaskDisplayArea} at or below this container call the callback. Traverses from
+ * top to bottom in terms of z-order.
+ * @param callback Applies on each {@link TaskDisplayArea} found.
+ */
+ void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback) {
+ forAllTaskDisplayAreas(callback, true /* traverseTopToBottom */);
+ }
+
+ /**
+ * Performs a reduction on all {@link TaskDisplayArea} at or below this container, using the
+ * provided initial value and an accumulation function, and returns the reduced value.
+ * @param accumulator Applies on each {@link TaskDisplayArea} found with the accumulative result
+ * from the previous call.
+ * @param initValue The initial value to pass to the accumulating function with the first
+ * {@link TaskDisplayArea}.
+ * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in
+ * terms of z-order, else from bottom-to-top.
+ * @return the accumulative result.
+ */
+ @Nullable
+ <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator,
+ @Nullable R initValue, boolean traverseTopToBottom) {
+ int childCount = mChildren.size();
+ int i = traverseTopToBottom ? childCount - 1 : 0;
+ R result = initValue;
+ while (i >= 0 && i < childCount) {
+ result = (R) mChildren.get(i)
+ .reduceOnAllTaskDisplayAreas(accumulator, result, traverseTopToBottom);
+ i += traverseTopToBottom ? -1 : 1;
+ }
+ return result;
+ }
+
+ /**
+ * Performs a reduction on all {@link TaskDisplayArea} at or below this container, using the
+ * provided initial value and an accumulation function, and returns the reduced value. Traverses
+ * from top to bottom in terms of z-order.
+ * @param accumulator Applies on each {@link TaskDisplayArea} found with the accumulative result
+ * from the previous call.
+ * @param initValue The initial value to pass to the accumulating function with the first
+ * {@link TaskDisplayArea}.
+ * @return the accumulative result.
+ */
+ @Nullable
+ <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator,
+ @Nullable R initValue) {
+ return reduceOnAllTaskDisplayAreas(accumulator, initValue, true /* traverseTopToBottom */);
+ }
+
+ /**
+ * Finds the first non {@code null} return value from calling the callback on all
+ * {@link TaskDisplayArea} at or below this container.
+ * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
+ * returns non {@code null}.
+ * @param traverseTopToBottom If {@code true}, traverses the hierarchy from top-to-bottom in
+ * terms of z-order, else from bottom-to-top.
+ * @return the first returned object that is not {@code null}. Returns {@code null} if not
+ * found.
+ */
+ @Nullable
+ <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback,
+ boolean traverseTopToBottom) {
+ int childCount = mChildren.size();
+ int i = traverseTopToBottom ? childCount - 1 : 0;
+ while (i >= 0 && i < childCount) {
+ R result = (R) mChildren.get(i)
+ .getItemFromTaskDisplayAreas(callback, traverseTopToBottom);
+ if (result != null) {
+ return result;
+ }
+ i += traverseTopToBottom ? -1 : 1;
+ }
+ return null;
+ }
+
+ /**
+ * Finds the first non {@code null} return value from calling the callback on all
+ * {@link TaskDisplayArea} at or below this container. Traverses from top to bottom in terms of
+ * z-order.
+ * @param callback Applies on each {@link TaskDisplayArea} found and stops the search if it
+ * returns non {@code null}.
+ * @return the first returned object that is not {@code null}. Returns {@code null} if not
+ * found.
+ */
+ @Nullable
+ <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback) {
+ return getItemFromTaskDisplayAreas(callback, true /* traverseTopToBottom */);
+ }
+
+ /**
* Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
* the input container in terms of z-order.
*/
@@ -2656,6 +2796,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return null;
}
+ /** Cheap way of doing cast and instanceof. */
+ DisplayArea asDisplayArea() {
+ return null;
+ }
+
/**
* @return {@code true} if window container is manage by a
* {@link android.window.WindowOrganizer}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 481ad9e79182..85972bffd755 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2670,10 +2670,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
// TODO(window-container): Clean up dead tokens
if (type == TYPE_WALLPAPER) {
- new WallpaperWindowToken(this, binder, true, dc, callerCanManageAppTokens);
+ new WallpaperWindowToken(this, binder, true, dc, callerCanManageAppTokens,
+ options);
} else {
new WindowToken(this, binder, type, true, dc, callerCanManageAppTokens,
- callingUid, false /* roundedCornerOverlay */, fromClientToken);
+ callingUid, false /* roundedCornerOverlay */, fromClientToken, options);
}
}
} finally {
@@ -5840,27 +5841,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- @Override
- public void setForceShowSystemBars(boolean show) {
- boolean isAutomotive = mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_AUTOMOTIVE);
- if (!isAutomotive) {
- throw new UnsupportedOperationException("Force showing system bars is only supported"
- + "for Automotive use cases.");
- }
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Caller does not hold permission "
- + android.Manifest.permission.STATUS_BAR);
- }
- synchronized (mGlobalLock) {
- final PooledConsumer c = PooledLambda.obtainConsumer(
- DisplayPolicy::setForceShowSystemBars, PooledLambda.__(), show);
- mRoot.forAllDisplayPolicies(c);
- c.recycle();
- }
- }
-
public void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bac921816e3f..86bc0a227ac1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2191,6 +2191,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (isInputMethodTarget()) {
dc.computeImeTarget(true /* updateImeTarget */);
}
+ if (dc.mInputMethodControlTarget == this) {
+ dc.updateImeControlTarget();
+ }
final int type = mAttrs.type;
if (WindowManagerService.excludeWindowTypeFromTapOutTask(type)) {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 86aacf308068..2c1bb3ec51eb 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -40,10 +40,12 @@ import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW;
import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER;
import android.annotation.CallSuper;
+import android.annotation.Nullable;
import android.app.IWindowToken;
import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
import android.os.RemoteException;
@@ -78,6 +80,13 @@ class WindowToken extends WindowContainer<WindowState> {
// The type of window this token is for, as per WindowManager.LayoutParams.
final int windowType;
+ /**
+ * Options that will be used to determine which {@link RootDisplayArea} this window should be
+ * attached to.
+ */
+ @Nullable
+ final Bundle mOptions;
+
/** {@code true} if this holds the rounded corner overlay */
final boolean mRoundedCornerOverlay;
@@ -233,9 +242,17 @@ class WindowToken extends WindowContainer<WindowState> {
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
DisplayContent dc, boolean ownerCanManageAppTokens, int ownerUid,
boolean roundedCornerOverlay, boolean fromClientToken) {
+ this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens, ownerUid,
+ roundedCornerOverlay, fromClientToken, null /* options */);
+ }
+
+ WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
+ DisplayContent dc, boolean ownerCanManageAppTokens, int ownerUid,
+ boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
super(service);
token = _token;
windowType = type;
+ mOptions = options;
mPersistOnEmpty = persistOnEmpty;
mOwnerCanManageAppTokens = ownerCanManageAppTokens;
mOwnerUid = ownerUid;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 75ec22486021..7bd455ab82a1 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -194,7 +194,7 @@ protected:
public:
NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper);
- inline sp<InputManager> getInputManager() const { return mInputManager; }
+ inline sp<InputManagerInterface> getInputManager() const { return mInputManager; }
void dump(std::string& dump);
@@ -225,7 +225,7 @@ public:
/* --- InputReaderPolicyInterface implementation --- */
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
- virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
+ virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId);
virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices);
virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier);
virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier);
@@ -236,29 +236,26 @@ public:
/* --- InputDispatcherPolicyInterface implementation --- */
- virtual void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
- uint32_t policyFlags) override;
- virtual void notifyConfigurationChanged(nsecs_t when);
- virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<IBinder>& token, const std::string& reason) override;
- virtual void notifyInputChannelBroken(const sp<IBinder>& token);
- virtual void notifyFocusChanged(const sp<IBinder>& oldToken,
- const sp<IBinder>& newToken) override;
- virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
- virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
- virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
- uint32_t& policyFlags) override;
- virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
- uint32_t& policyFlags) override;
- virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,
- const KeyEvent* keyEvent,
- uint32_t policyFlags) override;
- virtual bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent,
- uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) override;
- virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) override;
- virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,
- int32_t injectorUid) override;
- virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override;
+ void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
+ uint32_t policyFlags) override;
+ void notifyConfigurationChanged(nsecs_t when) override;
+ std::chrono::nanoseconds notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
+ const sp<IBinder>& token,
+ const std::string& reason) override;
+ void notifyInputChannelBroken(const sp<IBinder>& token) override;
+ void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) override;
+ bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
+ void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
+ void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) override;
+ void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
+ uint32_t& policyFlags) override;
+ nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token, const KeyEvent* keyEvent,
+ uint32_t policyFlags) override;
+ bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent,
+ uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) override;
+ void pokeUserActivity(nsecs_t eventTime, int32_t eventType) override;
+ bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid, int32_t injectorUid) override;
+ void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override;
/* --- PointerControllerPolicyInterface implementation --- */
@@ -270,7 +267,7 @@ public:
virtual int32_t getCustomPointerIconId();
private:
- sp<InputManager> mInputManager;
+ sp<InputManagerInterface> mInputManager;
jobject mServiceObj;
sp<Looper> mLooper;
@@ -299,7 +296,7 @@ private:
sp<SpriteController> spriteController;
// Pointer controller singleton, created and destroyed as needed.
- wp<PointerController> pointerController;
+ std::weak_ptr<PointerController> pointerController;
// Input devices to be disabled
std::set<int32_t> disabledInputDevices;
@@ -342,9 +339,9 @@ NativeInputManager::NativeInputManager(jobject contextObj,
}
mInteractive = true;
- mInputManager = new InputManager(this, this);
- defaultServiceManager()->addService(String16("inputflinger"),
- mInputManager, false);
+ InputManager* im = new InputManager(this, this);
+ mInputManager = im;
+ defaultServiceManager()->addService(String16("inputflinger"), im);
}
NativeInputManager::~NativeInputManager() {
@@ -544,15 +541,16 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
} // release lock
}
-sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32_t /* deviceId */) {
+std::shared_ptr<PointerControllerInterface> NativeInputManager::obtainPointerController(
+ int32_t /* deviceId */) {
ATRACE_CALL();
AutoMutex _l(mLock);
- sp<PointerController> controller = mLocked.pointerController.promote();
+ std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
if (controller == nullptr) {
ensureSpriteControllerLocked();
- controller = new PointerController(this, mLooper, mLocked.spriteController);
+ controller = PointerController::create(this, mLooper, mLocked.spriteController);
mLocked.pointerController = controller;
updateInactivityTimeoutLocked();
}
@@ -694,8 +692,9 @@ static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env,
return handle->getInputApplicationHandleObjLocalRef(env);
}
-nsecs_t NativeInputManager::notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<IBinder>& token, const std::string& reason) {
+std::chrono::nanoseconds NativeInputManager::notifyAnr(
+ const sp<InputApplicationHandle>& inputApplicationHandle, const sp<IBinder>& token,
+ const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyANR");
#endif
@@ -718,7 +717,7 @@ nsecs_t NativeInputManager::notifyAnr(const sp<InputApplicationHandle>& inputApp
} else {
assert(newTimeout >= 0);
}
- return newTimeout;
+ return std::chrono::nanoseconds(newTimeout);
}
void NativeInputManager::notifyInputChannelBroken(const sp<IBinder>& token) {
@@ -803,15 +802,14 @@ void NativeInputManager::setSystemUiVisibility(int32_t visibility) {
}
void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) {
- sp<PointerController> controller = mLocked.pointerController.promote();
+ std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
if (controller == nullptr) {
return;
}
bool lightsOut = mLocked.systemUiVisibility & ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN;
- controller->setInactivityTimeout(lightsOut
- ? PointerController::INACTIVITY_TIMEOUT_SHORT
- : PointerController::INACTIVITY_TIMEOUT_NORMAL);
+ controller->setInactivityTimeout(lightsOut ? PointerController::InactivityTimeout::SHORT
+ : PointerController::InactivityTimeout::NORMAL);
}
void NativeInputManager::setPointerSpeed(int32_t speed) {
@@ -891,7 +889,7 @@ void NativeInputManager::reloadCalibration() {
void NativeInputManager::setPointerIconType(int32_t iconId) {
AutoMutex _l(mLock);
- sp<PointerController> controller = mLocked.pointerController.promote();
+ std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
if (controller != nullptr) {
controller->updatePointerIcon(iconId);
}
@@ -899,7 +897,7 @@ void NativeInputManager::setPointerIconType(int32_t iconId) {
void NativeInputManager::reloadPointerIcons() {
AutoMutex _l(mLock);
- sp<PointerController> controller = mLocked.pointerController.promote();
+ std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
if (controller != nullptr) {
controller->reloadPointerResources();
}
@@ -907,7 +905,7 @@ void NativeInputManager::reloadPointerIcons() {
void NativeInputManager::setCustomPointerIcon(const SpriteIcon& icon) {
AutoMutex _l(mLock);
- sp<PointerController> controller = mLocked.pointerController.promote();
+ std::shared_ptr<PointerController> controller = mLocked.pointerController.lock();
if (controller != nullptr) {
controller->setCustomPointerIcon(icon);
}
@@ -1253,7 +1251,7 @@ int32_t NativeInputManager::getCustomPointerIconId() {
}
void NativeInputManager::setMotionClassifierEnabled(bool enabled) {
- mInputManager->setMotionClassifierEnabled(enabled);
+ mInputManager->getClassifier()->setMotionClassifierEnabled(enabled);
}
// ----------------------------------------------------------------------------
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/util/SystemAppOpsHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/util/SystemAppOpsHelperTest.java
index 04a9cca7fa51..f40d3168cf98 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/util/SystemAppOpsHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/util/SystemAppOpsHelperTest.java
@@ -41,8 +41,6 @@ import static org.mockito.MockitoAnnotations.initMocks;
import android.app.AppOpsManager;
import android.content.Context;
-import android.content.Intent;
-import android.location.LocationManager;
import android.location.util.identity.CallerIdentity;
import android.platform.test.annotations.Presubmit;
@@ -52,7 +50,6 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import java.util.ArrayList;
@@ -183,11 +180,6 @@ public class SystemAppOpsHelperTest {
eq(false), eq("myfeature"), nullable(String.class));
assertThat(mHelper.startHighPowerLocationMonitoring(identity)).isTrue();
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext).sendBroadcast(intentCaptor.capture());
- assertThat(intentCaptor.getValue().getAction()).isEqualTo(
- LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
-
doReturn(MODE_IGNORED).when(
mAppOps).startOpNoThrow(eq(OP_MONITOR_HIGH_POWER_LOCATION), eq(1000),
eq("mypackage"),
@@ -209,11 +201,6 @@ public class SystemAppOpsHelperTest {
mHelper.stopHighPowerLocationMonitoring(identity);
verify(mAppOps).finishOp(OP_MONITOR_HIGH_POWER_LOCATION, 1000, "mypackage", "myfeature");
-
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext).sendBroadcast(intentCaptor.capture());
- assertThat(intentCaptor.getValue().getAction()).isEqualTo(
- LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
}
@Test
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index ac2ec58fae2a..7fc6bbd70000 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -59,6 +59,7 @@ android_test {
libs: [
"android.hardware.power-java",
"android.hardware.tv.cec-V1.0-java",
+ "android.hardware.vibrator-java",
"android.hidl.manager-V1.0-java",
"android.test.mock",
"android.test.base",
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 6915220d3fb7..90e1cfcd305a 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -81,6 +81,9 @@
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID"/>
+ <uses-permission android:name="android.permission.VIBRATE"/>
+ <uses-permission android:name="android.permission.ACCESS_VIBRATOR_STATE"/>
+ <uses-permission android:name="android.permission.VIBRATE_ALWAYS_ON"/>
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
new file mode 100644
index 000000000000..c6922536f61a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -0,0 +1,607 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.intThat;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+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.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.PackageManagerInternal;
+import android.hardware.vibrator.IVibrator;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IVibratorStateListener;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.PowerManagerInternal;
+import android.os.PowerSaveState;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.util.test.FakeSettingsProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+
+/**
+ * Tests for {@link VibratorService}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:VibratorServiceTest
+ */
+@Presubmit
+public class VibratorServiceTest {
+
+ private static final int UID = Process.ROOT_UID;
+ private static final String PACKAGE_NAME = "package";
+ private static final VibrationAttributes ALARM_ATTRS =
+ new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_ALARM).build();
+ private static final VibrationAttributes HAPTIC_FEEDBACK_ATTRS =
+ new VibrationAttributes.Builder().setUsage(
+ VibrationAttributes.USAGE_TOUCH).build();
+ private static final VibrationAttributes NOTIFICATION_ATTRS =
+ new VibrationAttributes.Builder().setUsage(
+ VibrationAttributes.USAGE_NOTIFICATION).build();
+ private static final VibrationAttributes RINGTONE_ATTRS =
+ new VibrationAttributes.Builder().setUsage(
+ VibrationAttributes.USAGE_RINGTONE).build();
+
+ @Rule public MockitoRule rule = MockitoJUnit.rule();
+
+ @Mock private PackageManagerInternal mPackageManagerInternalMock;
+ @Mock private PowerManagerInternal mPowerManagerInternalMock;
+ @Mock private PowerSaveState mPowerSaveStateMock;
+ @Mock private Vibrator mVibratorMock;
+ @Mock private VibratorService.NativeWrapper mNativeWrapperMock;
+ @Mock private IVibratorStateListener mVibratorStateListenerMock;
+ @Mock private IBinder mVibratorStateListenerBinderMock;
+
+ private TestLooper mTestLooper;
+ private ContextWrapper mContextSpy;
+
+ @Before
+ public void setUp() throws Exception {
+ mTestLooper = new TestLooper();
+ mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+
+ MockContentResolver contentResolver = new MockContentResolver(mContextSpy);
+ contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+
+ when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
+ when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
+ when(mVibratorMock.getDefaultHapticFeedbackIntensity())
+ .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+ when(mVibratorMock.getDefaultNotificationVibrationIntensity())
+ .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+ when(mVibratorMock.getDefaultRingVibrationIntensity())
+ .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+ when(mVibratorStateListenerMock.asBinder()).thenReturn(mVibratorStateListenerBinderMock);
+ when(mPackageManagerInternalMock.getSystemUiServiceComponent())
+ .thenReturn(new ComponentName("", ""));
+ when(mPowerManagerInternalMock.getLowPowerState(PowerManager.ServiceType.VIBRATION))
+ .thenReturn(mPowerSaveStateMock);
+
+ addLocalServiceMock(PackageManagerInternal.class, mPackageManagerInternalMock);
+ addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
+ FakeSettingsProvider.clearSettingsProvider();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.removeServiceForTest(PowerManagerInternal.class);
+ FakeSettingsProvider.clearSettingsProvider();
+ }
+
+ private VibratorService createService() {
+ return new VibratorService(mContextSpy,
+ new VibratorService.Injector() {
+ @Override
+ VibratorService.NativeWrapper getNativeWrapper() {
+ return mNativeWrapperMock;
+ }
+
+ @Override
+ Handler createHandler(Looper looper) {
+ return new Handler(mTestLooper.getLooper());
+ }
+
+ @Override
+ void addService(String name, IBinder service) {
+ // ignore
+ }
+ });
+ }
+
+ @Test
+ public void createService_initializesNativeService() {
+ createService();
+ verify(mNativeWrapperMock).vibratorInit();
+ verify(mNativeWrapperMock).vibratorOff();
+ }
+
+ @Test
+ public void hasVibrator_withVibratorHalPresent_returnsTrue() {
+ when(mNativeWrapperMock.vibratorExists()).thenReturn(true);
+ assertTrue(createService().hasVibrator());
+ }
+
+ @Test
+ public void hasVibrator_withNoVibratorHalPresent_returnsFalse() {
+ when(mNativeWrapperMock.vibratorExists()).thenReturn(false);
+ assertFalse(createService().hasVibrator());
+ }
+
+ @Test
+ public void hasAmplitudeControl_withAmplitudeControlSupport_returnsTrue() {
+ when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ assertTrue(createService().hasAmplitudeControl());
+ }
+
+ @Test
+ public void hasAmplitudeControl_withNoAmplitudeControlSupport_returnsFalse() {
+ when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(false);
+ assertFalse(createService().hasAmplitudeControl());
+ }
+
+ @Test
+ public void areEffectsSupported_withNullResultFromNative_returnsSupportUnknown() {
+ when(mNativeWrapperMock.vibratorGetSupportedEffects()).thenReturn(null);
+ assertArrayEquals(new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN},
+ createService().areEffectsSupported(new int[]{VibrationEffect.EFFECT_CLICK}));
+ }
+
+ @Test
+ public void areEffectsSupported_withSomeEffectsSupported_returnsSupportYesAndNoForEffects() {
+ int[] effects = new int[]{VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK};
+
+ when(mNativeWrapperMock.vibratorGetSupportedEffects())
+ .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
+ assertArrayEquals(
+ new int[]{Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
+ Vibrator.VIBRATION_EFFECT_SUPPORT_NO},
+ createService().areEffectsSupported(effects));
+ }
+
+ @Test
+ public void arePrimitivesSupported_withoutComposeCapability_returnsAlwaysFalse() {
+ assertArrayEquals(new boolean[]{false, false},
+ createService().arePrimitivesSupported(new int[]{
+ VibrationEffect.Composition.PRIMITIVE_CLICK,
+ VibrationEffect.Composition.PRIMITIVE_TICK
+ }));
+ }
+
+ @Test
+ public void arePrimitivesSupported_withComposeCapability_returnsAlwaysTrue() {
+ mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ assertArrayEquals(new boolean[]{true, true},
+ createService().arePrimitivesSupported(new int[]{
+ VibrationEffect.Composition.PRIMITIVE_CLICK,
+ VibrationEffect.Composition.PRIMITIVE_QUICK_RISE
+ }));
+ }
+
+ @Test
+ public void setAlwaysOnEffect_withCapabilityAndValidEffect_enablesAlwaysOnEffect() {
+ mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+
+ assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
+ VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS));
+ verify(mNativeWrapperMock).vibratorAlwaysOnEnable(
+ eq(1L), eq((long) VibrationEffect.EFFECT_CLICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG));
+ }
+
+ @Test
+ public void setAlwaysOnEffect_withNonPrebakedEffect_ignoresEffect() {
+ mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+
+ assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
+ VibrationEffect.createOneShot(100, 255), ALARM_ATTRS));
+ verify(mNativeWrapperMock, never()).vibratorAlwaysOnDisable(anyLong());
+ verify(mNativeWrapperMock, never()).vibratorAlwaysOnEnable(anyLong(), anyLong(), anyLong());
+ }
+
+ @Test
+ public void setAlwaysOnEffect_withNullEffect_disablesAlwaysOnEffect() {
+ mockVibratorCapabilities(IVibrator.CAP_ALWAYS_ON_CONTROL);
+
+ assertTrue(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1, null, ALARM_ATTRS));
+ verify(mNativeWrapperMock).vibratorAlwaysOnDisable(eq(1L));
+ }
+
+ @Test
+ public void setAlwaysOnEffect_withoutCapability_ignoresEffect() {
+ assertFalse(createService().setAlwaysOnEffect(UID, PACKAGE_NAME, 1,
+ VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS));
+ verify(mNativeWrapperMock, never()).vibratorAlwaysOnDisable(anyLong());
+ verify(mNativeWrapperMock, never()).vibratorAlwaysOnEnable(anyLong(), anyLong(), anyLong());
+ }
+
+ @Test
+ public void vibrate_withOneShotAndAmplitudeControl_turnsVibratorOnAndSetsAmplitude() {
+ when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ vibrate(service, VibrationEffect.createOneShot(100, 128));
+ assertTrue(service.isVibrating());
+
+ verify(mNativeWrapperMock).vibratorOff();
+ verify(mNativeWrapperMock).vibratorOn(eq(100L));
+ verify(mNativeWrapperMock).vibratorSetAmplitude(eq(128));
+ }
+
+ @Test
+ public void vibrate_withOneShotAndNoAmplitudeControl_turnsVibratorOnAndIgnoresAmplitude() {
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ vibrate(service, VibrationEffect.createOneShot(100, 128));
+ assertTrue(service.isVibrating());
+
+ verify(mNativeWrapperMock).vibratorOff();
+ verify(mNativeWrapperMock).vibratorOn(eq(100L));
+ verify(mNativeWrapperMock, never()).vibratorSetAmplitude(anyInt());
+ }
+
+ @Test
+ public void vibrate_withPrebaked_performsEffect() {
+ when(mNativeWrapperMock.vibratorGetSupportedEffects())
+ .thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
+
+ verify(mNativeWrapperMock).vibratorOff();
+ verify(mNativeWrapperMock).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_CLICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
+ any(VibratorService.Vibration.class), eq(false));
+ }
+
+ @Test
+ public void vibrate_withComposed_performsEffect() {
+ mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f, 10)
+ .compose();
+ vibrate(service, effect);
+
+ ArgumentCaptor<VibrationEffect.Composition.PrimitiveEffect[]> primitivesCaptor =
+ ArgumentCaptor.forClass(VibrationEffect.Composition.PrimitiveEffect[].class);
+
+ verify(mNativeWrapperMock).vibratorOff();
+ verify(mNativeWrapperMock).vibratorPerformComposedEffect(
+ primitivesCaptor.capture(), any(VibratorService.Vibration.class));
+
+ // Check all primitive effect fields are passed down to the HAL.
+ assertEquals(1, primitivesCaptor.getValue().length);
+ VibrationEffect.Composition.PrimitiveEffect primitive = primitivesCaptor.getValue()[0];
+ assertEquals(VibrationEffect.Composition.PRIMITIVE_CLICK, primitive.id);
+ assertEquals(0.5f, primitive.scale, /* delta= */ 1e-2);
+ assertEquals(10, primitive.delay);
+ }
+
+ @Test
+ public void vibrate_withWaveform_controlsVibratorAmplitudeDuringTotalVibrationTime()
+ throws Exception {
+ when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ VibrationEffect effect = VibrationEffect.createWaveform(
+ new long[] { 10, 10, 10 }, new int[] { 100, 200, 50 }, -1);
+ vibrate(service, effect);
+
+ verify(mNativeWrapperMock).vibratorOff();
+
+ Thread.sleep(5);
+ verify(mNativeWrapperMock).vibratorOn(eq(30L));
+ verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
+
+ Thread.sleep(10);
+ verify(mNativeWrapperMock).vibratorSetAmplitude(eq(200));
+
+ Thread.sleep(10);
+ verify(mNativeWrapperMock).vibratorSetAmplitude(eq(50));
+ }
+
+ @Test
+ public void vibrate_withCallback_finishesVibrationWhenCallbackTriggered() {
+ mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ doAnswer(invocation -> {
+ ((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
+ return null;
+ }).when(mNativeWrapperMock).vibratorPerformComposedEffect(
+ any(), any(VibratorService.Vibration.class));
+
+ // Use vibration with delay so there is time for the callback to be triggered.
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
+ .compose();
+ vibrate(service, effect);
+
+ // Vibration canceled once before perform and once by native callback.
+ verify(mNativeWrapperMock, times(2)).vibratorOff();
+ verify(mNativeWrapperMock).vibratorPerformComposedEffect(
+ any(VibrationEffect.Composition.PrimitiveEffect[].class),
+ any(VibratorService.Vibration.class));
+ }
+
+ @Test
+ public void vibrate_whenBinderDies_cancelsVibration() {
+ mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ doAnswer(invocation -> {
+ ((VibratorService.Vibration) invocation.getArgument(1)).binderDied();
+ return null;
+ }).when(mNativeWrapperMock).vibratorPerformComposedEffect(
+ any(), any(VibratorService.Vibration.class));
+
+ // Use vibration with delay so there is time for the callback to be triggered.
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
+ .compose();
+ vibrate(service, effect);
+
+ // Vibration canceled once before perform and once by native binder death.
+ verify(mNativeWrapperMock, times(2)).vibratorOff();
+ verify(mNativeWrapperMock).vibratorPerformComposedEffect(
+ any(VibrationEffect.Composition.PrimitiveEffect[].class),
+ any(VibratorService.Vibration.class));
+ }
+
+ @Test
+ public void cancelVibrate_withDeviceVibrating_callsVibratorOff() {
+ VibratorService service = createService();
+ vibrate(service, VibrationEffect.createOneShot(100, 128));
+ assertTrue(service.isVibrating());
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ service.cancelVibrate(service);
+ assertFalse(service.isVibrating());
+ verify(mNativeWrapperMock).vibratorOff();
+ }
+
+ @Test
+ public void cancelVibrate_withDeviceNotVibrating_ignoresCall() {
+ VibratorService service = createService();
+ Mockito.clearInvocations(mNativeWrapperMock);
+
+ service.cancelVibrate(service);
+ assertFalse(service.isVibrating());
+ verify(mNativeWrapperMock, never()).vibratorOff();
+ }
+
+ @Test
+ public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
+ VibratorService service = createService();
+
+ service.registerVibratorStateListener(mVibratorStateListenerMock);
+ verify(mVibratorStateListenerMock).onVibrating(false);
+
+ vibrate(service, VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE));
+ verify(mVibratorStateListenerMock).onVibrating(true);
+
+ // Run the scheduled callback to finish one-shot vibration.
+ mTestLooper.moveTimeForward(10);
+ mTestLooper.dispatchAll();
+ verify(mVibratorStateListenerMock, times(2)).onVibrating(false);
+ }
+
+ @Test
+ public void unregisterVibratorStateListener_callbackNotTriggeredAfter() throws Exception {
+ VibratorService service = createService();
+
+ service.registerVibratorStateListener(mVibratorStateListenerMock);
+ verify(mVibratorStateListenerMock).onVibrating(false);
+
+ vibrate(service, VibrationEffect.createOneShot(5, VibrationEffect.DEFAULT_AMPLITUDE));
+ verify(mVibratorStateListenerMock).onVibrating(true);
+
+ service.unregisterVibratorStateListener(mVibratorStateListenerMock);
+ Mockito.clearInvocations(mVibratorStateListenerMock);
+
+ vibrate(service, VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE));
+ verifyNoMoreInteractions(mVibratorStateListenerMock);
+ }
+
+ @Test
+ public void scale_withPrebaked_userIntensitySettingAsEffectStrength() {
+ // Alarm vibration is always VIBRATION_INTENSITY_HIGH.
+ setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_MEDIUM);
+ setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_LOW);
+ setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_OFF);
+ VibratorService service = createService();
+ service.systemReady();
+
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK),
+ ALARM_ATTRS);
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK),
+ NOTIFICATION_ATTRS);
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK),
+ HAPTIC_FEEDBACK_ATTRS);
+ vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK),
+ RINGTONE_ATTRS);
+
+ verify(mNativeWrapperMock).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_CLICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any(), anyBoolean());
+ verify(mNativeWrapperMock).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_TICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any(), anyBoolean());
+ verify(mNativeWrapperMock).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK),
+ eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any(), anyBoolean());
+ verify(mNativeWrapperMock, never()).vibratorPerformEffect(
+ eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any(), anyBoolean());
+ }
+
+ @Test
+ public void scale_withOneShotAndWaveform_usesScaleLevelOnAmplitude() throws Exception {
+ when(mVibratorMock.getDefaultNotificationVibrationIntensity())
+ .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+ setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_HIGH);
+ setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_LOW);
+ setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_OFF);
+
+ when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ VibratorService service = createService();
+ service.systemReady();
+
+ vibrate(service, VibrationEffect.createOneShot(20, 100), ALARM_ATTRS);
+ vibrate(service, VibrationEffect.createOneShot(20, 100), NOTIFICATION_ATTRS);
+ vibrate(service, VibrationEffect.createOneShot(20, 255), RINGTONE_ATTRS);
+ vibrate(service, VibrationEffect.createWaveform(new long[] { 10 }, new int[] { 100 }, -1),
+ HAPTIC_FEEDBACK_ATTRS);
+
+ // Waveform effect runs on a separate thread.
+ Thread.sleep(5);
+
+ // Alarm vibration is never scaled.
+ verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
+ // Notification vibrations will be scaled with SCALE_VERY_HIGH.
+ verify(mNativeWrapperMock).vibratorSetAmplitude(intThat(amplitude -> amplitude > 150));
+ // Haptic feedback vibrations will be scaled with SCALE_LOW.
+ verify(mNativeWrapperMock).vibratorSetAmplitude(
+ intThat(amplitude -> amplitude < 100 && amplitude > 50));
+ // Ringtone vibration is off.
+ verify(mNativeWrapperMock, never()).vibratorSetAmplitude(eq(255));
+ }
+
+ @Test
+ public void scale_withComposed_usesScaleLevelOnPrimitiveScaleValues() {
+ when(mVibratorMock.getDefaultNotificationVibrationIntensity())
+ .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+ setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_HIGH);
+ setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_LOW);
+ setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_OFF);
+
+ mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ VibratorService service = createService();
+ service.systemReady();
+
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
+ .compose();
+ ArgumentCaptor<VibrationEffect.Composition.PrimitiveEffect[]> primitivesCaptor =
+ ArgumentCaptor.forClass(VibrationEffect.Composition.PrimitiveEffect[].class);
+
+ vibrate(service, effect, ALARM_ATTRS);
+ vibrate(service, effect, NOTIFICATION_ATTRS);
+ vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
+ vibrate(service, effect, RINGTONE_ATTRS);
+
+ // Ringtone vibration is off, so only the other 3 are propagated to native.
+ verify(mNativeWrapperMock, times(3)).vibratorPerformComposedEffect(
+ primitivesCaptor.capture(), any());
+
+ List<VibrationEffect.Composition.PrimitiveEffect[]> values =
+ primitivesCaptor.getAllValues();
+
+ // Alarm vibration is never scaled.
+ assertEquals(1f, values.get(0)[0].scale, /* delta= */ 1e-2);
+ assertEquals(0.5f, values.get(0)[1].scale, /* delta= */ 1e-2);
+
+ // Notification vibrations will be scaled with SCALE_VERY_HIGH.
+ assertEquals(1f, values.get(1)[0].scale, /* delta= */ 1e-2);
+ assertTrue(0.7 < values.get(1)[1].scale);
+
+ // Haptic feedback vibrations will be scaled with SCALE_LOW.
+ assertTrue(0.5 < values.get(2)[0].scale);
+ assertTrue(0.5 > values.get(2)[1].scale);
+ }
+
+ private void vibrate(VibratorService service, VibrationEffect effect) {
+ vibrate(service, effect, ALARM_ATTRS);
+ }
+
+ private void vibrate(VibratorService service, VibrationEffect effect,
+ VibrationAttributes attributes) {
+ service.vibrate(UID, PACKAGE_NAME, effect, attributes, "some reason", service);
+ }
+
+ private void mockVibratorCapabilities(int capabilities) {
+ when(mNativeWrapperMock.vibratorGetCapabilities()).thenReturn((long) capabilities);
+ }
+
+ private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
+ LocalServices.removeServiceForTest(clazz);
+ LocalServices.addService(clazz, mock);
+ }
+
+ private void setVibrationIntensityUserSetting(String settingName, int value) {
+ Settings.System.putIntForUser(
+ mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index 0445bff8fd0d..5327bf778537 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -51,6 +51,7 @@ import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -271,6 +272,25 @@ public class AbstractAccessibilityServiceConnectionTest {
}
@Test
+ public void setServiceInfo_ChangePackageNames_updateSuccess() {
+ assertTrue(mServiceConnection.mPackageNames.isEmpty());
+
+ final AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo();
+ updateServiceInfo(serviceInfo, 0, 0, A11Y_SERVICE_FLAG,
+ new String[] {PACKAGE_NAME1, PACKAGE_NAME2},
+ 1000);
+
+ mServiceConnection.setServiceInfo(serviceInfo);
+ assertEquals(serviceInfo.packageNames.length, mServiceConnection.mPackageNames.size());
+ assertTrue(mServiceConnection.mPackageNames.containsAll(
+ Arrays.asList(mServiceConnection.getServiceInfo().packageNames)));
+
+ updateServiceInfo(serviceInfo, 0, 0, A11Y_SERVICE_FLAG, null, 1000);
+ mServiceConnection.setServiceInfo(serviceInfo);
+ assertTrue(mServiceConnection.mPackageNames.isEmpty());
+ }
+
+ @Test
public void canReceiveEvents_hasEventType_returnTrue() {
final AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo();
updateServiceInfo(serviceInfo,
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 09f946d4b107..e7eff00c472e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -102,13 +102,13 @@ public class ScanTests {
@Before
public void setupDefaultAbiBehavior() throws Exception {
when(mMockPackageAbiHelper.derivePackageAbi(
- any(AndroidPackage.class), anyBoolean(), nullable(String.class), anyBoolean()))
+ any(AndroidPackage.class), anyBoolean(), nullable(String.class)))
.thenReturn(new Pair<>(
new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
new PackageAbiHelper.NativeLibraryPaths(
"derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
- when(mMockPackageAbiHelper.getNativeLibraryPaths(
- any(AndroidPackage.class), any(PackageSetting.class), any(File.class)))
+ when(mMockPackageAbiHelper.deriveNativeLibraryPaths(
+ any(AndroidPackage.class), anyBoolean(), any(File.class)))
.thenReturn(new PackageAbiHelper.NativeLibraryPaths(
"getRootDir", true, "getNativeDir", "getNativeDir2"
));
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
index 6d9b43a967c4..cd2c9230221c 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
@@ -252,6 +252,7 @@ public class RollbackUnitTest {
verify(mMockDataHelper).destroyAppDataSnapshot(eq(123), pkgRollbackInfoFor(PKG_2), eq(111));
verify(mMockDataHelper).destroyAppDataSnapshot(eq(123), pkgRollbackInfoFor(PKG_2), eq(222));
verify(mMockDataHelper, never()).destroyApexDeSnapshots(anyInt());
+ verify(mMockDataHelper, never()).destroyApexCeSnapshots(anyInt(), anyInt());
assertThat(rollback.isDeleted()).isTrue();
}
@@ -273,6 +274,8 @@ public class RollbackUnitTest {
verify(mMockDataHelper, never())
.destroyAppDataSnapshot(anyInt(), pkgRollbackInfoFor(PKG_2), anyInt());
verify(mMockDataHelper).destroyApexDeSnapshots(123);
+ verify(mMockDataHelper).destroyApexCeSnapshots(111, 123);
+ verify(mMockDataHelper).destroyApexCeSnapshots(222, 123);
assertThat(rollback.isDeleted()).isTrue();
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index f0531f5166b9..9f59763cfa58 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -35,6 +35,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.os.HandlerThread;
import android.os.TimestampedValue;
+import android.util.IndentingPrintWriter;
import androidx.test.runner.AndroidJUnit4;
@@ -46,6 +47,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.PrintWriter;
+import java.io.StringWriter;
@RunWith(AndroidJUnit4.class)
public class TimeDetectorServiceTest {
@@ -177,7 +179,8 @@ public class TimeDetectorServiceTest {
when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
.thenReturn(PackageManager.PERMISSION_GRANTED);
- mTimeDetectorService.dump(null, null, null);
+ PrintWriter pw = new PrintWriter(new StringWriter());
+ mTimeDetectorService.dump(null, pw, null);
verify(mMockContext).checkCallingOrSelfPermission(eq(android.Manifest.permission.DUMP));
mStubbedTimeDetectorStrategy.verifyDumpCalled();
@@ -251,7 +254,7 @@ public class TimeDetectorServiceTest {
}
@Override
- public void dump(PrintWriter pw, String[] args) {
+ public void dump(IndentingPrintWriter pw, String[] args) {
mDumpCalled = true;
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/StubbedTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index 43a6b8f3e314..dcf319058ca2 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/StubbedTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -25,10 +25,9 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
+import android.util.IndentingPrintWriter;
-import java.io.PrintWriter;
-
-class StubbedTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
+class FakeTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
private StrategyListener mListener;
@@ -110,7 +109,7 @@ class StubbedTimeZoneDetectorStrategy implements TimeZoneDetectorStrategy {
}
@Override
- public void dump(PrintWriter pw, String[] args) {
+ public void dump(IndentingPrintWriter pw, String[] args) {
mDumpCalled = true;
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
index 40ea3982df06..0e2c22756097 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorInternalImplTest.java
@@ -37,7 +37,7 @@ public class TimeZoneDetectorInternalImplTest {
private static final List<String> ARBITRARY_ZONE_IDS = Arrays.asList("TestZoneId");
private Context mMockContext;
- private StubbedTimeZoneDetectorStrategy mStubbedTimeZoneDetectorStrategy;
+ private FakeTimeZoneDetectorStrategy mFakeTimeZoneDetectorStrategy;
private TimeZoneDetectorInternalImpl mTimeZoneDetectorInternal;
private HandlerThread mHandlerThread;
@@ -53,10 +53,10 @@ public class TimeZoneDetectorInternalImplTest {
mHandlerThread.start();
mTestHandler = new TestHandler(mHandlerThread.getLooper());
- mStubbedTimeZoneDetectorStrategy = new StubbedTimeZoneDetectorStrategy();
+ mFakeTimeZoneDetectorStrategy = new FakeTimeZoneDetectorStrategy();
mTimeZoneDetectorInternal = new TimeZoneDetectorInternalImpl(
- mMockContext, mTestHandler, mStubbedTimeZoneDetectorStrategy);
+ mMockContext, mTestHandler, mFakeTimeZoneDetectorStrategy);
}
@After
@@ -72,7 +72,7 @@ public class TimeZoneDetectorInternalImplTest {
mTestHandler.assertTotalMessagesEnqueued(1);
mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeZoneDetectorStrategy.verifySuggestGeolocationTimeZoneCalled(timeZoneSuggestion);
+ mFakeTimeZoneDetectorStrategy.verifySuggestGeolocationTimeZoneCalled(timeZoneSuggestion);
}
private static GeolocationTimeZoneSuggestion createGeolocationTimeZoneSuggestion() {
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index aa517ac0eea7..971d2e28b14e 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -46,13 +46,16 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
@RunWith(AndroidJUnit4.class)
public class TimeZoneDetectorServiceTest {
private static final int ARBITRARY_USER_ID = 9999;
private Context mMockContext;
- private StubbedTimeZoneDetectorStrategy mStubbedTimeZoneDetectorStrategy;
+ private FakeTimeZoneDetectorStrategy mFakeTimeZoneDetectorStrategy;
private TimeZoneDetectorService mTimeZoneDetectorService;
private HandlerThread mHandlerThread;
@@ -68,10 +71,10 @@ public class TimeZoneDetectorServiceTest {
mHandlerThread.start();
mTestHandler = new TestHandler(mHandlerThread.getLooper());
- mStubbedTimeZoneDetectorStrategy = new StubbedTimeZoneDetectorStrategy();
+ mFakeTimeZoneDetectorStrategy = new FakeTimeZoneDetectorStrategy();
mTimeZoneDetectorService = new TimeZoneDetectorService(
- mMockContext, mTestHandler, mStubbedTimeZoneDetectorStrategy);
+ mMockContext, mTestHandler, mFakeTimeZoneDetectorStrategy);
}
@After
@@ -100,7 +103,7 @@ public class TimeZoneDetectorServiceTest {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
TimeZoneCapabilities capabilities = createTimeZoneCapabilities();
- mStubbedTimeZoneDetectorStrategy.initializeCapabilities(capabilities);
+ mFakeTimeZoneDetectorStrategy.initializeCapabilities(capabilities);
assertEquals(capabilities, mTimeZoneDetectorService.getCapabilities());
@@ -130,7 +133,7 @@ public class TimeZoneDetectorServiceTest {
TimeZoneConfiguration configuration =
createTimeZoneConfiguration(false /* autoDetectionEnabled */);
- mStubbedTimeZoneDetectorStrategy.initializeConfiguration(configuration);
+ mFakeTimeZoneDetectorStrategy.initializeConfiguration(configuration);
assertEquals(configuration, mTimeZoneDetectorService.getConfiguration());
@@ -161,7 +164,8 @@ public class TimeZoneDetectorServiceTest {
TimeZoneConfiguration autoDetectDisabledConfiguration =
createTimeZoneConfiguration(false /* autoDetectionEnabled */);
- mStubbedTimeZoneDetectorStrategy.initializeConfiguration(autoDetectDisabledConfiguration);
+
+ mFakeTimeZoneDetectorStrategy.initializeConfiguration(autoDetectDisabledConfiguration);
IBinder mockListenerBinder = mock(IBinder.class);
ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
@@ -177,7 +181,7 @@ public class TimeZoneDetectorServiceTest {
// Simulate the configuration being changed and verify the mockListener was notified.
TimeZoneConfiguration autoDetectEnabledConfiguration =
createTimeZoneConfiguration(true /* autoDetectionEnabled */);
- mStubbedTimeZoneDetectorStrategy.updateConfiguration(
+ mFakeTimeZoneDetectorStrategy.updateConfiguration(
ARBITRARY_USER_ID, autoDetectEnabledConfiguration);
verify(mockListener).onChange(autoDetectEnabledConfiguration);
@@ -209,7 +213,7 @@ public class TimeZoneDetectorServiceTest {
assertEquals(expectedResult,
mTimeZoneDetectorService.suggestManualTimeZone(timeZoneSuggestion));
- mStubbedTimeZoneDetectorStrategy.verifySuggestManualTimeZoneCalled(timeZoneSuggestion);
+ mFakeTimeZoneDetectorStrategy.verifySuggestManualTimeZoneCalled(timeZoneSuggestion);
verify(mMockContext).enforceCallingOrSelfPermission(
eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE),
@@ -261,7 +265,7 @@ public class TimeZoneDetectorServiceTest {
anyString());
mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeZoneDetectorStrategy.verifySuggestTelephonyTimeZoneCalled(timeZoneSuggestion);
+ mFakeTimeZoneDetectorStrategy.verifySuggestTelephonyTimeZoneCalled(timeZoneSuggestion);
}
@Test
@@ -269,25 +273,26 @@ public class TimeZoneDetectorServiceTest {
when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
.thenReturn(PackageManager.PERMISSION_GRANTED);
- mTimeZoneDetectorService.dump(null, null, null);
+ PrintWriter pw = new PrintWriter(new StringWriter());
+ mTimeZoneDetectorService.dump(null, pw, null);
verify(mMockContext).checkCallingOrSelfPermission(eq(android.Manifest.permission.DUMP));
- mStubbedTimeZoneDetectorStrategy.verifyDumpCalled();
+ mFakeTimeZoneDetectorStrategy.verifyDumpCalled();
}
@Test
public void testAutoTimeZoneDetectionChanged() throws Exception {
- mTimeZoneDetectorService.handleAutoTimeZoneDetectionChanged();
+ mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged();
mTestHandler.assertTotalMessagesEnqueued(1);
mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled();
+ mFakeTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled();
- mStubbedTimeZoneDetectorStrategy.resetCallTracking();
+ mFakeTimeZoneDetectorStrategy.resetCallTracking();
- mTimeZoneDetectorService.handleAutoTimeZoneDetectionChanged();
+ mTimeZoneDetectorService.handleAutoTimeZoneConfigChanged();
mTestHandler.assertTotalMessagesEnqueued(2);
mTestHandler.waitForMessagesToBeProcessed();
- mStubbedTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled();
+ mFakeTimeZoneDetectorStrategy.verifyHandleAutoTimeZoneConfigChangedCalled();
}
private static TimeZoneConfiguration createTimeZoneConfiguration(
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index 00a7caaa7254..68554451e43a 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -48,13 +48,13 @@ import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
import android.app.timezonedetector.TimeZoneCapabilities;
import android.app.timezonedetector.TimeZoneConfiguration;
+import android.util.IndentingPrintWriter;
import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedTelephonyTimeZoneSuggestion;
import org.junit.Before;
import org.junit.Test;
-import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -119,7 +119,8 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testGetCapabilities() {
new Script()
- .initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
TimeZoneCapabilities expectedCapabilities = mFakeCallback.getCapabilities(USER_ID);
assertEquals(expectedCapabilities, mTimeZoneDetectorStrategy.getCapabilities(USER_ID));
}
@@ -127,17 +128,19 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testGetConfiguration() {
new Script()
- .initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
TimeZoneConfiguration expectedConfiguration = mFakeCallback.getConfiguration(USER_ID);
assertTrue(expectedConfiguration.isComplete());
assertEquals(expectedConfiguration, mTimeZoneDetectorStrategy.getConfiguration(USER_ID));
}
@Test
- public void testCapabilitiesTestInfra_owner() {
+ public void testCapabilitiesTestInfra_unrestricted() {
Script script = new Script();
- script.initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
{
// Check the fake test infra is doing what is expected.
TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
@@ -145,7 +148,8 @@ public class TimeZoneDetectorStrategyImplTest {
assertEquals(CAPABILITY_NOT_APPLICABLE, capabilities.getSuggestManualTimeZone());
}
- script.initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
+ script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
{
// Check the fake test infra is doing what is expected.
TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
@@ -155,10 +159,11 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testCapabilitiesTestInfra_nonOwner() {
+ public void testCapabilitiesTestInfra_restricted() {
Script script = new Script();
- script.initializeUser(USER_ID, UserCase.NON_OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ script.initializeUser(USER_ID, UserCase.RESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
{
// Check the fake test infra is doing what is expected.
TimeZoneCapabilities capabilities = mFakeCallback.getCapabilities(USER_ID);
@@ -166,7 +171,7 @@ public class TimeZoneDetectorStrategyImplTest {
assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSuggestManualTimeZone());
}
- script.initializeUser(USER_ID, UserCase.NON_OWNER,
+ script.initializeUser(USER_ID, UserCase.RESTRICTED,
CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
{
// Check the fake test infra is doing what is expected.
@@ -177,10 +182,10 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testCapabilitiesTestInfra_ownerAutoDetectNotSupported() {
+ public void testCapabilitiesTestInfra_autoDetectNotSupported() {
Script script = new Script();
- script.initializeUser(USER_ID, UserCase.OWNER_AUTO_DETECT_NOT_SUPPORTED,
+ script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
{
// Check the fake test infra is doing what is expected.
@@ -189,7 +194,7 @@ public class TimeZoneDetectorStrategyImplTest {
assertEquals(CAPABILITY_POSSESSED, capabilities.getSuggestManualTimeZone());
}
- script.initializeUser(USER_ID, UserCase.OWNER_AUTO_DETECT_NOT_SUPPORTED,
+ script.initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED);
{
// Check the fake test infra is doing what is expected.
@@ -200,9 +205,10 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testUpdateConfiguration_owner() {
+ public void testUpdateConfiguration_unrestricted() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
// Set the configuration with auto detection enabled.
script.simulateUpdateConfiguration(USER_ID, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
@@ -225,9 +231,9 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testUpdateConfiguration_nonOwner() {
+ public void testUpdateConfiguration_restricted() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.NON_OWNER,
+ .initializeUser(USER_ID, UserCase.RESTRICTED,
CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
// Try to update the configuration with auto detection disabled.
@@ -244,9 +250,9 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testUpdateConfiguration_ownerAutoDetectNotSupported() {
+ public void testUpdateConfiguration_autoDetectNotSupported() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER_AUTO_DETECT_NOT_SUPPORTED,
+ .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
// Try to update the configuration with auto detection disabled.
@@ -269,7 +275,8 @@ public class TimeZoneDetectorStrategyImplTest {
TelephonyTimeZoneSuggestion slotIndex2TimeZoneSuggestion =
createEmptySlotIndex2Suggestion();
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
script.simulateTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion)
@@ -311,7 +318,8 @@ public class TimeZoneDetectorStrategyImplTest {
QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
// A low quality suggestions will not be taken: The device time zone setting is left
// uninitialized.
@@ -376,7 +384,8 @@ public class TimeZoneDetectorStrategyImplTest {
for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
// Start with the device in a known state.
- script.initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
+ script.initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
TelephonyTimeZoneSuggestion suggestion =
@@ -427,7 +436,8 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testTelephonySuggestionsSingleSlotId() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
for (TelephonyTestCase testCase : TELEPHONY_TEST_CASES) {
@@ -493,7 +503,8 @@ public class TimeZoneDetectorStrategyImplTest {
TELEPHONY_SCORE_NONE);
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
// Initialize the latest suggestions as empty so we don't need to worry about nulls
// below for the first loop.
@@ -579,7 +590,8 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testTelephonySuggestionTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED);
TelephonyTestCase testCase = newTelephonyTestCase(
MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, TELEPHONY_SCORE_HIGH);
@@ -613,9 +625,10 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testManualSuggestion_owner_simulateAutoTimeZoneEnabled() {
+ public void testManualSuggestion_unrestricted_simulateAutoTimeZoneEnabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Auto time zone detection is enabled so the manual suggestion should be ignored.
@@ -625,9 +638,9 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testManualSuggestion_nonOwner_simulateAutoTimeZoneEnabled() {
+ public void testManualSuggestion_restricted_simulateAutoTimeZoneEnabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.NON_OWNER,
+ .initializeUser(USER_ID, UserCase.RESTRICTED,
CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
@@ -638,9 +651,9 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testManualSuggestion_ownerAutoDetectNotSupported_simulateAutoTimeZoneEnabled() {
+ public void testManualSuggestion_autoDetectNotSupported_simulateAutoTimeZoneEnabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER_AUTO_DETECT_NOT_SUPPORTED,
+ .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
CONFIG_AUTO_TIME_ZONE_DETECTION_ENABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
@@ -652,9 +665,10 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testManualSuggestion_owner_autoTimeZoneDetectionDisabled() {
+ public void testManualSuggestion_unrestricted_autoTimeZoneDetectionDisabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER, CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
+ CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
// Auto time zone detection is disabled so the manual suggestion should be used.
@@ -665,13 +679,13 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testManualSuggestion_nonOwner_autoTimeZoneDetectionDisabled() {
+ public void testManualSuggestion_restricted_autoTimeZoneDetectionDisabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.NON_OWNER,
+ .initializeUser(USER_ID, UserCase.RESTRICTED,
CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
- // Only owners have the capability.
+ // Restricted users do not have the capability.
ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
script.simulateManualTimeZoneSuggestion(
USER_ID, manualSuggestion, false /* expectedResult */)
@@ -679,13 +693,13 @@ public class TimeZoneDetectorStrategyImplTest {
}
@Test
- public void testManualSuggestion_ownerAutoDetectNotSupported_autoTimeZoneDetectionDisabled() {
+ public void testManualSuggestion_autoDetectNotSupported_autoTimeZoneDetectionDisabled() {
Script script = new Script()
- .initializeUser(USER_ID, UserCase.OWNER_AUTO_DETECT_NOT_SUPPORTED,
+ .initializeUser(USER_ID, UserCase.AUTO_DETECT_NOT_SUPPORTED,
CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
- // Only owners have the capability.
+ // Unrestricted users have the capability.
ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris");
script.simulateManualTimeZoneSuggestion(
USER_ID, manualSuggestion, true /* expectedResult */)
@@ -695,22 +709,22 @@ public class TimeZoneDetectorStrategyImplTest {
@Test
public void testAddDumpable() {
new Script()
- .initializeUser(USER_ID, UserCase.OWNER,
+ .initializeUser(USER_ID, UserCase.UNRESTRICTED,
CONFIG_AUTO_TIME_ZONE_DETECTION_DISABLED)
.initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
AtomicBoolean dumpCalled = new AtomicBoolean(false);
class FakeDumpable implements Dumpable {
@Override
- public void dump(PrintWriter pw, String[] args) {
+ public void dump(IndentingPrintWriter pw, String[] args) {
dumpCalled.set(true);
}
}
mTimeZoneDetectorStrategy.addDumpable(new FakeDumpable());
- PrintWriter pw = new PrintWriter(new StringWriter());
+ IndentingPrintWriter ipw = new IndentingPrintWriter(new StringWriter());
String[] args = {"ArgOne", "ArgTwo"};
- mTimeZoneDetectorStrategy.dump(pw, args);
+ mTimeZoneDetectorStrategy.dump(ipw, args);
assertTrue(dumpCalled.get());
}
@@ -912,12 +926,15 @@ public class TimeZoneDetectorStrategyImplTest {
/** Simulated user test cases. */
enum UserCase {
- /** A catch-all for users that can set time zone config. */
- OWNER,
- /** A catch-all for users that can't set time zone config. */
- NON_OWNER,
- /** Owner, but auto tz detection is not supported on the device. */
- OWNER_AUTO_DETECT_NOT_SUPPORTED,
+ /** A catch-all for users that can set auto time zone config. */
+ UNRESTRICTED,
+ /** A catch-all for users that can't set auto time zone config. */
+ RESTRICTED,
+ /**
+ * Like {@link #UNRESTRICTED}, but auto tz detection is not
+ * supported on the device.
+ */
+ AUTO_DETECT_NOT_SUPPORTED,
}
/**
@@ -927,7 +944,7 @@ public class TimeZoneDetectorStrategyImplTest {
private static TimeZoneCapabilities createCapabilities(
int userId, UserCase userRole, TimeZoneConfiguration configuration) {
switch (userRole) {
- case OWNER: {
+ case UNRESTRICTED: {
int suggestManualTimeZoneCapability = configuration.isAutoDetectionEnabled()
? CAPABILITY_NOT_APPLICABLE : CAPABILITY_POSSESSED;
return new TimeZoneCapabilities.Builder(userId)
@@ -935,14 +952,14 @@ public class TimeZoneDetectorStrategyImplTest {
.setSuggestManualTimeZone(suggestManualTimeZoneCapability)
.build();
}
- case NON_OWNER: {
+ case RESTRICTED: {
return new TimeZoneCapabilities.Builder(userId)
.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_ALLOWED)
.setSuggestManualTimeZone(CAPABILITY_NOT_ALLOWED)
.build();
}
- case OWNER_AUTO_DETECT_NOT_SUPPORTED: {
+ case AUTO_DETECT_NOT_SUPPORTED: {
return new TimeZoneCapabilities.Builder(userId)
.setConfigureAutoDetectionEnabled(CAPABILITY_NOT_SUPPORTED)
.setSuggestManualTimeZone(CAPABILITY_POSSESSED)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 1b42a0466cf7..373eed921580 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -1331,42 +1331,40 @@ public class ActivityStackTests extends ActivityTestsBase {
}
@Test
- public void testCheckBehindFullscreenActivity() {
+ public void testIterateOccludedActivity() {
final ArrayList<ActivityRecord> occludedActivities = new ArrayList<>();
- final Consumer<ActivityRecord> handleBehindFullscreenActivity = occludedActivities::add;
+ final Consumer<ActivityRecord> handleOccludedActivity = occludedActivities::add;
final ActivityRecord bottomActivity =
new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
final ActivityRecord topActivity =
new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+ // Top activity occludes bottom activity.
doReturn(true).when(mStack).shouldBeVisible(any());
- assertTrue(mStack.checkBehindFullscreenActivity(bottomActivity,
- null /* handleBehindFullscreenActivity */));
- assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
- null /* handleBehindFullscreenActivity */));
+ assertTrue(topActivity.shouldBeVisible());
+ assertFalse(bottomActivity.shouldBeVisible());
- // Top activity occludes bottom activity.
- mStack.checkBehindFullscreenActivity(null /* toCheck */, handleBehindFullscreenActivity);
+ mStack.forAllOccludedActivities(handleOccludedActivity);
assertThat(occludedActivities).containsExactly(bottomActivity);
+ // Top activity doesn't occlude parent, so the bottom activity is not occluded.
doReturn(false).when(topActivity).occludesParent();
- assertFalse(mStack.checkBehindFullscreenActivity(bottomActivity,
- null /* handleBehindFullscreenActivity */));
- assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
- null /* handleBehindFullscreenActivity */));
+ assertTrue(bottomActivity.shouldBeVisible());
occludedActivities.clear();
- // Top activity doesn't occlude parent, so the bottom activity is not occluded.
- mStack.checkBehindFullscreenActivity(null /* toCheck */, handleBehindFullscreenActivity);
+ mStack.forAllOccludedActivities(handleOccludedActivity);
assertThat(occludedActivities).isEmpty();
+ // A finishing activity should not occlude other activities behind.
final ActivityRecord finishingActivity =
new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
finishingActivity.finishing = true;
doCallRealMethod().when(finishingActivity).occludesParent();
- assertFalse(mStack.checkBehindFullscreenActivity(bottomActivity,
- null /* handleBehindFullscreenActivity */));
- assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
- null /* handleBehindFullscreenActivity */));
+ assertTrue(topActivity.shouldBeVisible());
+ assertTrue(bottomActivity.shouldBeVisible());
+
+ occludedActivities.clear();
+ mStack.forAllOccludedActivities(handleOccludedActivity);
+ assertThat(occludedActivities).isEmpty();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 4a19684e5554..e3b1d6306a81 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -200,7 +200,8 @@ public class ActivityStarterTests extends ActivityTestsBase {
ai.packageName = "com.android.test.package";
final WindowProcessController wpc =
containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
- ? null : new WindowProcessController(service, ai, null, 0, -1, null, listener);
+ ? null
+ : new WindowProcessController(service, ai, null, 0, -1, null, listener);
doReturn(wpc).when(service).getProcessController(any());
final Intent intent = new Intent();
@@ -211,7 +212,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
IVoiceInteractionSession voiceSession =
containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
- ? mock(IVoiceInteractionSession.class) : null;
+ ? mock(IVoiceInteractionSession.class) : null;
// Create source token
final ActivityBuilder builder = new ActivityBuilder(service).setTask(
@@ -489,13 +490,12 @@ public class ActivityStarterTests extends ActivityTestsBase {
}
private void assertNoTasks(DisplayContent display) {
- for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
+ display.forAllTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
assertFalse(stack.hasChild());
}
- }
+ });
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 1fefb0c481d1..9d0cd26bc040 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -591,15 +591,14 @@ class ActivityTestsBase extends SystemServiceTestsBase {
mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
mSecondary.mRemoteToken.toWindowContainerToken());
DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
- for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
+ dc.forAllTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) {
stack.reparent(mSecondary, POSITION_BOTTOM);
}
}
- }
+ });
}
@Override
public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index 4ba08d7cd005..a8fc66da9bd0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -16,15 +16,19 @@
package com.android.server.wm;
+import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED;
+import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
import static com.android.server.wm.DisplayAreaPolicyBuilder.Feature;
@@ -33,13 +37,18 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
import static java.util.stream.Collectors.toList;
import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
+import com.google.android.collect.Lists;
+
import org.hamcrest.CustomTypeSafeMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
@@ -74,6 +83,10 @@ public class DisplayAreaPolicyBuilderTest {
private DisplayContent mDisplayContent;
private TaskDisplayArea mDefaultTaskDisplayArea;
private List<TaskDisplayArea> mTaskDisplayAreaList;
+ private RootDisplayArea mGroupRoot1;
+ private RootDisplayArea mGroupRoot2;
+ private TaskDisplayArea mTda1;
+ private TaskDisplayArea mTda2;
@Before
public void setup() {
@@ -85,6 +98,10 @@ public class DisplayAreaPolicyBuilderTest {
FEATURE_DEFAULT_TASK_CONTAINER);
mTaskDisplayAreaList = new ArrayList<>();
mTaskDisplayAreaList.add(mDefaultTaskDisplayArea);
+ mGroupRoot1 = new SurfacelessDisplayAreaRoot(mWms, "group1", FEATURE_VENDOR_FIRST + 1);
+ mGroupRoot2 = new SurfacelessDisplayAreaRoot(mWms, "group2", FEATURE_VENDOR_FIRST + 2);
+ mTda1 = new TaskDisplayArea(mDisplayContent, mWms, "tda1", FEATURE_VENDOR_FIRST + 3);
+ mTda2 = new TaskDisplayArea(mDisplayContent, mWms, "tda2", FEATURE_VENDOR_FIRST + 4);
}
@Test
@@ -191,6 +208,271 @@ public class DisplayAreaPolicyBuilderTest {
}
}
+ @Test
+ public void testBuilder_singleRoot_validateSettings() {
+ final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder();
+
+ // Root must be set.
+ assertThrows(IllegalStateException.class, () -> builder.build(mWms));
+
+ // IME must be set.
+ builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList));
+
+ assertThrows(IllegalStateException.class, () -> builder.build(mWms));
+
+ // Default TaskDisplayArea must be set.
+ builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(
+ new TaskDisplayArea(mDisplayContent, mWms, "testTda",
+ FEATURE_VENDOR_FIRST + 1))));
+
+ assertThrows(IllegalStateException.class, () -> builder.build(mWms));
+
+ // No exception
+ builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(mTaskDisplayAreaList));
+
+ builder.build(mWms);
+ }
+
+ @Test
+ public void testBuilder_displayAreaGroup_validateSettings() {
+ final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder();
+
+ // IME must be set to one of the roots.
+ builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot));
+ builder1.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setTaskDisplayAreas(mTaskDisplayAreaList));
+
+ assertThrows(IllegalStateException.class, () -> builder1.build(mWms));
+
+ // Default TaskDisplayArea must be set.
+ final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
+ builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot));
+ builder2.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(
+ new TaskDisplayArea(mDisplayContent, mWms, "testTda",
+ FEATURE_VENDOR_FIRST + 1))));
+
+ assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
+
+ // Each DisplayAreaGroup must have at least one TaskDisplayArea.
+ final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder();
+ builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot));
+ builder3.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(mTaskDisplayAreaList));
+ builder3.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2));
+
+ assertThrows(IllegalStateException.class, () -> builder3.build(mWms));
+
+ // No exception
+ final DisplayAreaPolicyBuilder builder4 = new DisplayAreaPolicyBuilder();
+ builder4.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot));
+ builder4.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(mTaskDisplayAreaList));
+ builder4.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(
+ new TaskDisplayArea(mDisplayContent, mWms, "testTda",
+ FEATURE_VENDOR_FIRST + 1))));
+
+ builder4.build(mWms);
+ }
+
+ @Test
+ public void testBuilder_displayAreaGroup_attachDisplayAreas() {
+ final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda1)))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda2)))
+ .build(mWms);
+
+ assertThat(mDefaultTaskDisplayArea.isDescendantOf(mRoot)).isTrue();
+ assertThat(mGroupRoot1.isDescendantOf(mRoot)).isTrue();
+ assertThat(mGroupRoot2.isDescendantOf(mRoot)).isTrue();
+ assertThat(mImeContainer.isDescendantOf(mGroupRoot1)).isTrue();
+ assertThat(mTda1.isDescendantOf(mGroupRoot1)).isTrue();
+ assertThat(mTda2.isDescendantOf(mGroupRoot2)).isTrue();
+ assertThat(isSibling(mDefaultTaskDisplayArea, mGroupRoot1)).isTrue();
+ assertThat(isSibling(mDefaultTaskDisplayArea, mGroupRoot2)).isTrue();
+ }
+
+ @Test
+ public void testBuilder_displayAreaGroup_createFeatureOnGroup() {
+ final Feature feature1 = new Feature.Builder(mWms.mPolicy, "feature1",
+ FEATURE_VENDOR_FIRST + 5)
+ .all()
+ .except(TYPE_STATUS_BAR)
+ .build();
+ final Feature feature2 = new Feature.Builder(mWms.mPolicy, "feature2",
+ FEATURE_VENDOR_FIRST + 6)
+ .upTo(TYPE_STATUS_BAR)
+ .and(TYPE_NAVIGATION_BAR)
+ .build();
+ final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda1))
+ .addFeature(feature1))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda2))
+ .addFeature(feature2))
+ .build(mWms);
+
+ List<DisplayArea<? extends WindowContainer>> feature1DAs =
+ policy.getDisplayAreas(feature1.getId());
+ List<DisplayArea<? extends WindowContainer>> feature2DAs =
+ policy.getDisplayAreas(feature2.getId());
+ for (DisplayArea<? extends WindowContainer> da : feature1DAs) {
+ assertThat(da.isDescendantOf(mGroupRoot1)).isTrue();
+ }
+ for (DisplayArea<? extends WindowContainer> da : feature2DAs) {
+ assertThat(da.isDescendantOf(mGroupRoot2)).isTrue();
+ }
+ }
+
+ @Test
+ public void testBuilder_addWindow_selectContainerForWindowFunc_defaultFunc() {
+ final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda1)))
+ .addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda2)))
+ .build(mWms);
+
+ final WindowToken token = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
+ policy.addWindow(token);
+
+ // By default, window are always added to the root.
+ assertThat(token.isDescendantOf(mRoot)).isTrue();
+ assertThat(token.isDescendantOf(mGroupRoot1)).isFalse();
+ assertThat(token.isDescendantOf(mGroupRoot2)).isFalse();
+ }
+
+ @Test
+ public void testBuilder_addWindow_selectContainerForWindowFunc_selectBasedOnType() {
+ final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 =
+ new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda1));
+ final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 =
+ new DisplayAreaPolicyBuilder.HierarchyBuilder(mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda2));
+ final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList))
+ .addDisplayAreaGroupHierarchy(hierarchy1)
+ .addDisplayAreaGroupHierarchy(hierarchy2)
+ .setSelectRootForWindowFunc((token, options) -> {
+ if (token.windowType == TYPE_STATUS_BAR) {
+ return mGroupRoot1;
+ }
+ return mGroupRoot2;
+ })
+ .build(mWms);
+
+ final WindowToken token1 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
+ final WindowToken token2 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_WALLPAPER, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
+ policy.addWindow(token1);
+ policy.addWindow(token2);
+
+ assertThat(token1.isDescendantOf(mGroupRoot1)).isTrue();
+ assertThat(token2.isDescendantOf(mGroupRoot2)).isTrue();
+ }
+
+ @Test
+ public void testBuilder_addWindow_selectContainerForWindowFunc_selectBasedOnOptions() {
+ final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy0 =
+ new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+ .setTaskDisplayAreas(mTaskDisplayAreaList);
+ final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy1 =
+ new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot1)
+ .setImeContainer(mImeContainer)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda1));
+ final DisplayAreaPolicyBuilder.HierarchyBuilder hierarchy2 =
+ new DisplayAreaPolicyBuilder.HierarchyBuilder(
+ mGroupRoot2)
+ .setTaskDisplayAreas(Lists.newArrayList(mTda2));
+ final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
+ .setRootHierarchy(hierarchy0)
+ .addDisplayAreaGroupHierarchy(hierarchy1)
+ .addDisplayAreaGroupHierarchy(hierarchy2)
+ .setSelectRootForWindowFunc((token, options) -> {
+ if (options == null) {
+ return mRoot;
+ }
+ if (options.getInt("HIERARCHY_ROOT_ID") == mGroupRoot1.mFeatureId) {
+ return mGroupRoot1;
+ }
+ if (options.getInt("HIERARCHY_ROOT_ID") == mGroupRoot2.mFeatureId) {
+ return mGroupRoot2;
+ }
+ return mRoot;
+ })
+ .build(mWms);
+
+ final Bundle options1 = new Bundle();
+ options1.putInt("HIERARCHY_ROOT_ID", mGroupRoot1.mFeatureId);
+ final Bundle options2 = new Bundle();
+ options2.putInt("HIERARCHY_ROOT_ID", mGroupRoot2.mFeatureId);
+ final WindowToken token0 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
+ final WindowToken token1 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, options1);
+ final WindowToken token2 = new WindowToken(mWms, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, options2);
+
+ policy.addWindow(token0);
+ policy.addWindow(token1);
+ policy.addWindow(token2);
+
+ assertThat(token0.isDescendantOf(mRoot)).isTrue();
+ assertThat(token1.isDescendantOf(mGroupRoot1)).isTrue();
+ assertThat(token2.isDescendantOf(mGroupRoot2)).isTrue();
+ }
+
private static Resources resourcesWithProvider(String provider) {
Resources mock = mock(Resources.class);
when(mock.getString(
@@ -260,6 +542,10 @@ public class DisplayAreaPolicyBuilderTest {
};
}
+ private boolean isSibling(WindowContainer da1, WindowContainer da2) {
+ return da1.getParent() != null && da1.getParent() == da2.getParent();
+ }
+
private WindowToken tokenOfType(int type) {
WindowToken m = mock(WindowToken.class);
when(m.getWindowLayerFromType()).thenReturn(
@@ -290,10 +576,14 @@ public class DisplayAreaPolicyBuilderTest {
}
}
- private static class SurfacelessDisplayAreaRoot extends RootDisplayArea {
+ static class SurfacelessDisplayAreaRoot extends RootDisplayArea {
SurfacelessDisplayAreaRoot(WindowManagerService wms) {
- super(wms);
+ this(wms, "SurfacelessDisplayAreaRoot", FEATURE_ROOT);
+ }
+
+ SurfacelessDisplayAreaRoot(WindowManagerService wms, String name, int featureId) {
+ super(wms, name, featureId);
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index 880c486c15af..c8ed87db9d3e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -19,47 +19,74 @@ package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
import static com.android.server.wm.DisplayArea.Type.ANY;
import static com.android.server.wm.DisplayArea.Type.BELOW_TASKS;
import static com.android.server.wm.DisplayArea.Type.checkChild;
import static com.android.server.wm.DisplayArea.Type.checkSiblings;
import static com.android.server.wm.DisplayArea.Type.typeOf;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.testing.Assert.assertThrows;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
-import android.view.SurfaceControl;
+import com.google.android.collect.Lists;
+
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Tests for the {@link DisplayArea} container.
+ *
+ * Build/Install/Run:
+ * atest WmTests:DisplayAreaTest
+ */
@Presubmit
public class DisplayAreaTest {
@Rule
public SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
+ private WindowManagerService mWms;
+
+ @Before
+ public void setup() {
+ mWms = mWmsRule.getWindowManagerService();
+ }
+
@Test
public void testDisplayArea_positionChanged_throwsIfIncompatibleChild() {
- WindowManagerService wms = mWmsRule.getWindowManagerService();
- DisplayArea<WindowContainer> parent = new DisplayArea<>(wms, BELOW_TASKS, "Parent");
- DisplayArea<WindowContainer> child = new DisplayArea<>(wms, ANY, "Child");
+ DisplayArea<WindowContainer> parent = new DisplayArea<>(mWms, BELOW_TASKS, "Parent");
+ DisplayArea<WindowContainer> child = new DisplayArea<>(mWms, ANY, "Child");
assertThrows(IllegalStateException.class, () -> parent.addChild(child, 0));
}
@Test
public void testType_typeOf() {
- WindowManagerService wms = mWmsRule.getWindowManagerService();
-
- assertEquals(ABOVE_TASKS, typeOf(new DisplayArea<>(wms, ABOVE_TASKS, "test")));
- assertEquals(ANY, typeOf(new DisplayArea<>(wms, ANY, "test")));
- assertEquals(BELOW_TASKS, typeOf(new DisplayArea<>(wms, BELOW_TASKS, "test")));
+ assertEquals(ABOVE_TASKS, typeOf(new DisplayArea<>(mWms, ABOVE_TASKS, "test")));
+ assertEquals(ANY, typeOf(new DisplayArea<>(mWms, ANY, "test")));
+ assertEquals(BELOW_TASKS, typeOf(new DisplayArea<>(mWms, BELOW_TASKS, "test")));
assertEquals(ABOVE_TASKS, typeOf(createWindowToken(TYPE_APPLICATION_OVERLAY)));
assertEquals(ABOVE_TASKS, typeOf(createWindowToken(TYPE_PRESENTATION)));
@@ -97,21 +124,264 @@ public class DisplayAreaTest {
assertThrows(IllegalStateException.class, () -> checkChild(BELOW_TASKS, ANY));
}
- private WindowToken createWindowToken(int type) {
- return new WindowToken(mWmsRule.getWindowManagerService(), new Binder(),
- type, false /* persist */, null /* displayContent */,
- false /* canManageTokens */);
+ @Test
+ public void testAsDisplayArea() {
+ final WindowContainer windowContainer = new WindowContainer(mWms);
+ final DisplayArea<WindowContainer> displayArea = new DisplayArea<>(mWms, ANY, "DA");
+ final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(null /* displayContent */,
+ mWms, "TDA", FEATURE_DEFAULT_TASK_CONTAINER);
+
+ assertThat(windowContainer.asDisplayArea()).isNull();
+ assertThat(displayArea.asDisplayArea()).isEqualTo(displayArea);
+ assertThat(taskDisplayArea.asDisplayArea()).isEqualTo(taskDisplayArea);
}
- private static class SurfacelessDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
+ @Test
+ public void testForAllTaskDisplayAreas_onlyTraversesDisplayAreaOfTypeAny() {
+ final RootDisplayArea root =
+ new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWms);
+ final Function<TaskDisplayArea, Boolean> callback0 = tda -> false;
+ final Consumer<TaskDisplayArea> callback1 = tda -> { };
+ final BiFunction<TaskDisplayArea, Integer, Integer> callback2 = (tda, result) -> result;
+ final Function<TaskDisplayArea, TaskDisplayArea> callback3 = tda -> null;
+
+ // Don't traverse the child if the current DA has type BELOW_TASKS
+ final DisplayArea<WindowContainer> da1 = new DisplayArea<>(mWms, BELOW_TASKS, "DA1");
+ final DisplayArea<WindowContainer> da2 = new DisplayArea<>(mWms, BELOW_TASKS, "DA2");
+ root.addChild(da1, POSITION_BOTTOM);
+ da1.addChild(da2, POSITION_TOP);
+ spyOn(da2);
+
+ da1.forAllTaskDisplayAreas(callback0);
+ da1.forAllTaskDisplayAreas(callback1);
+ da1.reduceOnAllTaskDisplayAreas(callback2, 0);
+ da1.getItemFromTaskDisplayAreas(callback3);
+
+ verifyZeroInteractions(da2);
+
+ // Traverse the child if the current DA has type ANY
+ final DisplayArea<WindowContainer> da3 = new DisplayArea<>(mWms, ANY, "DA3");
+ final DisplayArea<WindowContainer> da4 = new DisplayArea<>(mWms, ANY, "DA4");
+ root.addChild(da3, POSITION_TOP);
+ da3.addChild(da4, POSITION_TOP);
+ spyOn(da4);
+
+ da3.forAllTaskDisplayAreas(callback0);
+ da3.forAllTaskDisplayAreas(callback1);
+ da3.reduceOnAllTaskDisplayAreas(callback2, 0);
+ da3.getItemFromTaskDisplayAreas(callback3);
+
+ verify(da4).forAllTaskDisplayAreas(callback0, true /* traverseTopToBottom */);
+ verify(da4).forAllTaskDisplayAreas(callback1, true /* traverseTopToBottom */);
+ verify(da4).reduceOnAllTaskDisplayAreas(callback2, 0 /* initValue */,
+ true /* traverseTopToBottom */);
+ verify(da4).getItemFromTaskDisplayAreas(
+ callback3, true /* traverseTopToBottom */);
+
+ // Don't traverse the child if the current DA has type ABOVE_TASKS
+ final DisplayArea<WindowContainer> da5 = new DisplayArea<>(mWms, ABOVE_TASKS, "DA5");
+ final DisplayArea<WindowContainer> da6 = new DisplayArea<>(mWms, ABOVE_TASKS, "DA6");
+ root.addChild(da5, POSITION_TOP);
+ da5.addChild(da6, POSITION_TOP);
+ spyOn(da6);
+
+ da5.forAllTaskDisplayAreas(callback0);
+ da5.forAllTaskDisplayAreas(callback1);
+ da5.reduceOnAllTaskDisplayAreas(callback2, 0);
+ da5.getItemFromTaskDisplayAreas(callback3);
+
+ verifyZeroInteractions(da6);
+ }
+
+ @Test
+ public void testForAllTaskDisplayAreas_appliesOnTaskDisplayAreaInOrder() {
+ final RootDisplayArea root =
+ new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWms);
+ final DisplayArea<DisplayArea> da1 =
+ new DisplayArea<>(mWms, ANY, "DA1");
+ final DisplayArea<DisplayArea> da2 =
+ new DisplayArea<>(mWms, ANY, "DA2");
+ final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */,
+ mWms, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
+ final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */,
+ mWms, "TDA2", FEATURE_VENDOR_FIRST);
+ final TaskDisplayArea tda3 = new TaskDisplayArea(null /* displayContent */,
+ mWms, "TDA3", FEATURE_VENDOR_FIRST + 1);
+ root.addChild(da1, POSITION_TOP);
+ root.addChild(da2, POSITION_TOP);
+ da1.addChild(tda1, POSITION_TOP);
+ da2.addChild(tda2, POSITION_TOP);
+ da2.addChild(tda3, POSITION_TOP);
+
+ /* The hierarchy looks like this
+ Root
+ - DA1
+ - TDA1 ------ bottom
+ - DA2
+ - TDA2
+ - TDA3 ------ top
+ */
+
+ // Test forAllTaskDisplayAreas(Consumer<TaskDisplayArea>)
+ List<TaskDisplayArea> actualOrder = new ArrayList<>();
+ root.forAllTaskDisplayAreas(tda -> {
+ actualOrder.add(tda);
+ });
+
+ assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda3, tda2, tda1));
+
+ // Test forAllTaskDisplayAreas(Consumer<TaskDisplayArea>, boolean)
+ actualOrder.clear();
+ root.forAllTaskDisplayAreas(tda -> {
+ actualOrder.add(tda);
+ }, false /* traverseTopToBottom */);
+
+ assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda1, tda2, tda3));
+
+ // Test forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean>)
+ actualOrder.clear();
+ root.forAllTaskDisplayAreas(tda -> {
+ actualOrder.add(tda);
+ return false;
+ });
+
+ assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda3, tda2, tda1));
- SurfacelessDisplayArea(WindowManagerService wms, Type type, String name) {
- super(wms, type, name);
- }
+ // Test forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean>, boolean)
+ actualOrder.clear();
+ root.forAllTaskDisplayAreas(tda -> {
+ actualOrder.add(tda);
+ return false;
+ }, false /* traverseTopToBottom */);
- @Override
- SurfaceControl.Builder makeChildSurface(WindowContainer child) {
- return new MockSurfaceControlBuilder();
- }
+ assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda1, tda2, tda3));
+
+ // Test forAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R>, R)
+ actualOrder.clear();
+ root.reduceOnAllTaskDisplayAreas((tda, result) -> {
+ actualOrder.add(tda);
+ return result;
+ }, 0 /* initValue */);
+
+ assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda3, tda2, tda1));
+
+ // Test forAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R>, R, boolean)
+ actualOrder.clear();
+ root.reduceOnAllTaskDisplayAreas((tda, result) -> {
+ actualOrder.add(tda);
+ return result;
+ }, 0 /* initValue */, false /* traverseTopToBottom */);
+
+ assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda1, tda2, tda3));
+
+ // Test <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback)
+ actualOrder.clear();
+ root.getItemFromTaskDisplayAreas(tda -> {
+ actualOrder.add(tda);
+ return null;
+ });
+
+ assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda3, tda2, tda1));
+
+ // Test <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback, boolean)
+ actualOrder.clear();
+ root.getItemFromTaskDisplayAreas(tda -> {
+ actualOrder.add(tda);
+ return null;
+ }, false /* traverseTopToBottom */);
+
+ assertThat(actualOrder).isEqualTo(Lists.newArrayList(tda1, tda2, tda3));
+ }
+
+ @Test
+ public void testForAllTaskDisplayAreas_returnsWhenCallbackReturnTrue() {
+ final RootDisplayArea root =
+ new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWms);
+ final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */,
+ mWms, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
+ final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */,
+ mWms, "TDA2", FEATURE_VENDOR_FIRST);
+ root.addChild(tda1, POSITION_TOP);
+ root.addChild(tda2, POSITION_TOP);
+
+ /* The hierarchy looks like this
+ Root
+ - TDA1 ------ bottom
+ - TDA2 ------ top
+ */
+
+ root.forAllTaskDisplayAreas(tda -> {
+ assertThat(tda).isEqualTo(tda2);
+ return true;
+ });
+
+ root.forAllTaskDisplayAreas(tda -> {
+ assertThat(tda).isEqualTo(tda1);
+ return true;
+ }, false /* traverseTopToBottom */);
+ }
+
+ @Test
+ public void testReduceOnAllTaskDisplayAreas_returnsTheAccumulativeResult() {
+ final RootDisplayArea root =
+ new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWms);
+ final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */,
+ mWms, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
+ final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */,
+ mWms, "TDA2", FEATURE_VENDOR_FIRST);
+ root.addChild(tda1, POSITION_TOP);
+ root.addChild(tda2, POSITION_TOP);
+
+ /* The hierarchy looks like this
+ Root
+ - TDA1 ------ bottom
+ - TDA2 ------ top
+ */
+
+ String accumulativeName = root.reduceOnAllTaskDisplayAreas((tda, result) ->
+ result + tda.getName(), "" /* initValue */);
+ assertThat(accumulativeName).isEqualTo("TDA2TDA1");
+
+ accumulativeName = root.reduceOnAllTaskDisplayAreas((tda, result) ->
+ result + tda.getName(), "" /* initValue */, false /* traverseTopToBottom */);
+ assertThat(accumulativeName).isEqualTo("TDA1TDA2");
+ }
+
+ @Test
+ public void testGetItemFromTaskDisplayAreas_returnsWhenCallbackReturnNotNull() {
+ final RootDisplayArea root =
+ new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWms);
+ final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */,
+ mWms, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
+ final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */,
+ mWms, "TDA2", FEATURE_VENDOR_FIRST);
+ root.addChild(tda1, POSITION_TOP);
+ root.addChild(tda2, POSITION_TOP);
+
+ /* The hierarchy looks like this
+ Root
+ - TDA1 ------ bottom
+ - TDA2 ------ top
+ */
+
+ TaskDisplayArea result = root.getItemFromTaskDisplayAreas(tda -> {
+ assertThat(tda).isEqualTo(tda2);
+ return tda;
+ });
+
+ assertThat(result).isEqualTo(tda2);
+
+ result = root.getItemFromTaskDisplayAreas(tda -> {
+ assertThat(tda).isEqualTo(tda1);
+ return tda;
+ }, false /* traverseTopToBottom */);
+
+ assertThat(result).isEqualTo(tda1);
+ }
+
+ private WindowToken createWindowToken(int type) {
+ return new WindowToken(mWmsRule.getWindowManagerService(), new Binder(),
+ type, false /* persist */, null /* displayContent */,
+ false /* canManageTokens */);
}
}
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 f4f199ca52a1..018b3027bdff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -96,13 +96,10 @@ import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.view.DisplayCutout;
import android.view.Gravity;
-import android.view.IDisplayWindowInsetsController;
import android.view.IDisplayWindowRotationCallback;
import android.view.IDisplayWindowRotationController;
import android.view.ISystemGestureExclusionListener;
import android.view.IWindowManager;
-import android.view.InsetsSourceControl;
-import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceControl.Transaction;
@@ -950,6 +947,26 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testComputeImeControlTarget_exitingApp() throws Exception {
+ final DisplayContent dc = createNewDisplay();
+
+ WindowState exitingWin = createWindow(null, TYPE_BASE_APPLICATION, "exiting app");
+ makeWindowVisible(exitingWin);
+ exitingWin.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+ exitingWin.mAnimatingExit = true;
+
+ dc.mInputMethodControlTarget = exitingWin;
+ dc.mInputMethodTarget = dc.mInputMethodInputTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, "starting app");
+
+ assertEquals(exitingWin, dc.computeImeControlTarget());
+
+ exitingWin.removeImmediately();
+
+ assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget());
+ }
+
+ @Test
public void testComputeImeControlTarget_splitscreen() throws Exception {
final DisplayContent dc = createNewDisplay();
dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app");
@@ -970,28 +987,6 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(mAppWindow, mDisplayContent.computeImeControlTarget());
}
- private IDisplayWindowInsetsController createDisplayWindowInsetsController() {
- return new IDisplayWindowInsetsController.Stub() {
-
- @Override
- public void insetsChanged(InsetsState insetsState) throws RemoteException {
- }
-
- @Override
- public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] insetsSourceControls) throws RemoteException {
- }
-
- @Override
- public void showInsets(int i, boolean b) throws RemoteException {
- }
-
- @Override
- public void hideInsets(int i, boolean b) throws RemoteException {
- }
- };
- }
-
@Test
public void testUpdateSystemGestureExclusion() throws Exception {
final DisplayContent dc = createNewDisplay();
@@ -1487,7 +1482,6 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testEnsureActivitiesVisibleNotRecursive() {
final TaskDisplayArea mockTda = mock(TaskDisplayArea.class);
- doReturn(mockTda).when(mDisplayContent).getTaskDisplayAreaAt(anyInt());
final boolean[] called = { false };
doAnswer(invocation -> {
// The assertion will fail if DisplayArea#ensureActivitiesVisible is called twice.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index b69a1f3f7766..da7c41a74528 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -828,28 +828,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
}
@Test
- public void forceShowSystemBars_clearsSystemUIFlags() {
- doCallRealMethod().when(mDisplayPolicy).updateSystemUiVisibilityLw();
- mDisplayPolicy.mLastSystemUiFlags |= SYSTEM_UI_FLAG_FULLSCREEN;
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- mWindow.mAttrs.flags =
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mWindow.mSystemUiVisibility = SYSTEM_UI_FLAG_FULLSCREEN;
- mDisplayPolicy.setForceShowSystemBars(true);
- addWindow(mWindow);
-
- mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
- // triggers updateSystemUiVisibilityLw which will reset the flags as needed
- int finishPostLayoutPolicyLw = mDisplayPolicy.focusChangedLw(mWindow, mWindow);
-
- assertEquals(WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT, finishPostLayoutPolicyLw);
- assertEquals(0, mDisplayPolicy.mLastSystemUiFlags);
- assertEquals(0, mWindow.mAttrs.systemUiVisibility);
- assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- }
-
- @Test
public void testScreenDecorWindows() {
final WindowState decorWindow = spy(
createWindow(null, TYPE_APPLICATION_OVERLAY, "decorWindow"));
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index c794e1a3b328..87bc7f1bf781 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -172,8 +172,9 @@ public class InsetsPolicyTest extends WindowTestsBase {
}
@Test
- public void testControlsForDispatch_forceShowSystemBarsFromExternal_appHasNoControl() {
- mDisplayContent.getDisplayPolicy().setForceShowSystemBars(true);
+ public void testControlsForDispatch_remoteInsetsControllerControlsBars_appHasNoControl() {
+ mDisplayContent.setRemoteInsetsController(createDisplayWindowInsetsController());
+ mDisplayContent.getInsetsPolicy().setRemoteInsetsControllerControlsSystemBars(true);
addWindow(TYPE_STATUS_BAR, "statusBar");
addWindow(TYPE_NAVIGATION_BAR, "navBar");
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index add2054d5638..13f04d23ccd3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -46,7 +46,6 @@ import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.testutils.OffsettableClock;
@@ -244,7 +243,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
}
@Test
- public void testChange() throws Exception {
+ public void testChangeToSmallerSize() throws Exception {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
mDisplayContent.mChangingContainers.add(win.mActivityRecord);
try {
@@ -279,8 +278,61 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
assertEquals(false, app.isTranslucent);
verify(mMockTransaction).setPosition(
mMockLeash, app.startBounds.left, app.startBounds.top);
- verify(mMockTransaction).setWindowCrop(mMockLeash, 200, 200);
+ verify(mMockTransaction).setWindowCrop(
+ mMockLeash, app.startBounds.width(), app.startBounds.height());
verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
+ verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, -1, -1);
+
+ finishedCaptor.getValue().onAnimationFinished();
+ verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
+ eq(record.mAdapter));
+ verify(mThumbnailFinishedCallback).onAnimationFinished(
+ eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter));
+ } finally {
+ mDisplayContent.mChangingContainers.clear();
+ }
+ }
+
+ @Test
+ public void testChangeTolargerSize() throws Exception {
+ final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
+ mDisplayContent.mChangingContainers.add(win.mActivityRecord);
+ try {
+ final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
+ win.mActivityRecord, new Point(0, 0), null, new Rect(0, 0, 200, 200),
+ new Rect(50, 100, 150, 150));
+ assertNotNull(record.mThumbnailAdapter);
+ ((AnimationAdapter) record.mAdapter)
+ .startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION,
+ mFinishedCallback);
+ ((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
+ mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
+ mController.goodToGo();
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
+ ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
+ verify(mMockRunner).onAnimationStart(appsCaptor.capture(), wallpapersCaptor.capture(),
+ finishedCaptor.capture());
+ assertEquals(1, appsCaptor.getValue().length);
+ final RemoteAnimationTarget app = appsCaptor.getValue()[0];
+ assertEquals(RemoteAnimationTarget.MODE_CHANGING, app.mode);
+ assertEquals(new Point(0, 0), app.position);
+ assertEquals(new Rect(0, 0, 200, 200), app.sourceContainerBounds);
+ assertEquals(new Rect(50, 100, 150, 150), app.startBounds);
+ assertEquals(mMockLeash, app.leash);
+ assertEquals(mMockThumbnailLeash, app.startLeash);
+ assertEquals(win.mWinAnimator.mLastClipRect, app.clipRect);
+ assertEquals(false, app.isTranslucent);
+ verify(mMockTransaction).setPosition(
+ mMockLeash, app.startBounds.left, app.startBounds.top);
+ verify(mMockTransaction).setWindowCrop(
+ mMockLeash, app.startBounds.width(), app.startBounds.height());
+ verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
+ verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, -1, -1);
finishedCaptor.getValue().onAnimationFinished();
verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 51db099676b0..d9ec0b138552 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -292,13 +292,11 @@ public class RootActivityContainerTests extends ActivityTestsBase {
assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount());
final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent();
- doReturn(2).when(dc).getTaskDisplayAreaCount();
final TaskDisplayArea secondTaskDisplayArea = new TaskDisplayArea(dc,
mRootWindowContainer.mWmService, "SecondaryTaskDisplayArea", FEATURE_VENDOR_FIRST);
// Add second display area right above the default one
defaultTaskDisplayArea.getParent().addChild(secondTaskDisplayArea,
defaultTaskDisplayArea.getParent().mChildren.indexOf(defaultTaskDisplayArea) + 1);
- doReturn(secondTaskDisplayArea).when(dc).getTaskDisplayAreaAt(1);
final ActivityStack secondStack = secondTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
new ActivityBuilder(mService).setCreateTask(true).setStack(secondStack)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 35d1b17d5822..181de8e2a1a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -148,7 +148,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
@Test
public void testAllPausedActivitiesComplete() {
DisplayContent displayContent = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
- TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(0);
+ TaskDisplayArea taskDisplayArea = displayContent.getDefaultTaskDisplayArea();
ActivityStack stack = taskDisplayArea.getStackAt(0);
ActivityRecord activity = createActivityRecord(displayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index d2a2732d60ab..213c1f52aa37 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -43,10 +43,9 @@ class TestDisplayContent extends DisplayContent {
// hard-code to FULLSCREEN for tests.
setWindowingMode(WINDOWING_MODE_FULLSCREEN);
spyOn(this);
- for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) {
- spyOn(getTaskDisplayAreaAt(i));
- }
-
+ forAllTaskDisplayAreas(taskDisplayArea -> {
+ spyOn(taskDisplayArea);
+ });
final DisplayRotation displayRotation = getDisplayRotation();
spyOn(displayRotation);
doAnswer(invocation -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 040717d2aa56..1266c50d368e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -60,24 +60,6 @@ public class WindowManagerServiceTests extends WindowTestsBase {
@Rule
public ExpectedException mExpectedException = ExpectedException.none();
- @Test
- public void testForceShowSystemBarsThrowsExceptionForNonAutomotive() {
- if (!isAutomotive()) {
- mExpectedException.expect(UnsupportedOperationException.class);
-
- mWm.setForceShowSystemBars(true);
- }
- }
-
- @Test
- public void testForceShowSystemBarsDoesNotThrowExceptionForAutomotiveWithStatusBarPermission() {
- if (isAutomotive()) {
- mExpectedException.none();
-
- mWm.setForceShowSystemBars(true);
- }
- }
-
private boolean isAutomotive() {
return getInstrumentation().getTargetContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_AUTOMOTIVE);
@@ -167,7 +149,6 @@ public class WindowManagerServiceTests extends WindowTestsBase {
TaskDisplayArea secondTda =
new TaskDisplayArea(display, mWm, "Tapped TDA", FEATURE_VENDOR_FIRST);
display.addChild(secondTda, 1);
- display.mTaskDisplayAreas.add(secondTda);
// Current focused window
ActivityStack focusedStack = createTaskStackOnDisplay(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, display);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 5f40b6d96b22..04d52afa3874 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -673,13 +673,12 @@ public class WindowOrganizerTests extends WindowTestsBase {
private List<Task> getTasksCreatedByOrganizer(DisplayContent dc) {
ArrayList<Task> out = new ArrayList<>();
- for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
- final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx);
+ dc.forAllTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final Task t = taskDisplayArea.getStackAt(sNdx);
if (t.mCreatedByOrganizer) out.add(t);
}
- }
+ });
return out;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index a1e5b80eb2ed..156298c86d41 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -41,11 +41,15 @@ import static org.mockito.Mockito.mock;
import android.content.Context;
import android.content.Intent;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.IDisplayWindowInsetsController;
import android.view.IWindow;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.WindowManager;
@@ -123,7 +127,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
mChildAppWindowBelow = createCommonWindow(mAppWindow,
TYPE_APPLICATION_MEDIA_OVERLAY,
"mChildAppWindowBelow");
- mDisplayContent.getDisplayPolicy().setForceShowSystemBars(false);
+ mDisplayContent.getInsetsPolicy().setRemoteInsetsControllerControlsSystemBars(false);
// Adding a display will cause freezing the display. Make sure to wait until it's
// unfrozen to not run into race conditions with the tests.
@@ -344,6 +348,32 @@ class WindowTestsBase extends SystemServiceTestsBase {
return createNewDisplay(displayInfo, false /* supportIme */);
}
+ IDisplayWindowInsetsController createDisplayWindowInsetsController() {
+ return new IDisplayWindowInsetsController.Stub() {
+
+ @Override
+ public void insetsChanged(InsetsState insetsState) throws RemoteException {
+ }
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] insetsSourceControls) throws RemoteException {
+ }
+
+ @Override
+ public void showInsets(int i, boolean b) throws RemoteException {
+ }
+
+ @Override
+ public void hideInsets(int i, boolean b) throws RemoteException {
+ }
+
+ @Override
+ public void topFocusedWindowChanged(String packageName) {
+ }
+ };
+ }
+
/** Sets the default minimum task size to 1 so that tests can use small task sizes */
void removeGlobalMinSizeRestriction() {
mWm.mAtmService.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index 23a097eb0c7c..5264e9aaba27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -20,16 +20,21 @@ import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import android.content.res.Configuration;
+import android.os.Bundle;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
@@ -38,6 +43,8 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.function.BiFunction;
+
/**
* Tests for the {@link WindowToken} class.
*
@@ -205,4 +212,27 @@ public class WindowTokenTests extends WindowTestsBase {
false /* fromClientToken */);
assertNotNull(nonClientToken.mSurfaceControl);
}
+
+ @Test
+ public void testWindowAttachedWithOptions() {
+ BiFunction<WindowToken, Bundle, RootDisplayArea> selectFunc =
+ ((DisplayAreaPolicyBuilder.Result) mDisplayContent.mDisplayAreaPolicy)
+ .mSelectRootForWindowFunc;
+ spyOn(selectFunc);
+
+ final WindowToken token1 = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
+
+ verify(selectFunc).apply(token1, null);
+
+ final Bundle options = new Bundle();
+ final WindowToken token2 = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class),
+ TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
+ true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
+ false /* fromClientToken */, options /* options */);
+
+ verify(selectFunc).apply(token2, options);
+ }
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 57345f1c0e21..6cf0eecc6352 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1367,6 +1367,9 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
try {
writeStringIfNotNull(dump, "kernel_state", UsbHandlerProto.KERNEL_STATE,
FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
+ } catch (FileNotFoundException exNotFound) {
+ Slog.w(TAG, "Ignore missing legacy kernel path in bugreport dump: "
+ + "kernel state:" + STATE_PATH);
} catch (Exception e) {
Slog.e(TAG, "Could not read kernel state", e);
}
@@ -1375,6 +1378,9 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
writeStringIfNotNull(dump, "kernel_function_list",
UsbHandlerProto.KERNEL_FUNCTION_LIST,
FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
+ } catch (FileNotFoundException exNotFound) {
+ Slog.w(TAG, "Ignore missing legacy kernel path in bugreport dump: "
+ + "kernel function list:" + FUNCTIONS_PATH);
} catch (Exception e) {
Slog.e(TAG, "Could not read kernel function list", e);
}
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index 2d0bd52f84ee..4e4abd0f63b0 100644
--- a/telephony/java/android/telephony/CellLocation.java
+++ b/telephony/java/android/telephony/CellLocation.java
@@ -16,7 +16,9 @@
package android.telephony;
+import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import android.telephony.cdma.CdmaCellLocation;
@@ -31,11 +33,25 @@ import com.android.internal.telephony.PhoneConstants;
public abstract class CellLocation {
/**
- * Request an update of the current location. If the location has changed,
- * a broadcast will be sent to everyone registered with {@link
- * PhoneStateListener#LISTEN_CELL_LOCATION}.
+ * This method will not do anything.
+ *
+ * Whenever location changes, a callback will automatically be be sent to
+ * all registrants of {@link PhoneStateListener#LISTEN_CELL_LOCATION}.
+ *
+ * <p>This method is a no-op for callers targeting SDK level 31 or greater.
+ * <p>This method is a no-op for callers that target SDK level 29 or 30 and lack
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
+ * <p>This method is a no-op for callers that target SDK level 28 or below and lack
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
+ *
+ * Callers wishing to request a single location update should use
+ * {@link TelephonyManager#requestCellInfoUpdate}.
*/
public static void requestLocationUpdate() {
+ // Since this object doesn't have a context, this is the best we can do.
+ final Context appContext = ActivityThread.currentApplication();
+ if (appContext == null) return; // should never happen
+
try {
ITelephony phone = ITelephony.Stub.asInterface(
TelephonyFrameworkInitializer
@@ -43,7 +59,7 @@ public abstract class CellLocation {
.getTelephonyServiceRegisterer()
.get());
if (phone != null) {
- phone.updateServiceLocation();
+ phone.updateServiceLocationWithPackageName(appContext.getOpPackageName());
}
} catch (RemoteException ex) {
// ignore it
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 347dcc81ce4e..717a9b155cbf 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -255,28 +255,6 @@ public class SmsMessage {
}
/**
- * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
- * +CMT unsolicited response (PDU mode, of course)
- * +CMT: [&lt;alpha>],<length><CR><LF><pdu>
- *
- * Only public for debugging and for RIL
- *
- * {@hide}
- */
- public static SmsMessage newFromCMT(byte[] pdu) {
- // received SMS in 3GPP format
- SmsMessageBase wrappedMessage =
- com.android.internal.telephony.gsm.SmsMessage.newFromCMT(pdu);
-
- if (wrappedMessage != null) {
- return new SmsMessage(wrappedMessage);
- } else {
- Rlog.e(LOG_TAG, "newFromCMT(): wrappedMessage is null");
- return null;
- }
- }
-
- /**
* Creates an SmsMessage from an SMS EF record.
*
* @param index Index of SMS EF record.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3104c20b0063..d96e024d4c60 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2341,58 +2341,6 @@ public class TelephonyManager {
}
/**
- * Enables location update notifications. {@link PhoneStateListener#onCellLocationChanged
- * PhoneStateListener.onCellLocationChanged} will be called on location updates.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES)
- public void enableLocationUpdates() {
- enableLocationUpdates(getSubId());
- }
-
- /**
- * Enables location update notifications for a subscription.
- * {@link PhoneStateListener#onCellLocationChanged
- * PhoneStateListener.onCellLocationChanged} will be called on location updates.
- *
- * @param subId for which the location updates are enabled
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES)
- public void enableLocationUpdates(int subId) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- telephony.enableLocationUpdatesForSubscriber(subId);
- } catch (RemoteException ex) {
- } catch (NullPointerException ex) {
- }
- }
-
- /**
- * Disables location update notifications. {@link PhoneStateListener#onCellLocationChanged
- * PhoneStateListener.onCellLocationChanged} will be called on location updates.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.CONTROL_LOCATION_UPDATES)
- public void disableLocationUpdates() {
- disableLocationUpdates(getSubId());
- }
-
- /** @hide */
- public void disableLocationUpdates(int subId) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- telephony.disableLocationUpdatesForSubscriber(subId);
- } catch (RemoteException ex) {
- } catch (NullPointerException ex) {
- }
- }
-
- /**
* Returns the neighboring cell information of the device.
*
* @return List of NeighboringCellInfo or null if info unavailable.
@@ -9290,17 +9238,14 @@ public class TelephonyManager {
return RADIO_POWER_UNAVAILABLE;
}
- /** @hide */
+ /**
+ * This method should not be used due to privacy and stability concerns.
+ *
+ * @hide
+ */
@SystemApi
- @SuppressLint("Doclava125")
public void updateServiceLocation() {
- try {
- ITelephony telephony = getITelephony();
- if (telephony != null)
- telephony.updateServiceLocation();
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#updateServiceLocation", e);
- }
+ Log.e(TAG, "Do not call TelephonyManager#updateServiceLocation()");
}
/** @hide */
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 4276e713561b..e2de5c82940f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -222,42 +222,29 @@ interface ITelephony {
boolean setRadioPower(boolean turnOn);
/**
- * Request to update location information in service state
+ * This method has been removed due to security and stability issues.
*/
@UnsupportedAppUsage
void updateServiceLocation();
/**
- * Request to update location information for a subscrition in service state
- * @param subId user preferred subId.
+ * Version of updateServiceLocation that records the caller and validates permissions.
*/
- void updateServiceLocationForSubscriber(int subId);
+ void updateServiceLocationWithPackageName(String callingPkg);
/**
- * Enable location update notifications.
+ * This method has been removed due to security and stability issues.
*/
@UnsupportedAppUsage
void enableLocationUpdates();
/**
- * Enable location update notifications.
- * @param subId user preferred subId.
- */
- void enableLocationUpdatesForSubscriber(int subId);
-
- /**
- * Disable location update notifications.
+ * This method has been removed due to security and stability issues.
*/
@UnsupportedAppUsage
void disableLocationUpdates();
/**
- * Disable location update notifications.
- * @param subId user preferred subId.
- */
- void disableLocationUpdatesForSubscriber(int subId);
-
- /**
* Allow mobile data connections.
*/
@UnsupportedAppUsage
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index d41a6c889afb..d216162cc257 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -171,8 +171,8 @@ public class TelephonyIntents {
* if not specified </dd>
* </dl>
*
- * <p class="note">
- * Requires the READ_PHONE_STATE permission.
+ * <p class="note">This is a sticky broadcast, and therefore requires no permissions to listen
+ * to. Do not add any additional information to this broadcast.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index ccb14749109d..e4205aaae5b6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -139,38 +139,6 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
- * +CMT unsolicited response (PDU mode, of course)
- * +CMT: [&lt;alpha>],<length><CR><LF><pdu>
- *
- * Only public for debugging
- *
- * {@hide}
- */
- public static SmsMessage newFromCMT(byte[] pdu) {
- try {
- SmsMessage msg = new SmsMessage();
- msg.parsePdu(pdu);
- return msg;
- } catch (RuntimeException ex) {
- Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
- return null;
- }
- }
-
- /** @hide */
- public static SmsMessage newFromCDS(byte[] pdu) {
- try {
- SmsMessage msg = new SmsMessage();
- msg.parsePdu(pdu);
- return msg;
- } catch (RuntimeException ex) {
- Rlog.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex);
- return null;
- }
- }
-
- /**
* Creates an SmsMessage from an SMS EF record.
*
* @param index Index of SMS EF record.
diff --git a/test-base/src/android/test/InstrumentationTestCase.java b/test-base/src/android/test/InstrumentationTestCase.java
index 6b79314a4385..9f7a2fa44dc2 100644
--- a/test-base/src/android/test/InstrumentationTestCase.java
+++ b/test-base/src/android/test/InstrumentationTestCase.java
@@ -34,9 +34,9 @@ import junit.framework.TestCase;
* A test case that has access to {@link Instrumentation}.
*
* @deprecated Use
- * <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html">
+ * <a href="{@docRoot}reference/androidx/test/platform/app/InstrumentationRegistry.html">
* InstrumentationRegistry</a> instead. New tests should be written using the
- * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+ * <a href="{@docRoot}training/testing/index.html">AndroidX Test Library</a>.
*/
@Deprecated
public class InstrumentationTestCase extends TestCase {
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 2be4ae6bb214..a23df920b396 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -29,7 +29,12 @@ java_test_host {
name: "StagedRollbackTest",
srcs: ["StagedRollbackTest/src/**/*.java"],
libs: ["tradefed"],
- static_libs: ["testng", "compatibility-tradefed", "RollbackTestLib"],
+ static_libs: [
+ "compatibility-tradefed",
+ "frameworks-base-hostutils",
+ "RollbackTestLib",
+ "testng",
+ ],
test_suites: ["general-tests"],
test_config: "StagedRollbackTest.xml",
data: [":com.android.apex.apkrollback.test_v1"],
@@ -39,7 +44,7 @@ java_test_host {
name: "NetworkStagedRollbackTest",
srcs: ["NetworkStagedRollbackTest/src/**/*.java"],
libs: ["tradefed"],
- static_libs: ["RollbackTestLib"],
+ static_libs: ["RollbackTestLib", "frameworks-base-hostutils"],
test_suites: ["general-tests"],
test_config: "NetworkStagedRollbackTest.xml",
}
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 55bbe22c4d86..c2fd0c39221e 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -453,6 +453,32 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
after.forEach(dir -> assertDirectoryIsEmpty(dir));
}
+ @Test
+ public void testExpireApexRollback() throws Exception {
+ List<String> before = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
+ pushTestApex();
+
+ // Push files to apex data directory
+ String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
+ String oldFilePath2 =
+ apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
+ assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
+ assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+
+ // Install new version of the APEX with rollback enabled
+ runPhase("testRollbackApexDataDirectories_Phase1");
+ getDevice().reboot();
+
+ List<String> after = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
+ // Only check directories newly created during the test
+ after.removeAll(before);
+ // Expire all rollbacks and check CE snapshot directories are deleted
+ runPhase("testCleanUp");
+ for (String dir : after) {
+ assertNull(getDevice().getFileEntry(dir));
+ }
+ }
+
private void pushTestApex() throws Exception {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex";
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index c3fdd695c2b7..65d15a7dccaa 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -24,7 +24,7 @@ java_test_host {
name: "StagedInstallInternalTest",
srcs: ["src/**/*.java"],
libs: ["tradefed"],
- static_libs: ["testng", "compatibility-tradefed"],
+ static_libs: ["testng", "compatibility-tradefed", "frameworks-base-hostutils"],
test_suites: ["general-tests"],
test_config: "StagedInstallInternalTest.xml",
}
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 9b432f7d0ca5..e6ba8015e5b5 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -19,14 +19,17 @@ package com.android.tests.stagedinstallinternal.host;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import com.android.ddmlib.Log;
+import com.android.tests.rollback.host.AbandonSessionsRule;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.util.ProcessInfo;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,7 +38,9 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
private static final String TAG = StagedInstallInternalTest.class.getSimpleName();
private static final long SYSTEM_SERVER_TIMEOUT_MS = 60 * 1000;
- private boolean mWasRoot = false;
+
+ @Rule
+ public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this);
/**
* Runs the given phase of a test by calling into the device.
@@ -62,21 +67,11 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
@Before
public void setUp() throws Exception {
- mWasRoot = getDevice().isAdbRoot();
- if (!mWasRoot) {
- getDevice().enableAdbRoot();
- }
cleanUp();
- // Abandon all staged sessions
- getDevice().executeShellCommand("pm install-abandon $(pm get-stagedsessions --only-ready "
- + "--only-parent --only-sessionid)");
}
@After
public void tearDown() throws Exception {
- if (!mWasRoot) {
- getDevice().disableAdbRoot();
- }
cleanUp();
}
@@ -89,23 +84,24 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
private void restartSystemServer() throws Exception {
// Restart the system server
- long oldStartTime = getDevice().getProcessByName("system_server").getStartTime();
+ ProcessInfo oldPs = getDevice().getProcessByName("system_server");
+
+ getDevice().enableAdbRoot(); // Need root to restart system server
assertThat(getDevice().executeShellCommand("am restart")).contains("Restart the system");
+ getDevice().disableAdbRoot();
// Wait for new system server process to start
long start = System.currentTimeMillis();
- long newStartTime = oldStartTime;
while (System.currentTimeMillis() < start + SYSTEM_SERVER_TIMEOUT_MS) {
ProcessInfo newPs = getDevice().getProcessByName("system_server");
if (newPs != null) {
- newStartTime = newPs.getStartTime();
- if (newStartTime != oldStartTime) {
- break;
+ if (newPs.getPid() != oldPs.getPid()) {
+ getDevice().waitForDeviceAvailable();
+ return;
}
}
Thread.sleep(500);
}
- assertThat(newStartTime).isNotEqualTo(oldStartTime);
- getDevice().waitForDeviceAvailable();
+ fail("Timed out in restarting system server");
}
}
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 9e3aeefd204c..5a29c2c96ba7 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -114,6 +114,7 @@ public class PermissionMonitorTest {
@Mock private INetd mNetdService;
@Mock private PackageManagerInternal mMockPmi;
@Mock private UserManager mUserManager;
+ @Mock private PermissionMonitor.Dependencies mDeps;
private PermissionMonitor mPermissionMonitor;
@@ -128,7 +129,7 @@ public class PermissionMonitorTest {
new UserInfo(MOCK_USER2, "", 0),
}));
- mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService));
+ mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mMockPmi);
@@ -283,14 +284,14 @@ public class PermissionMonitorTest {
@Test
public void testHasRestrictedNetworkPermissionSystemUid() {
- doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt();
+ doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
assertTrue(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
assertTrue(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt();
+ doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
assertFalse(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
diff --git a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/AbandonSessionsRule.java b/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java
index b08621314ee0..b08621314ee0 100644
--- a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/AbandonSessionsRule.java
+++ b/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index a230de46dcf3..4c741c49cfdb 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -25,6 +25,7 @@
namespace android {
namespace stats_log_api_gen {
+using google::protobuf::OneofDescriptor;
using google::protobuf::EnumDescriptor;
using google::protobuf::FieldDescriptor;
using google::protobuf::FileDescriptor;
@@ -396,16 +397,14 @@ int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>
collate_enums(*field->enum_type(), &atField);
}
- // Generate signature for pushed atoms
- if (atomDecl->code < PULL_ATOM_START_ID) {
- if (javaType == JAVA_TYPE_ENUM) {
- // All enums are treated as ints when it comes to function signatures.
- signature->push_back(JAVA_TYPE_INT);
- } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
- signature->push_back(JAVA_TYPE_BYTE_ARRAY);
- } else {
- signature->push_back(javaType);
- }
+ // Generate signature for atom.
+ if (javaType == JAVA_TYPE_ENUM) {
+ // All enums are treated as ints when it comes to function signatures.
+ signature->push_back(JAVA_TYPE_INT);
+ } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
+ signature->push_back(JAVA_TYPE_BYTE_ARRAY);
+ } else {
+ signature->push_back(javaType);
}
atomDecl->fields.push_back(atField);
@@ -518,8 +517,7 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
shared_ptr<AtomDecl> atomDecl =
make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name());
- if (atomDecl->code < PULL_ATOM_START_ID &&
- atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
+ if (atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
addAnnotationToAtomDecl(atomDecl.get(), ATOM_ID_FIELD_NUMBER,
ANNOTATION_ID_TRUNCATE_TIMESTAMP, ANNOTATION_TYPE_BOOL,
AnnotationValue(true));
@@ -537,7 +535,24 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
continue;
}
- FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = atoms->signatureInfoMap[signature];
+ const OneofDescriptor* oneofAtom = atomField->containing_oneof();
+ if (oneofAtom == nullptr) {
+ print_error(atomField, "Atom is not declared in a `oneof` field: %s\n",
+ atomField->name().c_str());
+ errorCount++;
+ continue;
+ }
+ else if ((oneofAtom->name() != ONEOF_PUSHED_ATOM_NAME) &&
+ (oneofAtom->name() != ONEOF_PULLED_ATOM_NAME)) {
+ print_error(atomField, "Atom is neither a pushed nor pulled atom: %s\n",
+ atomField->name().c_str());
+ errorCount++;
+ continue;
+ }
+
+ FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = oneofAtom->name() ==
+ ONEOF_PUSHED_ATOM_NAME ? atoms->signatureInfoMap[signature] :
+ atoms->pulledAtomsSignatureInfoMap[signature];
populateFieldNumberToAtomDeclSet(atomDecl, &fieldNumberToAtomDeclSet);
atoms->decls.insert(atomDecl);
@@ -556,6 +571,7 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
}
if (dbg) {
+ // Signatures for pushed atoms.
printf("signatures = [\n");
for (SignatureInfoMap::const_iterator it = atoms->signatureInfoMap.begin();
it != atoms->signatureInfoMap.end(); it++) {
@@ -566,6 +582,17 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
}
printf("\n");
}
+
+ // Signatures for pull atoms.
+ for (SignatureInfoMap::const_iterator it = atoms->pulledAtomsSignatureInfoMap.begin();
+ it != atoms->pulledAtomsSignatureInfoMap.end(); it++) {
+ printf(" ");
+ for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
+ jt++) {
+ printf(" %d", (int)*jt);
+ }
+ printf("\n");
+ }
printf("]\n");
}
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 10b34ecf5f54..e637ed945a08 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -29,6 +29,7 @@
namespace android {
namespace stats_log_api_gen {
+using google::protobuf::OneofDescriptor;
using google::protobuf::Descriptor;
using google::protobuf::FieldDescriptor;
using std::map;
@@ -41,6 +42,14 @@ const int PULL_ATOM_START_ID = 10000;
const int FIRST_UID_IN_CHAIN_ID = 0;
+/**
+ * The types of oneof atoms.
+ *
+ * `OneofDescriptor::name()` returns the name of the oneof.
+ */
+const string ONEOF_PUSHED_ATOM_NAME = "pushed";
+const string ONEOF_PULLED_ATOM_NAME = "pulled";
+
enum AnnotationId : uint8_t {
ANNOTATION_ID_IS_UID = 1,
ANNOTATION_ID_TRUNCATE_TIMESTAMP = 2,
@@ -184,6 +193,7 @@ using SignatureInfoMap = map<vector<java_type_t>, FieldNumberToAtomDeclSet>;
struct Atoms {
SignatureInfoMap signatureInfoMap;
+ SignatureInfoMap pulledAtomsSignatureInfoMap;
AtomDeclSet decls;
AtomDeclSet non_chained_decls;
SignatureInfoMap nonChainedSignatureInfoMap;
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index f4c937c3f599..ffbe9f800736 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -96,29 +96,160 @@ static void write_annotations(FILE* out, int argIndex,
}
}
+static void write_method_signature(FILE* out, const vector<java_type_t>& signature,
+ const AtomDecl& attributionDecl) {
+ int argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
+ chainField.name.c_str());
+ }
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", android.util.SparseArray<Object> valueMap");
+ } else {
+ fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
+ }
+ argIndex++;
+ }
+}
+
+static int write_method_body(FILE* out, const vector<java_type_t>& signature,
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
+ const AtomDecl& attributionDecl, const string& indent) {
+ // Start StatsEvent.Builder.
+ fprintf(out,
+ "%s final StatsEvent.Builder builder = "
+ "StatsEvent.newBuilder();\n",
+ indent.c_str());
+
+ // Write atom code.
+ fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str());
+ write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet);
+
+ // Write the args.
+ int argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+ arg++) {
+ switch (*arg) {
+ case JAVA_TYPE_BOOLEAN:
+ fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(),
+ argIndex);
+ break;
+ case JAVA_TYPE_INT:
+ case JAVA_TYPE_ENUM:
+ fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
+ break;
+ case JAVA_TYPE_FLOAT:
+ fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(),
+ argIndex);
+ break;
+ case JAVA_TYPE_LONG:
+ fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
+ break;
+ case JAVA_TYPE_STRING:
+ fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(),
+ argIndex);
+ break;
+ case JAVA_TYPE_BYTE_ARRAY:
+ fprintf(out,
+ "%s builder.writeByteArray(null == arg%d ? new byte[0] : "
+ "arg%d);\n",
+ indent.c_str(), argIndex, argIndex);
+ break;
+ case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+
+ fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str());
+ fprintf(out, "%s null == %s ? new int[0] : %s,\n",
+ indent.c_str(), uidName, uidName);
+ fprintf(out, "%s null == %s ? new String[0] : %s);\n",
+ indent.c_str(), tagName, tagName);
+ break;
+ }
+ case JAVA_TYPE_KEY_VALUE_PAIR:
+ fprintf(out, "\n");
+ fprintf(out, "%s // Write KeyValuePairs.\n", indent.c_str());
+ fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
+ fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
+ indent.c_str());
+ fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
+ fprintf(out, "%s final int key = valueMap.keyAt(i);\n",
+ indent.c_str());
+ fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
+ indent.c_str());
+ fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
+ fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s intMap = new "
+ "android.util.SparseIntArray();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s intMap.put(key, (Integer) value);\n",
+ indent.c_str());
+ fprintf(out, "%s } else if (value instanceof Long) {\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s longMap = new "
+ "android.util.SparseLongArray();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s longMap.put(key, (Long) value);\n",
+ indent.c_str());
+ fprintf(out, "%s } else if (value instanceof String) {\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s stringMap = new "
+ "android.util.SparseArray<>();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s stringMap.put(key, (String) value);\n",
+ indent.c_str());
+ fprintf(out, "%s } else if (value instanceof Float) {\n",
+ indent.c_str());
+ fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s floatMap = new "
+ "android.util.SparseArray<>();\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s floatMap.put(key, (Float) value);\n",
+ indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out, "%s }\n", indent.c_str());
+ fprintf(out,
+ "%s builder.writeKeyValuePairs("
+ "intMap, longMap, stringMap, floatMap);\n",
+ indent.c_str());
+ break;
+ default:
+ // Unsupported types: OBJECT, DOUBLE.
+ fprintf(stderr, "Encountered unsupported type.");
+ return 1;
+ }
+ write_annotations(out, argIndex, fieldNumberToAtomDeclSet);
+ argIndex++;
+ }
+ return 0;
+}
+
static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl, const bool supportQ) {
for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature.
fprintf(out, " public static void write(int code");
- const vector<java_type_t>& signature = signatureInfoMapIt->first;
- const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
- int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
- chainField.name.c_str());
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", android.util.SparseArray<Object> valueMap");
- } else {
- fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
- }
- argIndex++;
- }
+ write_method_signature(out, signatureInfoMapIt->first, attributionDecl);
fprintf(out, ") {\n");
// Print method body.
@@ -128,130 +259,13 @@ static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMa
indent = " ";
}
- // Start StatsEvent.Builder.
- fprintf(out,
- "%s final StatsEvent.Builder builder = "
- "StatsEvent.newBuilder();\n",
- indent.c_str());
-
- // Write atom code.
- fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str());
- write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet);
-
- // Write the args.
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- switch (*arg) {
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(),
- argIndex);
- break;
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_FLOAT:
- fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(),
- argIndex);
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(),
- argIndex);
- break;
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out,
- "%s builder.writeByteArray(null == arg%d ? new byte[0] : "
- "arg%d);\n",
- indent.c_str(), argIndex, argIndex);
- break;
- case JAVA_TYPE_ATTRIBUTION_CHAIN: {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
-
- fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str());
- fprintf(out, "%s null == %s ? new int[0] : %s,\n",
- indent.c_str(), uidName, uidName);
- fprintf(out, "%s null == %s ? new String[0] : %s);\n",
- indent.c_str(), tagName, tagName);
- break;
- }
- case JAVA_TYPE_KEY_VALUE_PAIR:
- fprintf(out, "\n");
- fprintf(out, "%s // Write KeyValuePairs.\n", indent.c_str());
- fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
- fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
- indent.c_str());
- fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
- fprintf(out, "%s final int key = valueMap.keyAt(i);\n",
- indent.c_str());
- fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
- indent.c_str());
- fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
- fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
- fprintf(out,
- "%s intMap = new "
- "android.util.SparseIntArray();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s intMap.put(key, (Integer) value);\n",
- indent.c_str());
- fprintf(out, "%s } else if (value instanceof Long) {\n",
- indent.c_str());
- fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
- fprintf(out,
- "%s longMap = new "
- "android.util.SparseLongArray();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s longMap.put(key, (Long) value);\n",
- indent.c_str());
- fprintf(out, "%s } else if (value instanceof String) {\n",
- indent.c_str());
- fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
- fprintf(out,
- "%s stringMap = new "
- "android.util.SparseArray<>();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s stringMap.put(key, (String) value);\n",
- indent.c_str());
- fprintf(out, "%s } else if (value instanceof Float) {\n",
- indent.c_str());
- fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
- fprintf(out,
- "%s floatMap = new "
- "android.util.SparseArray<>();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s floatMap.put(key, (Float) value);\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out,
- "%s builder.writeKeyValuePairs("
- "intMap, longMap, stringMap, floatMap);\n",
- indent.c_str());
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE.
- fprintf(stderr, "Encountered unsupported type.");
- return 1;
- }
- write_annotations(out, argIndex, fieldNumberToAtomDeclSet);
- argIndex++;
+ int ret = write_method_body(out, signatureInfoMapIt->first, signatureInfoMapIt->second,
+ attributionDecl, indent);
+ if (ret != 0) {
+ return ret;
}
-
fprintf(out, "\n");
+
fprintf(out, "%s builder.usePooledBuffer();\n", indent.c_str());
fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str());
@@ -259,9 +273,9 @@ static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMa
if (supportQ) {
fprintf(out, " } else {\n");
fprintf(out, " QLogger.write(code");
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ int argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signatureInfoMapIt->first.begin();
+ arg != signatureInfoMapIt->first.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
const char* uidName = attributionDecl.fields.front().name.c_str();
const char* tagName = attributionDecl.fields.back().name.c_str();
@@ -285,6 +299,32 @@ static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMa
return 0;
}
+static int write_java_build_stats_event_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
+ const AtomDecl& attributionDecl) {
+ for (auto signatureInfoMapIt = signatureInfoMap.begin();
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+ // Print method signature.
+ fprintf(out, " public static StatsEvent buildStatsEvent(int code");
+ write_method_signature(out, signatureInfoMapIt->first, attributionDecl);
+ fprintf(out, ") {\n");
+
+ // Print method body.
+ string indent("");
+ int ret = write_method_body(out, signatureInfoMapIt->first, signatureInfoMapIt->second,
+ attributionDecl, indent);
+ if (ret != 0) {
+ return ret;
+ }
+ fprintf(out, "\n");
+
+ fprintf(out, "%s return builder.build();\n", indent.c_str());
+
+ fprintf(out, " }\n"); // method
+ fprintf(out, "\n");
+ }
+ return 0;
+}
+
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& javaClass, const string& javaPackage, const bool supportQ,
const bool supportWorkSource) {
@@ -319,6 +359,8 @@ int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attribut
fprintf(out, " // Write methods\n");
errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
+ errors += write_java_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
+ attributionDecl);
if (supportWorkSource) {
errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
}
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index aaa488e44fee..e658b62b8daa 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -58,7 +58,7 @@ message AllTypesAtom {
}
message Event {
- oneof event {
+ oneof pushed {
OutOfOrderAtom out_of_order_atom = 2;
IntAtom int_atom = 1;
AnotherIntAtom another_int_atom = 3;
@@ -74,7 +74,7 @@ message BadTypesAtom {
}
message BadTypesEvent {
- oneof event {
+ oneof pushed {
BadTypesAtom bad_types_atom = 1;
}
}
@@ -84,7 +84,7 @@ message BadSkippedFieldSingleAtom {
}
message BadSkippedFieldSingle {
- oneof event {
+ oneof pushed {
BadSkippedFieldSingleAtom bad = 1;
}
}
@@ -96,7 +96,7 @@ message BadSkippedFieldMultipleAtom {
}
message BadSkippedFieldMultiple {
- oneof event {
+ oneof pushed {
BadSkippedFieldMultipleAtom bad = 1;
}
}
@@ -107,11 +107,11 @@ message BadAttributionNodePositionAtom {
}
message BadAttributionNodePosition {
- oneof event { BadAttributionNodePositionAtom bad = 1; }
+ oneof pushed { BadAttributionNodePositionAtom bad = 1; }
}
message GoodEventWithBinaryFieldAtom {
- oneof event { GoodBinaryFieldAtom field1 = 1; }
+ oneof pushed { GoodBinaryFieldAtom field1 = 1; }
}
message ComplexField {
@@ -124,7 +124,7 @@ message GoodBinaryFieldAtom {
}
message BadEventWithBinaryFieldAtom {
- oneof event { BadBinaryFieldAtom field1 = 1; }
+ oneof pushed { BadBinaryFieldAtom field1 = 1; }
}
message BadBinaryFieldAtom {
@@ -133,7 +133,7 @@ message BadBinaryFieldAtom {
}
message BadStateAtoms {
- oneof event {
+ oneof pushed {
BadStateAtom1 bad1 = 1;
BadStateAtom2 bad2 = 2;
BadStateAtom3 bad3 = 3;
@@ -141,7 +141,7 @@ message BadStateAtoms {
}
message GoodStateAtoms {
- oneof event {
+ oneof pushed {
GoodStateAtom1 good1 = 1;
GoodStateAtom2 good2 = 2;
}
@@ -204,7 +204,7 @@ message NoModuleAtom {
}
message ModuleAtoms {
- oneof event {
+ oneof pushed {
ModuleOneAtom module_one_atom = 1 [(android.os.statsd.module) = "module1"];
ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.module) = "module2"];
ModuleOneAndTwoAtom module_one_and_two_atom = 3 [
@@ -213,3 +213,24 @@ message ModuleAtoms {
NoModuleAtom no_module_atom = 4;
}
}
+
+message NotAPushNorPullAtom {
+ oneof event {
+ IntAtom int_atom = 1;
+ }
+}
+
+message AtomNotInAOneof {
+ optional IntAtom int_atom = 1;
+}
+
+message PushedAndPulledAtoms {
+ oneof pushed {
+ IntAtom int_atom_1 = 1;
+ }
+
+ oneof pulled {
+ OutOfOrderAtom out_of_order_atom = 11;
+ AnotherIntAtom another_int_atom = 10;
+ }
+}
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index dbae58889333..5fd728a29c07 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -365,5 +365,69 @@ TEST(CollationTest, RecognizeModule1Atom) {
EXPECT_TRUE(annotation->value.boolValue);
}
+/**
+ * Test that an atom is not a pushed nor pulled atom.
+ */
+TEST(CollationTest, InvalidAtomType) {
+ Atoms atoms;
+ int errorCount = collate_atoms(NotAPushNorPullAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+
+ EXPECT_EQ(1, errorCount);
+}
+
+/**
+ * Test that an atom was not declared in a `oneof` field.
+ */
+TEST(CollationTest, AtomNotDeclaredInAOneof) {
+ Atoms atoms;
+ int errorCount = collate_atoms(AtomNotInAOneof::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+
+ EXPECT_EQ(1, errorCount);
+}
+
+/**
+ * Test a correct collation with pushed and pulled atoms.
+ */
+TEST(CollationTest, CollatePushedAndPulledAtoms) {
+ Atoms atoms;
+ int errorCount = collate_atoms(PushedAndPulledAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+
+ EXPECT_EQ(0, errorCount);
+ EXPECT_EQ(1ul, atoms.signatureInfoMap.size());
+ EXPECT_EQ(2ul, atoms.pulledAtomsSignatureInfoMap.size());
+
+ // IntAtom
+ EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT);
+
+ // AnotherIntAtom
+ EXPECT_MAP_CONTAINS_SIGNATURE(atoms.pulledAtomsSignatureInfoMap, JAVA_TYPE_INT);
+
+ // OutOfOrderAtom
+ EXPECT_MAP_CONTAINS_SIGNATURE(atoms.pulledAtomsSignatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT);
+
+ EXPECT_EQ(3ul, atoms.decls.size());
+
+ AtomDeclSet::const_iterator atomIt = atoms.decls.begin();
+ EXPECT_EQ(1, (*atomIt)->code);
+ EXPECT_EQ("int_atom_1", (*atomIt)->name);
+ EXPECT_EQ("IntAtom", (*atomIt)->message);
+ EXPECT_NO_ENUM_FIELD((*atomIt));
+ atomIt++;
+
+ EXPECT_EQ(10, (*atomIt)->code);
+ EXPECT_EQ("another_int_atom", (*atomIt)->name);
+ EXPECT_EQ("AnotherIntAtom", (*atomIt)->message);
+ EXPECT_NO_ENUM_FIELD((*atomIt));
+ atomIt++;
+
+ EXPECT_EQ(11, (*atomIt)->code);
+ EXPECT_EQ("out_of_order_atom", (*atomIt)->name);
+ EXPECT_EQ("OutOfOrderAtom", (*atomIt)->message);
+ EXPECT_NO_ENUM_FIELD((*atomIt));
+ atomIt++;
+
+ EXPECT_EQ(atoms.decls.end(), atomIt);
+}
+
} // namespace stats_log_api_gen
} // namespace android